CodeCharter analysiert eure Solution einmal und stellt der DSL ein gecachtes Code-Modell zur Verfügung. Diese Seite listet was ihr darauf abfragen könnt, sortiert nach Entitäts-Typ.
Wenn ihr eine Regel formuliert wandert ihr von einer Root-Collection ausgehend durch das Modell. Property-Reads, Method-Aufrufe, LINQ-Ketten, am Ende sammelt ihr die Treffer ein.
Root-Collections
Jede Query startet bei einer dieser Sammlungen.
| Root | Element | Inhalt |
|---|---|---|
Types |
TypeModel |
Alle Klassen, Structs, Interfaces, Enums, Records |
Methods |
MethodModel |
Alle Methoden über alle Typen |
Properties |
PropertyModel |
Alle Properties |
Fields |
FieldModel |
Alle Felder |
Events |
EventModel |
Alle Events |
Namespaces |
NamespaceModel |
Alle Namespaces |
Assemblies |
AssemblyModel |
Eines pro Projekt |
TypeDependencies |
TypeDependency |
Gerichtete Type-zu-Type-Abhängigkeiten |
SyntaxIssues |
SyntaxIssue |
Vor-analysierte Syntax-Pattern (siehe unten) |
TypeModel
Identität:
Name string # ohne Namespace
FullName string # Namespace.Type
Namespace string
Kind string # "Class" | "Interface" | "Struct" | "Enum"
Modifiers:
IsAbstract bool
IsSealed bool
IsStatic bool
IsPartial bool
AccessModifier string # "Public" | "Internal" | "Private" | "Protected"
Strukturelle Metriken:
LinesOfCode int
NumberOfMethods int
NumberOfFields int
NumberOfDerivedTypes int
WeightedMethodsPerClass int
DepthOfInheritance int
LackOfCohesion double
ResponseForClass int
Abstractness double
Instability double
DistanceFromMainSequence double
MaintainabilityIndex double
CouplingEfferent int
CouplingAfferent int
Beziehungen:
BaseType TypeModel
Methods collection<MethodModel>
Constructors collection<MethodModel>
Properties collection<PropertyModel>
Fields collection<FieldModel>
NestedTypes collection<TypeModel>
DerivedTypes collection<TypeModel>
UsedTypes collection<TypeModel>
UsedByTypes collection<TypeModel>
ImplementedInterfaces collection<TypeModel>
Attributes collection<AttributeModel>
MethodModel
Name string
FullName string
ShortName string
AccessModifier string
IsAsync bool
IsStatic bool
IsOverride bool
IsInterfaceImplementation bool
IsConstructor bool
IsExtensionMethod bool
IsVirtual bool
ReturnType string
ReturnTypeShortName string
Parameters collection<ParameterModel>
LinesOfCode int
CognitiveComplexity int
CyclomaticComplexity int
NestingDepth int
NumberOfLocalVariables int
NumberOfParameters int
DeclaringType TypeModel
CalledMethods collection<MethodModel>
CalledByMethods collection<MethodModel>
Attributes collection<AttributeModel>
ParameterModel
Name string
Type TypeModel
TypeShortName string # z.B. "CancellationToken"
HasDefaultValue bool
PropertyModel und FieldModel
Name string
Type TypeModel
TypeShortName string
AccessModifier string
IsStatic bool
HasGetter bool # nur PropertyModel
HasSetter bool # nur PropertyModel
IsReadOnly bool # nur FieldModel
SyntaxIssue
SyntaxIssues ist eine globale Liste vor-analysierter Pattern. Jeder
Issue hat ein Kind und ist einem MethodModel zugeordnet. Bekannte
Kinds:
"DateTimeDirectUsage"
"EmptyCatch"
"ExplicitTypeInsteadOfVar"
"FireAndForgetAsync"
"GenericExceptionCatch"
"MagicNumber"
"MissingGuardClause"
"MissingInheritDoc"
"MissingParamDoc"
"MissingXmlDoc"
"NewInConstructor"
"NullEqualityCheck"
"StringConcatenation"
"TodoComment"
"UnusedParameter"
"UnusedUsing"
Beispiel-Nutzung:
from m in Methods
where m.SyntaxIssues.Any(i => i.Kind == "EmptyCatch")
select m
String-Helfer
Wenn ihr ein string-Property lest, könnt ihr verkettern:
.StartsWith("...")
.EndsWith("...")
.Contains("...")
.Matches("regex")
Vergleiche sind case-sensitive sofern der Helper nichts anderes sagt.
Collection-Helfer
Alle Root-Collections und Sub-Collections (Methods, Parameters,
Properties, ...) unterstützen die übliche LINQ-Oberfläche:
.Where(x => ...)
.Any(x => ...)
.All(x => ...)
.Count # Property, nicht Methode
.First()
.Sum(x => ...)
.Min(x => ...)
.Max(x => ...)
.OrderBy(x => ...)
.OrderByDescending(x => ...)
Häufige Fallen
.Countstatt.Count(): Sub-Collections nutzenCountals Property.Kind == "Class"ist case-sensitive: Großbuchstabe ist Pflicht.AccessModifier == "Public": wir folgen der C#-Pascal-Konvention.Parametersenthält keinenthis-Receiver bei Instanz-Methoden.
Was fehlt
Wenn euer Use-Case ein Property braucht das hier nicht steht, schreibt eine Issue. Die DSL wächst auf Nachfrage, nicht ins Blaue.
Wo geht's weiter
- DSL-Grammatik: wie die Sprache strukturell aufgebaut ist
- Regel-Beispiele: praktische Anwendungen der Prädikate
- Syntax-Übersicht: kompaktere Variante dieses Katalogs