CodeGuard

Selectoren

Wie der erste Teil jeder Regel-Query festlegt was geprüft wird.

Selectoren

Der "Selector" ist der erste Teil einer Regel, die from-Klausel oder der initiale Collection-Zugriff. Er bestimmt auf welcher Sorte Code-Element die Regel arbeitet.

Top-Level-Collections

Diese kannst du direkt als Startpunkt nutzen:

Collection Element-Typ Beschreibung
Types TypeModel Alle Klassen, Structs, Interfaces, Enums
Methods MethodModel Alle Methoden inkl. Konstruktoren-Variante
Properties PropertyModel Alle Properties
Fields FieldModel Alle Felder
Events EventModel Alle Events
Namespaces NamespaceModel Alle Namespaces
Assemblies AssemblyModel Alle analysierten Assemblies
TypeDependencies TypeDependency Coupling-Beziehungen zwischen Typen
SyntaxIssues SyntaxIssue Vor-analysierte Pattern-Befunde

Zwei Schreibweisen

Die DSL unterstützt sowohl from x in Y (Query-Syntax) als auch Y.Where(x => ...) (Method-Syntax). Beide produzieren das gleiche Ergebnis.

Query-Syntax:

from t in Types
where t.Kind == "Class"
where t.IsAbstract
select t

Method-Syntax:

Types.Where(t => t.Kind == "Class" && t.IsAbstract)

Wann welche? Bei mehreren where-Klauseln ist Query-Syntax lesbarer. Bei einer Bedingung oder einer Aggregation (.Count > 10) ist Method-Syntax kürzer.

Per-Element-Properties

Die Element-Typen haben jeweils Properties die du in where-Klauseln und Sub-Queries nutzen kannst.

TypeModel (Auszug)

t.Name                 // einfacher Name
t.FullName             // mit Namespace
t.Namespace            // nur der Namespace
t.Kind                 // "Class", "Interface", "Struct", "Enum"
t.IsAbstract           // bool
t.IsSealed             // bool
t.IsStatic             // bool
t.LinesOfCode          // int
t.NumberOfMethods      // int
t.Methods              // collection of MethodModel
t.Constructors         // collection of MethodModel
t.NestedTypes          // collection of TypeModel
t.DerivedTypes         // collection of TypeModel
t.UsedTypes            // welche Typen referenziert dieser Typ
t.UsedByTypes          // welche Typen referenzieren diesen
t.BaseType.FullName    // Vater-Klasse

MethodModel (Auszug)

m.Name                 // Methodenname
m.AccessModifier       // "Public", "Private", "Protected", "Internal"
m.IsAsync              // bool
m.IsStatic             // bool
m.IsOverride           // bool
m.IsInterfaceImplementation // bool
m.Parameters           // collection of ParameterModel
m.CalledMethods        // welche Methoden ruft diese auf
m.CalledByMethods      // welche Methoden rufen diese
m.LinesOfCode          // int
m.DeclaringType        // TypeModel

Die vollständige Schema-Liste ist in der CLI über codeguard list-rules --schema abrufbar (geplant, kommt mit der nächsten Minor-Version).

Composition mit Any / All / Count

Sub-Queries auf Collection-Properties:

# Klassen mit mindestens einer async Methode ohne CancellationToken
from t in Types
where t.Methods.Any(m =>
    m.IsAsync &&
    !m.Parameters.Any(p => p.TypeShortName == "CancellationToken"))
select t
# Klassen mit mehr als 10 public Methoden
from t in Types
where t.Methods.Where(m => m.AccessModifier == "Public").Count > 10
select t

SyntaxIssues als Selector

Manche Pattern erkennt der Analyzer syntaktisch (nicht semantisch über das Typmodell) und stellt sie als SyntaxIssue zur Verfügung. Eine Regel kann gezielt auf eine Kategorie filtern:

@name "Direct DateTime usage"
@severity warn
@category "Testability"

SyntaxIssues.Where(s => s.Kind == "DateTimeDirectUsage")

Die Kind-Werte sind festgelegt. Liste in der Schema-Doku (siehe Syntax-Übersicht).

Was als nächstes