CodeCharter analyses your solution once and hands the DSL a cached code model. This page lists what you can query, sorted by entity type.
When you write a rule you navigate the model starting from a root collection. Property reads, method calls, LINQ chains, and at the end you collect the matches.
Root collections
Every query starts at one of these.
| Root | Element | Contents |
|---|---|---|
Types |
TypeModel |
All classes, structs, interfaces, enums, records |
Methods |
MethodModel |
All methods across all types (constructors are not included; they live in TypeModel.Constructors) |
Properties |
PropertyModel |
All properties |
Fields |
FieldModel |
All fields |
Events |
EventModel |
All events |
Namespaces |
NamespaceModel |
All namespaces |
Assemblies |
AssemblyModel |
One per project |
TypeDependencies |
TypeDependency |
Directed type-to-type dependencies |
Files |
FileModel |
One per source file: using directives and comment trivia |
TypeModel
Identity:
Name string # without namespace
FullName string # Namespace.Type
Namespace NamespaceModel # object, not a string: use t.Namespace.FullName
Kind string # "Class" | "Interface" | "Struct" | "Enum" | "Record" | "Delegate"
SourceFile string
LineNumber int
Modifiers:
IsAbstract bool
IsSealed bool
IsStatic bool
IsPartial bool
IsGeneric bool
IsRecord bool
AccessModifier string # "Public" | "Internal" | "Private" | "Protected" | "ProtectedInternal" | "PrivateProtected"
Structural metrics:
LinesOfCode int
NumberOfMethods int
NumberOfFields int
NumberOfProperties int
NumberOfDerivedTypes int
WeightedMethodsPerClass int
DepthOfInheritance int
LackOfCohesion double
ResponseForClass int
Instability double
MaintainabilityIndex double
CouplingEfferent int
CouplingAfferent int
Abstractness and DistanceFromMainSequence are namespace-level
metrics; you find them on NamespaceModel, not here.
Relationships:
BaseType TypeModel # only set when the base type is declared in the analysed code; null for framework base types
DeclaredBaseTypeName string # fully qualified name of the DIRECT base type, e.g. "System.Exception" (set even for framework types); null when there is no explicit base
BaseTypeNames collection<string> # fully qualified names of the WHOLE inheritance chain (direct + transitive) up to System.Object; crosses the framework boundary, so use it for transitive base checks
Methods collection<MethodModel>
Constructors collection<MethodModel>
Properties collection<PropertyModel>
Fields collection<FieldModel>
Events collection<EventModel>
NestedTypes collection<TypeModel>
DerivedTypes collection<TypeModel>
UsedTypes collection<TypeModel>
UsedByTypes collection<TypeModel>
ImplementedInterfaces collection<TypeModel>
Attributes collection<AttributeModel>
MethodModel
Name string
FullName string
AccessModifier string
IsAsync bool
IsStatic bool
IsAbstract bool
IsSealed bool
IsOverride bool
IsInterfaceImplementation bool
IsConstructor bool
IsExtensionMethod bool
IsVirtual bool
ReturnType string
ReturnTypeShortName string
IsReturnTypeClass bool
IsReturnTypeInterface bool
IsReturnTypeRecord bool
ResolvedReturnType TypeInfo
Parameters collection<ParameterModel>
LinesOfCode int
CognitiveComplexity int
CyclomaticComplexity int
NestingDepth int
NumberOfLocalVariables int
NumberOfParameters int
NumberOfOverloads int
Overloads collection<MethodModel>
DeclaringType TypeModel
CalledMethods collection<MethodModel>
CalledByMethods collection<MethodModel>
Attributes collection<AttributeModel>
SourceFile string
LineNumber int
Syntax node # the method body, for statement-level rules — see below
Syntax (statement-level navigation)
The properties above describe a method from the outside. m.Syntax lets you
query the statements inside the body — loops, try/catch, throw, calls,
and so on. You start at m.Syntax and walk down to the construct you want.
m.Syntax is a node. Reading a member gives you another node, a node set
(a collection of nodes), or a token (a leaf such as an identifier).
Members of a node
Every node — m.Syntax included — exposes exactly these:
Kind string # the construct name, e.g. "CatchClause" (see "Construct kinds")
Text string # the verbatim source text of this construct
Line int # 1-based start line
Column int # 1-based start column
Descendants node set # every construct below this node, at any depth
Children node set # the direct child constructs only (one level down)
ResolvedType TypeInfo # the semantically resolved type of this node, or null
ResolvedSymbol string # the fully qualified name of the symbol it binds to, or null
<slot> node | node set | token # a named part, see "Child slots per construct"
A token (for example the Identifier of a catch declaration) exposes Kind,
Text, Line, and Column only. It is a leaf: it has no Descendants,
Children, or child slots.
Members of a node set
A node set is a collection. It exposes Count and the same closed
collection helpers (.Any, .Where, .Count, .Select,
…) as every other collection, plus:
Count int # number of nodes in the set
Descendants node set # all descendants of every node in the set
Children node set # direct children of every node in the set
<Kind> node set # the nodes of that kind, e.g. .Descendants.CatchClause
.<Kind> filters by construct name (see below). A name that is not a known
construct is reported as an error, not a silent empty result.
Construct kinds
The exact names you use as a kind filter (.Descendants.<Kind>) or compare with
Kind. They are the names of the C# language constructs.
Statements Block ExpressionStatement LocalDeclarationStatement
IfStatement ElseClause SwitchStatement SwitchSection
ForStatement ForEachStatement WhileStatement DoStatement
TryStatement ThrowStatement ReturnStatement YieldStatement
UsingStatement LockStatement
BreakStatement ContinueStatement GotoStatement
Clauses CatchClause CatchDeclaration CatchFilterClause FinallyClause
Expressions InvocationExpression MemberAccessExpression ObjectCreationExpression
BinaryExpression AssignmentExpression ConditionalExpression
CastExpression AwaitExpression IdentifierName
LiteralExpression NumericLiteralExpression StringLiteralExpression
ArgumentList Argument
Declarations VariableDeclaration VariableDeclarator EqualsValueClause
These follow C#'s own grammar; any other construct in the language is reachable by its grammar name, no matter how deeply nested. The grammar is large — the kinds above are the ones rules normally need.
Child slots per construct
A construct's named parts. Each yields a node, a node set, or a token. A slot
that is absent in the source (an if with no else, a bare throw;, a
catch {} with no declaration) yields empty and is safe to read.
TryStatement Block (node) Catches (node set) Finally (node)
CatchClause Declaration (node) Filter (node) Block (node)
CatchDeclaration Type (node) Identifier (token)
CatchFilterClause FilterExpression (node)
FinallyClause Block (node)
IfStatement Condition (node) Statement (node) Else (node)
ElseClause Statement (node)
ForStatement Declaration (node) Condition (node) Incrementors (node set) Statement (node)
ForEachStatement Type (node) Identifier (token) Expression (node) Statement (node)
WhileStatement Condition (node) Statement (node)
DoStatement Statement (node) Condition (node)
SwitchStatement Expression (node) Sections (node set)
SwitchSection Labels (node set) Statements (node set)
ThrowStatement Expression (node)
ReturnStatement Expression (node)
Block Statements (node set)
ExpressionStatement Expression (node)
LocalDeclarationStatement Declaration (node)
UsingStatement Declaration (node) Expression (node) Statement (node)
LockStatement Expression (node) Statement (node)
InvocationExpression Expression (node) ArgumentList (node)
ArgumentList Arguments (node set)
Argument Expression (node)
MemberAccessExpression Expression (node) Name (node)
ObjectCreationExpression Type (node) ArgumentList (node) Initializer (node)
BinaryExpression Left (node) Right (node)
AssignmentExpression Left (node) Right (node)
ConditionalExpression Condition (node) WhenTrue (node) WhenFalse (node)
CastExpression Type (node) Expression (node)
AwaitExpression Expression (node)
IdentifierName Identifier (token)
LiteralExpression Token (token)
VariableDeclaration Type (node) Variables (node set)
VariableDeclarator Identifier (token) Initializer (node)
EqualsValueClause Value (node)
Example
Flag throw ex;, which discards the original error location:
@name "Rethrow loses the original location"
@severity error
@category "ErrorHandling"
@recommendation "Use a bare throw; to keep the original stack trace"
Methods.Where(m =>
m.Syntax.Descendants.CatchClause.Any(c =>
c.Block.Descendants.ThrowStatement.Any(t =>
t.Expression.Text == c.Declaration.Identifier.Text)))
The finding points at the exact throw statement, even when it sits deep inside
if branches or loops, not at the whole method.
Resolving types and symbols
By default m.Syntax matches the written form of the code. When you need to
match the real type behind an expression — regardless of aliased usings or partial
names — read ResolvedType (a TypeInfo) or ResolvedSymbol (the symbol's fully
qualified name). Both are null when resolution is unavailable, so guard accordingly.
# Flag MD5/SHA1 by their real type, however the code spells them:
Methods.Where(m =>
m.Syntax.Descendants.ObjectCreationExpression.Any(n =>
n.ResolvedType.FullName == "System.Security.Cryptography.MD5"))
Limits
m.Syntax does not follow a value across statements — var e2 = ex; throw e2;
reads as a different variable — and it is scoped to a single method body. For checks
that span several methods, use the structural properties above. Syntax is empty for
members without a body (abstract or interface methods); navigating it then yields no
matches.
ParameterModel
Name string
Type string # fully qualified type name
TypeShortName string # e.g. "CancellationToken"
HasDefaultValue bool
IsParams bool
IsOut bool
IsRef bool
IsTypeInterface bool
IsTypeClass bool
IsTypeRecord bool
IsTypeEnum bool
IsTypeStruct bool
IsTypePrimitive bool
IsTypeAbstract bool
ResolvedType TypeInfo
TypeBaseTypeNames collection<string> # base type names of the parameter type
PropertyModel
Name string
Type string # type name
AccessModifier string
IsStatic bool
IsAutoProperty bool
IsAbstract bool
IsVirtual bool
IsOverride bool
HasGetter bool
HasSetter bool
DeclaringType TypeModel
Attributes collection<AttributeModel>
ResolvedType TypeInfo
SourceFile string
LineNumber int
FieldModel
Name string
Type string # type name
AccessModifier string
IsStatic bool
IsReadonly bool # note the lowercase "o": property names are case-sensitive
IsConst bool
DeclaringType TypeModel
Attributes collection<AttributeModel>
ResolvedType TypeInfo
SourceFile string
LineNumber int
EventModel
Name string
DelegateType string # delegate type of the event
DeclaringType TypeModel
SourceFile string
LineNumber int
NamespaceModel
Name string # last segment
FullName string
Assembly AssemblyModel
Types collection<TypeModel> # directly contained types
NumberOfTypes int
Abstractness double
Instability double
DistanceFromMainSequence double
AssemblyModel
Name string
Version string
TargetFramework string
Namespaces collection<NamespaceModel>
TypeDependency
Source TypeModel
Target TypeModel
Kind string # "Inherits" | "Implements" | "Uses"
AttributeModel
Name string # without "Attribute" suffix, e.g. "Obsolete"
FullName string # e.g. "System.ObsoleteAttribute"
Only Name and FullName are exposed; constructor arguments and named
arguments of an attribute (e.g. the message of [Obsolete("...")]) are
not accessible.
TypeInfo
Returned by ResolvedType / ResolvedReturnType. Unlike TypeModel
it also works for types outside your solution:
FullName string
ShortName string
IsClass bool # classes excluding records
IsRecord bool
IsInterface bool
IsEnum bool
IsStruct bool
IsPrimitive bool
IsAbstract bool
String helpers
When you read a string property you can chain:
.StartsWith("...")
.EndsWith("...")
.Contains("...")
.Matches("regex")
.ToLower()
.ToUpper()
.Length # property, not a method
Comparisons are case-sensitive unless the helper documents otherwise.
This list is closed: only the methods above exist. Other string
methods you may know from C#, such as Trim or Replace, are not
supported and fail at evaluation time.
Collection helpers
All root collections and sub-collections (Methods, Parameters,
Properties, ...) support exactly these methods:
.Where(x => ...)
.Select(x => ...)
.SelectMany(x => ...)
.Any(x => ...)
.All(x => ...)
.Count # property, not a method
.Contains(value)
.First(x => ...)
.Sum(x => ...)
.Min(x => ...)
.Max(x => ...)
.Average(x => ...)
.OrderBy(x => ...)
.OrderByDescending(x => ...)
.Take(n)
.Distinct()
This list is closed as well: any method not listed here, including
common LINQ operators such as GroupBy, Skip, or FirstOrDefault,
does not exist in the DSL and fails at evaluation time. What happens
then depends on the query form: the LINQ form skips just the failing
item, the fluent form aborts the whole rule without findings. See
DSL grammar for details.
Common pitfalls
.Countinstead of.Count(): sub-collections useCountas a property.- Zero-argument calls like
.Any(),.First(),.Count()only work as steps of the top-level fluent chain: inside nested expressions they are read as member access and fail. Use.Countas a property and pass a lambda toAny/First. Kind == "Class"is case-sensitive: the capital letter is required.AccessModifier == "Public": we follow the C# Pascal-case convention.Parametersdoes not contain thethisreceiver for instance methods.
What is missing
If your use case needs a property that is not listed here, please file an issue. The DSL grows on demand, not on speculation.
Where to go next
- DSL grammar: how the language is structurally put together.
- Rule examples: practical applications of the predicates.
- Syntax overview: more compact variant of this catalog.