Code
Query Language 1.8 Specification
CQL
1.8
CQL
1.8 is supported by NDepend 2.9 and higher, including NDepend 3.x versions
Copyright
SMACCHIA.COM S.A.R.L 2006/2007/2008/2009
All
right reserved
The CQL language and real-world
needs
Storing CQL queries and constraints
in your C# or VB.NET source code
Some examples of queries and
constraints written in CQL
Examples of code Quality constraints
Examples of naming constraints
Examples of design constraints
Examples of encapsulation
constraints
Examples of queries on the graph of
dependencies
Examples of queries on the
inheritance tree
Examples of queries to get extremum
WARN IF xxx IN: Query vs. Constraint
TOP xxx: Restrict the number of rows
in the result
FROM / OUT OF xxx: Domain of search
WHERE xxx: Define a set of
conditions
ORDER BY xxx: Order rows of the
result
Kind of Code Elements’ Names
Prefixes
The OPTIONAL: Code Elements’ Names
Prefix
ABT
T (Association Between Types)
LCOM
T (Lack Of Cohesion Of Methods)
LCOMHS T (Lack Of Cohesion Of Methods
Henderson-Sellers)
CQL test coverage metrics conditions
ContainsNamespaceDependencyCycle A
ContainsMethodDependencyCycle M
CQL boolean conditions dedicated to
Build Comparison
CQL boolean conditions dedicated to
Optimal Encapsulation
CQL boolean conditions dedicated to
Purity / Side-Effects / Mutability
CQL is a
language which allows writing queries on the code structure of any.NET
application, independently of the .NET language used (C#, VB.NET, C++/CLI …).
For example, the following CQL query returns all the methods of your
application with more than 200 IL instructions, ordered from the biggest to the
smallest:
SELECT METHODS WHERE NbILInstructions > 200 ORDER BY NbILInstructions DESC
You might
wish to avoid methods with more than 200 IL instructions since they are hard to
maintain. After having shrunk all your methods, you certainly want to be
notified when during development a method exceeds this threshold. The CQL
language addresses this need by allowing the transformation of queries into
constraints. For example, here is our previous query rewritten as a constraint:
WARN IF Count >
With almost
a hundred keywords, the CQL language allows you to deal with various conditions
on your code structure. It allows to write code quality constraints, naming constraints, design constraints, encapsulation constraints, queries on the graph of
dependencies, queries on the
inheritance tree, queries to get the biggest or
smallest code elements according to almost 30 metrics and much more.
The tool VisualNDepend
allows the editing and execution of CQL queries and constraints. A GUI allows
you to have a unique understanding of your application. VisualNDepend
can also be used to generate reports during each build of your application.

Writing CQL
queries and constraints is straightforward thanks to the three following
features:


The CQL
language has been conceived to understand and control real-world application. In
a real-world environment, there are often exceptions (like automatically
generated methods which are often very big) and you need to allow a few
particular methods to exceed this threshold without being bothered by our
previous constraint. The CQL language offers numerous features allowing you to
deal with such exceptions. For example, all generated methods might contain the
word “Generated” in their names:
WARN IF Count >
Or maybe,
all generated methods are in dedicated assemblies, namespaces or types:
WARN IF Count >
Or maybe,
you prefer to mention each one explicitly:
WARN IF Count >
You can also
mix all these features in the same constraint:
WARN IF Count >
NDepend
stores your CQL queries and constraints in the project file. As the source code is the design you might prefer storing your CQL queries and
constraints directly in your source code (C#, VB.NET...). To do so, you must
reference the assembly ./Lib/NDepend.CQL.dll and use the attribute NDepend.CQL.CQLConstraintAttribute
in your code.
WARN IF Count >
// METHODS WHERE NbILInstructions > 200 are extremely complex and
// should be split in smaller methods
// (except if they are
automatically generated by a tool).
WARN IF Count >
// METHODS WHERE ILCyclomaticComplexity > 20 are hard to understand
and maintain.
// METHODS WHERE ILCyclomaticComplexity > 40 are extremely complex
and should be split
// in smaller methods (except if
they are automatically generated by a tool).
WARN IF Count >
// METHODS WHERE NbParameters > 5 might be painful to call and might
degrade performance.
// You should prefer using additional properties/fields to the declaring
type to handle
// numerous states. Another alternative is to provide a class or
structure dedicated to
// handle arguments passing (for example see the class
System.Diagnostics.ProcessStartInfo
// and the method
System.Diagnostics.Process.Start(ProcessStartInfo))
WARN IF Count >
// METHODS WHERE NbVariables > 8 are hard to understand and maintain.
// METHODS WHERE NbVariables > 15 are extremely complex and should be
split in
// smaller methods (except if they
are automatically generated by a tool).
WARN IF Count >
// TYPES WHERE NbMethods > 20 might be hard to understand and
maintain
// but there might be cases where it is relevant to have a high value
for NbMethods.
// For example, the
System.Windows.Forms.DataGridView standard class has more than 1000 methods.
WARN IF Count >
// TYPES WHERE NbFields > 20 AND !IsEnumeration might be hard to
understand and maintain
// but there might be cases where it is relevant to have a high value
for NbFields.
// For example, the System.Windows.Forms.Control standard class has more
than 200 fields.
// The value of the metric
SizeOfInst might be a better indicator of complex type.
WARN IF Count >
// TYPES WHERE SizeOfInst > 64 might degrade performance (depending
on the number of
// instances created at runtime) and might be hard to maintain.
// However it is not a rule since sometime there is no alternative
// (the size of instances of the
System.Net.NetworkInformation.SystemIcmpV6Statistics
// standard class is 2064 bytes).
WARN IF Count >
// TYPES WHERE LCOM > 0.8 AND NbFields > 10 AND NbMethods >10
might be problematic.
// However, it is very hard to avoid such non-cohesive types. The LCOMHS
metric
// is often considered as more
efficient to detect non-cohesive types.
WARN IF Count >
// TYPES WHERE LCOMHS > 1.0 AND NbFields > 10 AND NbMethods >10
should be avoided.
// Note that this constraint is stronger than the constraint
// TYPES WHERE LCOM > 0.8 AND
NbFields > 10 AND NbMethods >10.
SELECT TYPES WHERE DepthOfInheritance > 6 ORDER BY DepthOfInheritance DESC
// TYPES WHERE DepthOfInheritance > 6 might be hard to maintain.
However it is not
// a rule since sometime your classes might inherit from tier classes
which have a
// high value for depth of inheritance. For example, the average depth
of inheritance
// for framework classes which
derive from System.Windows.Forms.Control is 5.3.
WARN IF Count >
// Type with big instances can be problematic
// (Obviously the SizeOfInst metric does not do a deep traverse.
// Any instance reference field
will count for 4 bytes.
//
It is also unable to cop with generic types properly)
WARN IF Percentage >
// With generics, boxing and
unboxing should be very rare.
WARN IF Percentage >
WARN IF Count >
// As classes inside an assembly should be strongly related,
// the cohesion should be high. On the other hand, a value which is too
high may
// indicate over-coupling. A good
range for RelationalCohesion is 1.5 to 4.0.
WARN IF Count >
// A static field should not be
named 'm_XXX'
WARN IF Count >
// A non-static field should not
be named 's_XXX'
WARN IF Count >
// The name of an interface should
begin with a 'I'
WARN IF Count >
// The name of an exception class
should end with 'Exception'
WARN IF Count >
// The name of an attribute class
should end with 'Attribute'
WARN IF Count >
!NameLike "^[A-Z]" AND // The name of a
type should begin with an Upper letter.
!NameLike "__StaticArrayInit" AND // Except __StaticArrayInit generated type
!NameLike "<" // Except C# compiler generated
type
WARN IF Count >
!NameLike "^[A-Z]" AND
!(IsClassConstructor OR IsConstructor OR
IsPropertyGetter OR IsPropertySetter OR
IsIndexerGetter OR IsIndexerSetter OR
IsEventAdder OR IsEventRemover OR
IsOperator)
// The name of a regular method
should begin with an Upper letter.
WARN IF Count >
// It indicate stateless types that
might eventually be turned into static classes.
WARN IF Count >
// A field should not be public or
internal, except for performance reasons.
WARN IF Count >
// A nested type should not be
public or internal.
WARN IF Count >
// Restrict the possibility of
using the type "System.Xml.XmlChildNodes" only to certain namespace.
WARN IF Count >
DepthOfIsUsing "System.Xml.XmlNamedNodeMap.InsertNodeAt(Int32,XmlNode)"== 1
// Restrict the possibility of calling the method
"System.Xml.XmlNamedNodeMap.InsertNodeAt(Int32,XmlNode)"
// only to certain namespace.
WARN IF Count >
"System.Xml.XmlDocumentFragment",
"System.Xml.XmlEntityReference",
"System.Xml.XmlDocumentType",
"System.Xml.XmlEntity",
"System.Xml.XmlDocument",
"System.Xml.XmlAttribute",
"System.Xml.XmlElement" WHERE DepthOfCreateA "System.Xml.XmlLoader" ==1 ORDER BY DepthOfCreateA
// Restrict the possibility of
creating an instance of "System.Xml.XmlLoader" only to certain type.
WARN IF Count >
WHERE DepthOfCreateA "System.Xml.XmlLoader" == 1 ORDER BY DepthOfCreateA
// Restrict the possibility of
creating an instance of "System.Xml.XmlLoader" only to certain
namespaces.
WARN IF Count >
WHERE DepthOfIsUsing "System.Windows.Forms.Internal" == 1
// Restrict the possibility of
using a namespace only to one assembly.
WARN IF Count >
DepthOfIsUsing "System.Windows.Forms.DataGridView+HitTestInfo.typeInternal" == 1
// Restrict the possibility of using the field
//
"System.Windows.Forms.DataGridView+HitTestInfo.typeInternal"
// only to certain namespace.
SELECT METHODS WHERE IsUsing "System.Xml.XmlWriter..ctor()" ORDER BY DepthOfIsUsing
// 'IsUsing/IsUsedBy/DepthOfIsUsing/DepthOfIsUsedBy' conditions are
useful
// to understand who calls statically who for example to anticipate
future impacts
// of some refactoring or to
provide some customized encapsulation constraints.
SELECT METHODS WHERE DepthOfIsUsing "System.Xml.XmlWriter..ctor()" <=3
// 'IsUsing/IsUsedBy/DepthOfIsUsing/DepthOfIsUsedBy' conditions are
useful
// to understand who calls statically who for example to anticipate
future impacts
// of some refactoring or to
provide some customized encapsulation constraints.
SELECT METHODS WHERE
IsUsedBy "System.Xml.Serialization.SoapSchemaImporter.ImportMembersMapping(String,String,SoapSchemaMember[])"
ORDER BY DepthOfIsUsedBy
// 'IsUsing/IsUsedBy/DepthOfIsUsing/DepthOfIsUsedBy' conditions are
useful
// to understand who calls statically who for example to anticipate
future impacts
// of some refactoring or to
provide some customized encapsulation constraints.
SELECT METHODS WHERE CreateA "System.Xml.XmlWriter" ORDER BY DepthOfCreateA
// 'CreateA'/'DepthOfCreateA' conditions can be useful to enforce some
constraints on design patterns such as factory
// where the ctors must be called
only from certain methods or certain type.
SELECT METHODS WHERE DepthOfCreateA "System.Xml.XmlDocument" < 10 ORDER BY DepthOfCreateA
// 'CreateA'/'DepthOfCreateA' conditions can be useful to enforce some
constraints on design patterns such as factory
// where the ctors must be called
only from certain methods or certain type.
SELECT METHODS WHERE IsUsing "System.Xml.XmlWriter.WriteEndElement()"
SELECT METHODS WHERE IsUsing "System.Web.Security.PassportIdentity.LoginUser()"
OR IsUsedBy "System.Web.Security.PassportIdentity.LoginUser()"
// 'IsUsing/IsUsedBy/DepthOfIsUsing/DepthOfIsUsedBy' conditions are
useful
// to understand who calls statically who for example to anticipate
future impacts
// of some refactoring or to provide
some customized encapsulation constraints.
SELECT TYPES WHERE DepthOfIsUsedBy "System.Net.Sockets.Socket" > 2 ORDER BY DepthOfIsUsedBy
// Try to play with the numeric intellisense by selecting the 2 and
moving the trackbar.
// A 'IsUsing/IsUsed' relation between two types A and B is created by
NDepend as soon as
// there is a 'IsCalled/IsUsedBy'
relation between a method of A and a method of B.
SELECT NAMESPACES WHERE DepthOfIsUsedBy "System.Net.Sockets" <=2
// Try to play with the numeric intellisense by selecting the 2 and
moving the trackbar.
// A 'IsUsing/IsUsed' relation between two namespaces A and B is created
by NDepend as soon as
// there is a 'IsUsing/IsUsed'
relation between a type of A and a type of B.
SELECT TYPES WHERE DeriveFrom "System.Windows.Forms.Control" ORDER BY DepthOfDeriveFrom DESC
SELECT TYPES WHERE DeriveFrom "System.Web.UI.Control" ORDER BY DepthOfDeriveFrom DESC
SELECT TYPES WHERE DepthOfDeriveFrom "System.Windows.Forms.Control" == 1
// Select classes which derive
directly from control.
SELECT TYPES WHERE Implement "System.Web.UI.IDataSource"
SELECT TYPES WHERE Implement "System.Web.IHttpHandler" ORDER BY NbILInstructions DESC
SELECT TYPES WHERE NbChildren > 5 ORDER BY NbChildren DESC
SELECT TOP 10 METHODS WHERE !IsConstructor AND !IsClassConstructor ORDER BY NbILInstructions DESC
// Try to play with the numeric intellisense
by selecting the 2 and moving the trackbar.
SELECT TOP 10 TYPES FROM ASSEMBLIES "System.Web" ORDER BY NbMethods DESC
// Illustrate the 'FROM' domain of
search definition.
SELECT TOP 10 METHODS OUT OF NAMESPACES "System.Windows.Forms" ORDER BY NbVariables DESC
// Illustrate the 'OUT OF' domain
of search definition.
SELECT TOP 10 METHODS ORDER BY NbParameters ,NbVariables ASC, NbILInstructions DESC
// Illustrate the fact that several 'ORDER BY' clause can be specified.
// By default the 'ASC' option is chosen.
// Check in the Query Result panel
that 4 columns are displayed.
SELECT TOP 10 TYPES ORDER BY TypeCa DESC
// TypeCa: Afferent Coupling
// The Afferent Coupling for a particular
type is the number of types that depends directly on it.
SELECT TOP 10 TYPES ORDER BY TypeCe DESC
// TypeCe: Efferent Coupling
// The Efferent Coupling for a
particular type is the number of types it directly depends on..
SELECT TOP 10 METHODS WHERE !IsConstructor AND !IsClassConstructor ORDER BY NbParameters DESC
SELECT TOP 10 METHODS WHERE IsPropertyGetter OR IsPropertySetter ORDER BY NbILInstructions DESC
SELECT TOP 10 TYPES WHERE IsClass ORDER BY NbILInstructions DESC
SELECT TOP 10 TYPES WHERE IsStructure ORDER BY NbILInstructions DESC
SELECT TOP 10 TYPES WHERE IsClass ORDER BY NbFields DESC
SELECT TOP 10 TYPES WHERE IsStructure ORDER BY NbFields DESC
SELECT TOP 10 TYPES WHERE IsClass ORDER BY SizeOfInst DESC
SELECT TOP 10 TYPES WHERE IsStructure ORDER BY SizeOfInst DESC
SELECT TOP 10 NAMESPACES ORDER BY NbILInstructions DESC
SELECT TOP 10 ASSEMBLIES ORDER BY NbILInstructions DESC
SELECT ASSEMBLIES ORDER BY NbILInstructions DESC
The SELECT METHODS expression allows to select all kind
of methods. You can use a combination of following conditions to select some
particular methods:
NbILInstructions NbMethods
NbParameters NbVariables
ILCyclomaticComplexity
IsUsing DepthOfIsUsing IsDirectlyUsing
IsUsedBy DepthOfIsUsedBy
IsDirectlyUsedBy CreateA DepthOfCreateA
IsPublic IsInternal IsProtected IsProtectedOrInternal
IsProtectedAndInternal IsPrivate IsConstructor
IsPropertySetter IsPropertyGetter IsStatic
IsVirtual IsAbstract
IsUsingBoxing IsUsingUnboxing
IsGeneric IsUsingPointers
IsOperator IsIndexerSetter
IsIndexerGetter IsEventAdder
IsEventRemover IsClassConstructor
The SELECT FIELDS
expression allows to select all kind of fields. You can use a combination of
following conditions to select some particular field:
IsPublic IsInternal IsProtected IsProtectedOrInternal
IsProtectedAndInternal IsPrivate IsEnumValue
IsStatic IsLiteral IsInitOnly IsEventDelegateObject
IsUsedBy DepthOfIsUsedBy
IsDirectlyUsedBy
The SELECT TYPES
expression allows to select all kind of types. You can use a combination of
following conditions to select some particular types:
NbILInstructions NbMethods
NbFields NbTypes ILCyclomaticComplexity SizeOfInst DepthOfInheritance
NbChildren TypeCe TypeCa ABT LCOM LCOMHS
IsUsing DepthOfIsUsing IsDirectlyUsing
IsUsedBy DepthOfIsUsedBy
IsDirectlyUsedBy DeriveFrom
DepthOfDeriveFrom Implement
IsPublic IsInternal IsProtected IsProtectedOrInternal
IsProtectedAndInternal IsPrivate IsStatic IsAbstract IsUsingBoxing
IsUsingUnboxing IsGeneric
IsUsingPointers IsClass
IsStructure IsEnumeration
IsInterface IsSealed
IsNested IsDelegate IsAttributeClass IsExceptionClass
The SELECT NAMESPACES expression allows to select
some namespaces. You can use a combination of following conditions to select
some particular namespaces:
NbILInstructions NbMethods
NbFields NbTypes NbNamespaces
IsUsing DepthOfIsUsing IsDirectlyUsing
IsUsedBy DepthOfIsUsedBy
IsDirectlyUsedBy
The SELECT ASSEMBLIES expression allows to select
some assemblies. You can use a combination of following conditions to select
some particular assemblies:
NbILInstructions NbMethods
NbFields NbTypes NbNamespaces Abstracness
Instability NormDistFromMainSeq DistFromMainSeq RelationalCohesion
AsmCa AsmCe
IsUsing DepthOfIsUsing IsDirectlyUsing
IsUsedBy DepthOfIsUsedBy
IsDirectlyUsedBy
You can
transform every CQL query into a CQL constraint by adding a WARN IF xxx IN expression at
the beginning. There are two kinds of CQL constraint.
WARN IF Count >
WARN IF Count <=
WARN IF Percentage >
WARN IF Percentage <=
WARN IF xxx IN expressions are
optional.
You can
restrict the number of code elements selected thanks to a TOP xxx expression. For
example:
SELECT TOP 10 METHODS ORDER BY NbILInstructions DESC
SELECT TOP 10 TYPES WHERE IsStructure ORDER BY SizeOfInst DESC
It is
likely that queries which contain a TOP xxx expression also take
advantage of an ORDER BY xxx
expression.
TOP xxx expressions are
optional.
You can
restrict the domain of search for code elements by using a FROM / OUT OF xxx expression.
By default, the domain of search is the whole set of application assemblies.
A FROM / OUT OF xxx expression
can be defined as a set of assemblies, namespaces or types when the kind of
code elements requested is METHODS or FIELDS. For example:
SELECT METHODS FROM ASSEMBLIES "System" WHERE IsAbstract
SELECT FIELDS OUT OF NAMESPACES "System.Net","System.XML" WHERE IsInitOnly
SELECT METHODS OUT OF TYPES "System.Xml.XmlWriter" WHERE CreateA "System.Xml.XmlWriter"
A FROM / OUT OF xxx expression
can be defined as a set of assemblies or namespaces when the kind of code
elements requested is TYPES. For example:
SELECT TYPES FROM ASSEMBLIES "System","System.XML" WHERE IsDelegate
SELECT TYPES OUT OF NAMESPACES "System.Windows.Forms" WHERE IsUsing "System.Windows.Forms.Control"
A FROM / OUT OF xxx expression
can be defined as a set of assemblies when the kind of code elements requested
is NAMESPACES. For example:
SELECT NAMESPACES OUT OF ASSEMBLIES "System.Windows.Forms" WHERE DepthOfIsUsing "System.Windows.Forms" == 2
The FROM / OUT OF xxx feature is
not available when the kind of code elements requested is ASSEMBLIES.
FROM / OUT OF xxx expressions
are optional.
You can
define a set of condition thanks to:
For
example:
SELECT METHODS WHERE
( NbILInstructions > 200 OR
ILCyclomaticComplexity > 50 OR
NbParameters > 5 OR
NbVariables > 8 )
AND
!( NameLike "InitializeComponent" OR NameLike "Generated")
WHERE xxx expressions are optional
but each query must have either a WHERE xxx expression or an ORDER BY xxx expression or
both.
You can
communicate to the CQL runtime engine how to sort code elements selected thanks
to the ORDER BY xxx
expression. Several metrics can be mentioned. Each metric mentioned can be
followed by one of the keyword ASC
or DESC to precise the
order of sort. The first metric mentioned will be the last one used for
sorting. For example:
SELECT TYPES ORDER BY NbILInstructions
SELECT METHODS ORDER BY NbILInstructions, NbParameters DESC, NbVariables ASC
ORDER BY xxx expressions are
optional but each query must have either a WHERE xxx expression or an ORDER BY xxx expression or
both.
You can use
following metrics to sort your result:
NbILInstructions NbMethods
NbFields NbTypes NbNamespaces NbParameters
NbVariables ILCyclomaticComplexity SizeOfInst DepthOfInheritance
NbChildren TypeCe TypeCa ABT LCOM LCOMHS Abstracness Instability
NormDistFromMainSeq DistFromMainSeq RelationalCohesion
AsmCa AsmCe DepthOfIsUsing DepthOfIsUsedBy DepthOfCreateA
DepthOfDeriveFrom
You can
insert comments à la C++/C#/Java in
your CQL queries, for example:
SELECT METHODS /*Comment 1*/ ORDER
BY NbILInstructions // Comment 2
New in CQL version 1.4
You can
name your queries using the <Name> </Name> tags inside a line of a
comment. Query name are then displayed in VisualNDepend
in lieu of the whole query and can be more meaningful than the whole query
itself:
// <Name>Methods too big (NbLinesOfCode)</Name>
WARN IF Count > 0 IN SELECT TOP 10 METHODS WHERE NbLinesOfCode > 30 ORDER BY NbLinesOfCode DESC
First of
all, here are some C# code extracted from regression tests of NDepend that
illustrates how code elements are named in NDepend:
using
System.Collections.Generic;
using NDepend.CQL;
// Test the anonymous
namespace name : ""
[assembly: CQLConstraint(@"WARN IF Count !=
[CQLConstraint(@"WARN IF Count !=
class TypeInAnonymousNamespace {
[CQLConstraint(@"WARN IF Count !=
internal static
int MethodWithArrayParam(string[] args) { return
5; }
[CQLConstraint(@"WARN IF Count !=
unsafe internal
static void
MethodWithPointerParam(int* arg) { }
[CQLConstraint(@"WARN IF Count !=
internal static
void MethodWithOutParam(out int arg) { arg = 8; }
[CQLConstraint(@"WARN IF Count !=
internal static
void MethodWithRefParam(ref string arg) { }
[CQLConstraint(@"WARN IF Count !=
internal static
void MethodWithGenericParam(Dictionary<int, Dictionary<int, string>> arg) { }
}
[CQLConstraint(@"WARN IF Count !=
interface IInterfaceInAnonymousNamespace {
[CQLConstraint(@"WARN IF Count !=
int NonGenericMethod(short i);
}
namespace Test {
[CQLConstraint(@"WARN IF Count !=
class GenericClass<K, V> {
[CQLConstraint(@"WARN IF Count !=
int GenericMethod<U>(U u) { return 7; }
}
[CQLConstraint(@"WARN IF Count !=
struct GenericStructure<X> {
[CQLConstraint(@"WARN IF Count !=
int
GenericMethod<U>(U u) { return 8; }
}
[CQLConstraint(@"WARN IF Count !=
interface IGenericInterface<S, T>
{
[CQLConstraint(@"WARN IF Count !=
int GenericMethod<U>(U u);
[CQLConstraint(@"WARN IF Count !=
int NonGenericMethod(S s);
}
[CQLConstraint(@"WARN IF Count !=
interface INonGenericInterface {
[CQLConstraint(@"WARN IF Count !=
int GenericMethod<P>(P p);
[CQLConstraint(@"WARN IF Count !=
int NonGenericMethod(int i);
}
[CQLConstraint(@"WARN IF Count !=
class C1<I, J> :
IGenericInterface<I, J>, INonGenericInterface,
IInterfaceInAnonymousNamespace {
[CQLConstraint(@"WARN IF Count !=
int
IInterfaceInAnonymousNamespace.NonGenericMethod(short
i) {
return
i;
}
[CQLConstraint(@"WARN IF Count !=
int
IGenericInterface<I,J>.GenericMethod<U>(U u) {
return
6;
}
[CQLConstraint(@"WARN IF Count !=
int IGenericInterface<I,
J>.NonGenericMethod(I i) {
return
6;
}
[CQLConstraint(@"WARN IF Count !=
int
INonGenericInterface.GenericMethod<P>(P p) {
return
6;
}
[CQLConstraint(@"WARN IF Count !=
int INonGenericInterface.NonGenericMethod(int i) {
return
6;
}
[CQLConstraint(@"WARN IF Count !=
public int
GenericMethod<P>(P p) {
return
6;
}
[CQLConstraint(@"WARN IF Count !=
public int
NonGenericMethod(int i) {
return
6;
}
[CQLConstraint(@"WARN IF Count !=
class C2<Q, R, S> {
[CQLConstraint(@"WARN IF Count !=
public
int GenericMethod<P>(P p) {
return
6;
}
}
[CQLConstraint(@"WARN IF Count !=
class C3 { }
}
}
Sometime, 2
different kinds of code elements can have the same name. For example, you can
have one assembly named Foo, one
namespace named Foo and one class
named Foo. The IsUsing-like
conditions takes a code element as parameter and need to resolve if it is an
assembly, a namespace, a type, a method or a field.
SELECT METHODS WHERE IsDirectlyUsing "Foo"
Such a
query cannot compile because it cannot infer which code element Foo it is referencing. This is why we
need ASSEMBLY: NAMESPACE: TYPE: METHOD: and FIELD: prefixes.
SELECT METHODS WHERE IsDirectlyUsing "NAMESPACE:Foo"
The
OPTIONAL: prefix lets write some generic constraint. Suppose you want to be
advised when a method is using the .NET Framework method: System.Threading.Thread.Sleep(Int32). You just have to write the
following constraint:
WARN IF Count > 0 IN SELECT METHODS WHERE IsDirectlyUsing "System.Threading.Thread.Sleep(Int32)"
However, if
you want to forbid the use of the Thread.Sleep()
method, this method won’t be referenced anymore by the NDepend analysis because
it just keep code elements from tier assemblies that are used from your
application code. As a consequence, the constraint above won’t compile because
the method referenced can’t be found.
The
OPTIONAL: prefix lets remedy this problem and indicate to the CQL compiler that
if the code element is not found, an error should not be emitted:
WARN IF Count > 0 IN SELECT METHODS WHERE IsDirectlyUsing "OPTIONAL:System.Threading.Thread.Sleep(Int32)"
The
OPTIONAL: prefix must always appear before an ASSEMBLY: NAMESPACE: TYPE:
METHOD: or FIELD prefix.
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The
keyword NameLike is used to select code elements
whose names match a given regular expression. Regular expression accepts the
suffix \i to ignore case.
Example:
Select all
fields of application where the name begin with m_
SELECT FIELDS WHERE NameLike "^m_"
Select all
fields of application where the name begin with m_ or M_
SELECT FIELDS WHERE NameLike "^m_\i"
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword NameIs is
used to select code elements whose names are equal to a given string.
Example: Select all methods of application where the
name is .ctor(String)
SELECT METHODS WHERE NameIs ".ctor(String)"
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword FullNameLike is used to select
code elements whose full names match a given regular expression. Regular
expression accepts the suffix \i to ignore case.
Example: Select all methods of application where the
full name (i.e namespace.type.method) contains Database.
SELECT METHODS WHERE FullNameLike "Database"
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword FullNameIs
is used to select code elements whose full names are equal to a given string.
Note that there can’t be more than one code element which matches a FullNameIs condition.
Example: Select all methods of application where the
full name is System.Windows.Forms.ToolStripMenuItem..ctor(String)
SELECT METHODS WHERE FullNameIs "System.Windows.Forms.ToolStripMenuItem..ctor(String)"
New in CQL version 1.1
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: This
metric (known as LOC) can be computed only if PDB files are present. NDepend
computes this metric directly from the info provided in PDB files. The LOC for
a method is equals to the number of sequence point found for this method in the
PDB file. A sequence point is used to mark a spot in the IL code that
corresponds to a specific location in the original source. More info about
sequence points here.Notice that sequence points which
correspond to C# braces‘{‘ and ‘}’ are not taken account.
Computing the number of lines of code from PDB’s sequence points allows to
obtain a logical LOC of code instead of a physical LOC (i.e
directly computed from source files). 2
significant advantages of logical LOC over physical LOC are:
Notice that the LOC for a type is the sum
of its methods’ LOC, the LOC for a namespace is the sum of its types’ LOC, the
LOC for an assembly is the sum of its namespaces’ LOC and the LOC for an
application is the sum of its assemblies LOC. Here are some observations:
Related Link:
Why
is it useful to count the number of Lines Of Code (LOC) ?
How
do you count your number of Lines Of Code (LOC) ?
Example:
SELECT METHODS WHERE NbLinesOfCode > 20
You can
also use the NbILInstructions keyword to
order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY NbLinesOfCode DESC
Recommendations:
METHODS WHERE NbLinesOfCode > 20 are hard to understand and maintain. METHODS WHERE NbILInstructions > 40 are extremely complex and should be
split in smaller methods (except if they are automatically generated by a
tool).
There is no
particular recommendation for NbLinesOfCode
values on ASSEMBLIES, NAMESPACES and TYPES.
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: The number of IL instruction of some code
elements might be 0, for example for abstract method, interface or enumeration.
Example:
SELECT METHODS WHERE NbILInstructions > 200
You can
also use the NbILInstructions keyword to
order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY NbILInstructions DESC
Recommendations:
METHODS WHERE NbILInstructions > 100 are hard to understand and maintain. METHODS WHERE NbILInstructions > 200 are extremely complex and should be
split in smaller methods (except if they are automatically generated by a
tool).
There is no
particular recommendation for NbILInstructions
values on ASSEMBLIES, NAMESPACES and TYPES.
New in CQL version 1.2
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: This metric can be computed only if PDB
files are present and if corresponding source files can be found. The number of
lines of comment is computed as follow:
Notice that
this metric is not an additive metric (i.e for example, the number of lines of
comment of a namespace can be greater than the number of lines of comment over
all its types).
Example:
SELECT METHODS WHERE NbLinesOfComment > 10
You can
also use the NbLinesOfComment keyword to
order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY NbLinesOfComment DESC
Recommendations:
This metric is
not helpful to asses the quality of source code. We prefer to use the metric PercentageComment.
New in CQL version 1.2
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: This
metric is computed with the following formula:
PercentageComment = 100* NbLinesOfComment / (NbLinesOfComment + NbLinesOfCode)
Example:
SELECT METHODS WHERE PercentageComment < 10
You can
also use the PercentageComment keyword
to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY PercentageComment DESC
Recommendations:
Code where the percentage of comment
is lower than 20% should be more commented. However overly commented code (>40%)
is not necessarily a blessing as it can be considered as an insult to the
intelligence of the reader.
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: The value of the NbMethods
metric is equal to 1 for all methods, no matter it is static or not, it is abstract,
it is a constructor, it is a property accessor ….
Example:
SELECT TYPES WHERE NbMethods > 10
You can also use the NbMethods keyword to order the rows in the result list.
SELECT TOP 10 NAMESPACES ORDER BY NbMethods ASC
Recommendations:
TYPES WHERE NbMethods > 20 might be hard to understand and
maintain but there might be cases where it is relevant to have a high value for
NbMethods. For example, the System.Windows.Forms.DataGridView
framework class has more than 1000 methods.
There is no
particular recommendation for NbMethods values
on ASSEMBLIES and NAMESPACES.
Applicable on: ASSEMBLIES NAMESPACES TYPES FIELDS
Remarks: The value of the NbFields
metric is equal to 1 for all fields, no matter it is static or not, it is an
enumeration value, it is literal ….
Example:
SELECT TYPES WHERE NbFields < 10
You can also use the NbFields keyword to order the rows in the result list.
SELECT TOP 10 NAMESPACES ORDER BY NbFields ASC
Recommendations:
TYPES WHERE NbFields > 20 AND !IsEnumeration might be hard to understand and maintain but there
might be cases where it is relevant to have a high value for NbFields. For example, the System.Windows.Forms.Control framework class has more than 200
fields. The value of the metric SizeOfInst might
be a better indicator to pinpoint complex types.
There is no
particular recommendation for NbFields values on
ASSEMBLIES and NAMESPACES.
Applicable on: ASSEMBLIES NAMESPACES TYPES
Remarks: The value of the NbTypes
metric is equal to 1 for all types, no matter it is a class, an interface, a
structure, a delegate, a nested type….
Examples:
SELECT ASSEMBLIES WHERE NbTypes > 10
You can also use the NbTypes keyword to order the rows in the result list.
SELECT TOP 10 NAMESPACES ORDER BY NbTypes ASC
Recommendations:
There is no
particular recommendation for NbTypes values on ASSEMBLIES and NAMESPACES.
Applicable on: ASSEMBLIES NAMESPACES
Remarks: The value of the NbNamespaces
metric is equal to 1 for all namespaces.
Example:
SELECT ASSEMBLIES WHERE NbNamespaces == 10
You can also use the NbNamespaces keyword to order the rows in the result list.
SELECT TOP 10 ASSEMBLIES ORDER BY NbNamespaces DESC
Recommendations:
There is no
particular recommendation for NbNamespaces
values on ASSEMBLIES.
Applicable on: TYPES
Remarks: The value of the NbInterfacesImplemented metric is equal
the number of interfaces implemented by a type. This metric is available for
interfaces, in this case the value is the number of interface extended,
directly or indirectly. For derived class, this metric also count the sum of
interfaces implemented by base class(es).
Example:
SELECT TYPES WHERE NbInterfacesImplemented > 3
You can also use the NbInterfacesImplemented keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY NbInterfacesImplemented DESC
Applicable on: METHODS
Remarks: The keyword NbParameters
is used to define a condition on the number of parameters in METHODS. Note that the this reference passed as parameters to instance methods in IL is
not taken account by the underlying metric.
Example:
SELECT METHODS WHERE NbParameters > 2
You can also use the NbParameters keyword to order the rows in the result list.
SELECT TOP 10 METHODS ORDER BY NbParameters DESC
Recommendations:
METHODS WHERE NbParameters > 5 might be painful to call and might
degrade performance. You should prefer using additional properties/fields to
the declaring type to handle numerous states. Another alternative is to provide
a class or structure dedicated to handle arguments passing (for example see the
class System.Diagnostics.ProcessStartInfo
and the method System.Diagnostics.Process.Start(ProcessStartInfo)).
Applicable on: METHODS
Remarks: The keyword NbVariables
is used to define a condition on the number of local variables declared in METHODS.
Example:
SELECT METHODS WHERE NbParameters > 2
You can also use the NbVariables keyword to order the rows in the result list.
SELECT TOP 10 METHODS ORDER BY NbParameters DESC
Recommendations:
METHODS WHERE NbVariables > 8 are hard to understand and maintain.
METHODS WHERE NbVariables > 15 are extremely complex and should be
split in smaller methods (except if they are automatically generated by a
tool).
New in CQL version 1.8
Applicable on: METHODS
Remarks: The keyword NbOverloads
is used to define a condition on the number of overloads of a METHODS. If a method is not overloaded, its NbOverloads value is equals to 1. This metric is
also applicable to constructors.
Example:
SELECT METHODS WHERE NbOverloads > 6
You can also use the NbParameters keyword to order the rows in the result list.
SELECT TOP 10 METHODS ORDER BY NbOverloads DESC
Recommendations:
METHODS WHERE NbOverloads > 6 might be a problem to maintain and
provoke higher coupling than necessary. This might also reveal a potential
misused of the C# and VB.NET language that since C#3 and VB9 support object
initialization. This feature helps reducing the number of constructors of a
class.
New in CQL version 1.2
Remarks: Cyclomatic
complexity is a popular procedural software metric equal to the number of
decisions that can be taken in a procedure. Concretely, in C# the CC of a
method is the number of following expressions found in the body of the method:
if | while | for | foreach | case | default | continue | goto | && | ||
| catch | ternary operator ?: | ??
Following expressions are not counted for CC computation:
else | do | switch | try | using | throw | finally | return | object creation |
method call | field access
Adapted to the OO world, this metric is defined both on methods and
classes/structures (as the sum of its methods CC). Notice that the CC of an
anonymous method is not counted when computing the CC of its outer method.
Example:
SELECT METHODS WHERE CyclomaticComplexity > 30
You can also use the CyclomaticComplexity keyword to order the rows in the result list.
SELECT TOP 10 METHODS ORDER BY CyclomaticComplexity DESC
Recommendations:
Methods where CC is higher than 15 are
hard to understand and maintain. Methods where CC is higher than 30 are
extremely complex and should be split in smaller methods (except if they are
automatically generated by a tool).
Remarks: Cyclomatic complexity is a popular procedural
software metric equals to the number of decision that can be taken in a
procedure (i.e number of if/else, switch/case, ternary operator, loop…).
Adapted to the OO world, this metric is defined both on methods and
classes/structures (as the sum of its methods CC).
This metric
is language dependent, and NDepend only cops with the IL language. Thus, CC in
NDepend is defined on a method as the number of different offsets targeted by a
jump/branch IL instruction. Experience shows that NDepend CC is between two and
three times larger than the CC computed in C# or VB.NET. Indeed, a C# for loop
yields two different offsets targeted by a branch IL instruction while a
foreach C# loop yields three ones.
Example:
SELECT METHODS WHERE ILCyclomaticComplexity > 30
You can also use the ILCyclomaticComplexity keyword to order the rows in the result list.
SELECT TOP 10 METHODS ORDER BY NbParameters DESC
Recommendations:
METHODS WHERE ILCyclomaticComplexity > 20 are hard to understand and maintain.
METHODS WHERE ILCyclomaticComplexity > 40 are extremely complex and should be split in smaller
methods (except if they are automatically generated by a tool).
There is no
particular recommendation for ILCyclomaticComplexity
values on TYPES.
Applicable on: METHODS
Remarks: The metric Nesting Depth for a method
is the maximum number of encapsulated scopes inside the body of the method. The
metric IL Nesting Depth is computed from the IL code. Values computed are very
similar to what we would expect by computing them from the C# or VB.NET source
code.
When you have a testing condition with N conditions, such as
if( i > 9 && i < 12) then it is considered as N scopes because it
is possible to decompose such conditions into N atomic conditions.
When a method has a large number of case statements
corresponding to a switch, the C# and VB.NET compiler generally produce
optimizations while generating the IL. In such case, the IL Nesting Depth
corresponding value might be slightly higher to what you would expect.
Related
Link: A
simple trick to code better and to increase testability
Example:
SELECT METHODS WHERE ILNestingDepth > 4
You can also use the ILNestingDepth keyword to order the rows in the result list.
SELECT TOP 10 METHODS ORDER BY ILNestingDepth DESC
Recommendations:
METHODS WHERE ILNestingDepth > 4 are hard to understand and maintain.
METHODS WHERE ILNestingDepth > 8 are extremely complex and should be split in smaller
methods (except if they are automatically generated by a tool).
Remarks: The size of instances of an instance field is
defined as the size, in bytes, of instances of its type. The size of instance
of a static field is equal to 0. The size of instances of a class or a
structure is defined as the sum of size of instances of its fields plus the
size of instances of its base class. Fields of reference types (class,
interface, delegate…) always count for 4 bytes while the footprint of fields of
value types (structure, int, byte, double…) might vary. Size of instances of an
enumeration is equal to the size of instances of the underlying numeric
primitive type. It is computed from the value__
instance field (all enumerations have such a field when compiled in IL). Size
of instances of generic types might be erroneous because we can’t statically
know the footprint of parameter types (except when they have the class constraint).
Example:
SELECT TYPES WHERE SizeOfInst > 12
You can also use the SizeOfInst keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY SizeOfInst DESC
Recommendations:
TYPES WHERE SizeOfInst > 64 might degrade performance (depending
on the number of instances created at runtime) and might be hard to maintain.
However it is not a rule since sometime there is no alternative (the size of
instances of the System.Net.NetworkInformation.SystemIcmpV6Statistics
framework class is 2064 bytes).
TYPES WHERE SizeOfInst ==0 AND !IsStatic AND !IsGeneric indicate
stateless types that might eventually be turned into static classes.
There is no
particular recommendation for SizeOfInst values
on FIELDS.
New in CQL version 1.1
Applicable on: TYPES
Remarks: TypeRank values
are computed by applying the Google PageRank algorithm on the graph of types' dependencies. A homothety of center
0.15 is applied to make it so that the average of TypeRank
is 1.
Related Link: Code
metrics on Coupling, Dead Code, Design flaws and Re-engineering
Example:
SELECT TYPES WHERE TypeRank > 0.7
You can
also use the TypeRank keyword to order the rows in
the result list.
SELECT TYPES WHERE TypeRank > 0.7 ORDER BY TypeRank DESC
Recommendations:
Types with
high TypeRank should be more carefully tested
because bugs in such types will likely be more catastrophic.
New in CQL version 1.1
Applicable on: METHODS
Remarks: MethodRank
values are computed by applying the Google PageRank algorithm on the graph of methods' dependencies. A homothety of center
0.15 is applied to make it so that the average of MethodRank
is 1.
Related Link: Code
metrics on Coupling, Dead Code, Design flaws and Re-engineering
Example:
SELECT METHODS WHERE MethodRank > 0.7
You can
also use the MethodRank keyword to order the rows
in the result list.
SELECT METHODS WHERE MethodRank > 0.7 ORDER BY MethodRank DESC
Recommendations:
Methods
with high MethodRank should be more carefully
tested because bugs in such methods will likely be more catastrophic.
Applicable on: TYPES
Remarks: The depth of inheritance for a class is
defined as its number of base classes (including the System.Object class thus depth of inheritance >= 1). The depth of inheritance for an interface is equal
to 0. The depth of inheritance for a value type (structure, enumeration) is
equal to 2 since they all derive directly from System.ValueType.
Example:
SELECT TYPES WHERE DepthOfInheritance > 4
You can also use the DepthOfInheritance keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY DepthOfInheritance DESC
Recommendations:
TYPES WHERE DepthOfInheritance > 6 might be hard to maintain. However it is not a
rule since sometime your classes might inherit from tier classes which have a
high value for depth of inheritance. For example, the average depth of
inheritance for framework classes which derive from System.Windows.Forms.Control is 5.3.
Applicable on: TYPES
Remarks: The number of children for a class is the
number of sub-classes (no matter their positions in the sub branch of the
inheritance tree). The number of children for an interface is the number of
types that implement it. Types with numerous children are central type (the
framework interface System.ComponentModel.IComponent
is implemented by hundreds of classes).
Example:
SELECT TYPES WHERE NbChildren > 10
You can also use the NbChildren keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY NbChildren DESC
Recommendations:
There is no
particular recommendation for NbChildren values
on TYPES.
New in CQL version 1.1
Applicable on: FIELDS
Remarks: The Afferent Coupling for a particular field
is the number of methods that directly use it.
Related Link: Code
metrics on Coupling, Dead Code, Design flaws and Re-engineering
Example:
SELECT FIELDS WHERE FieldCa > 10
You can also use the FieldCa keyword to order the rows in the result list.
SELECT TOP 10 FIELDS ORDER BY FieldCa DESC
Recommendations:
There is no
particular recommendation for FieldCa values on FIELDS.
New in CQL version 1.1
Applicable on: METHODS
Remarks: The Efferent Coupling for a particular method is
the number of methods it directly depends on. Notice that methods declared in
framework assemblies are taken into account.
Related Link: Code
metrics on Coupling, Dead Code, Design flaws and Re-engineering
Example:
SELECT METHODS WHERE MethodCe > 10
You can also use the MethodCe keyword to order the rows in the result list.
SELECT TOP 10 METHODS ORDER BY MethodCe DESC
Recommendations:
There is no
particular recommendation for MethodCe values on METHODS.
New in CQL version 1.1
Applicable on: METHODS
Remarks: The Afferent Coupling for a particular method
is the number of methods that depends directly on it.
Related Link: Code
metrics on Coupling, Dead Code, Design flaws and Re-engineering
Example:
SELECT METHODS WHERE MethodCa > 10
You can also use the MethodCa keyword to order the rows in the result list.
SELECT TOP 10 METHODS ORDER BY MethodCa DESC
Recommendations:
There is no
particular recommendation for MethodCa values on METHODS.
Applicable on: TYPES
Remarks: The efferent coupling for a particular type is
the number of types it directly depends on. Types with high efferent coupling
are more complex than others but you can’t avoid them.
Related Link: Code
metrics on Coupling, Dead Code, Design flaws and Re-engineering
Example:
SELECT TYPES WHERE TypeCe > 10
You can also use the TypeCe keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY TypeCe DESC
Recommendations:
There is no
particular recommendation for TypeCe values on TYPES.
Applicable on: TYPES
Remarks: The afferent coupling for a particular type is
the number of types that depends directly on it. Types with high afferent
coupling are central type. The fact the public class System.Web.AspNetHostingPermissionAttribute holds one of the
highest afferent coupling of the framework is a good indication of the
commitment of Microsoft on security.
Related Link: Code
metrics on Coupling, Dead Code, Design flaws and Re-engineering
Example:
SELECT TYPES WHERE TypeCa > 10
You can also use the TypeCa keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY TypeCa DESC
Recommendations:
There is no
particular recommendation for TypeCa values on TYPES.
New in CQL version 1.1
Applicable on: NAMESPACES
Remarks: The Efferent Coupling for a particular
namespace is the number of namespaces it directly depends on. Notice that
namespaces declared in framework assemblies are taken into account.
Related Link: Code
metrics on Coupling, Dead Code, Design flaws and Re-engineering
Example:
SELECT NAMESPACES WHERE NamespaceCe > 10
You can also use the NamespaceCe keyword to order the rows in the result list.
SELECT TOP 10 NAMESPACES ORDER BY NamespaceCe DESC
Recommendations:
There is no
particular recommendation for NamespaceCe values
on NAMESPACES.
New in CQL version 1.1
Applicable on: NAMESPACES
Remarks: The Afferent Coupling for a particular
namespace is the number of namespaces that depends directly on it.
Related Link: Code
metrics on Coupling, Dead Code, Design flaws and Re-engineering
Example:
SELECT NAMESPACES WHERE NamespaceCa > 10
You can also use the NamespaceCa keyword to order the rows in the result list.
SELECT TOP 10 NAMESPACES ORDER BY NamespaceCa DESC
Recommendations:
There is no
particular recommendation for NamespaceCa values
on NAMESPACES.
Applicable on: TYPES
Remarks: The Association Between Types metric for a
particular class or structure is the number of members of others types it
directly uses in the bodies of its methods. Types with high Association Between
Types are more complex than others but you can’t avoid them.
Example:
SELECT TYPES WHERE ABT > 100
You can also use the ABT keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY ABT DESC
Recommendations:
There is no
particular recommendation for ABT values on TYPES.
Applicable on: TYPES
Remarks: The single responsibility principle states that a class should have more than one reason to change. Such a class is said to be cohesive. A high LCOM value generally pinpoints a poorly cohesive class. There are several LCOM metrics. The LCOM takes its values in the range [0-1]. The LCOMHS (HS stands for Henderson-Sellers) takes its values in the range [0-2]. Note that the LCOMHS metric is often considered as more efficient to detect non-cohesive types. A LCOMHS value higher than 1 should be considered alarming.
Here are
algorithms used by NDepend to compute LCOM metrics:
Where:
Example:
SELECT TYPES WHERE LCOM > 0.8
You can also use the LCOM keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY LCOM DESC
Recommendations:
TYPES WHERE LCOM > 0.8 AND NbFields > 10 AND NbMethods >10 might be problematic. However, it is
very hard to avoid such non-cohesive types.
Applicable on: TYPES
Remarks: See the section LCOM T (Lack Of Cohesion Of Methods) for the
definition of the LCOMHS
metric.
Example:
SELECT TYPES WHERE LCOMHS > 1.1
You can also use the LCOMHS keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY BY LCOMHS DESC
Recommendations:
TYPES WHERE LCOMHS > 1.0 AND NbFields > 10 AND NbMethods >10 should be avoided. Note that this
constraint is stronger than the constraint TYPES WHERE LCOM > 0.8 AND NbFields > 10 AND NbMethods >10.
New in CQL version 1.2
Applicable on: TYPES
Remarks: The Level value for a namespace is
defined as follow:
Level metric definitions for
assemblies, types and methods are inferred from the above definition.
This metric has been first defined by John Lakos in his book Large-Scale
C++ Software Design.
Related Link: Layering,
the Level metric and the Discourse of Method
Example:
SELECT TYPES WHERE TypeLevel ==
10
You can also use the AssemblyLevel keyword to order the rows in the result list.
SELECT ASSEMBLIES ORDER BY AssemblyLevel DESC
Recommendations:
This metric helps objectively classify the assemblies, namespaces, types
and methods as high level,mid level or low level. There is no particular
recommendation for high or small values.
This metric is also useful to discover dependency cycles in your application.
For instance if some namespaces are matched by the following CQL query, it
means that there is some dependency cycles between the namespaces of your
application:
SELECT NAMESPACES WHERE !HasLevel AND !IsInFrameworkAssembly
Applicable on: ASSEMBLIES
Remarks: The ratio of the number of internal abstract
types (i.e abstract classes and interfaces) to the number of internal types.
The range for this metric is 0 to 1, with Abstracness=0
indicating a completely concrete assembly and Abstracness=1
indicating a completely abstract assembly.
Example:
SELECT ASSEMBLIES WHERE Abstractness > 0.15
You can also use the Abstracness keyword to order the rows in the result list.
SELECT TOP 10 ASSEMBLIES ORDER BY Abstractness DESC
Recommendations:
There is no particular recommendation for Abstracness values on ASSEMBLIES.
Applicable on: ASSEMBLIES
Remarks: The ratio of efferent coupling (AsmCe) to total coupling. Instability = AsmCe / (AsmCe + AsmCa). This metric is an indicator
of the package's resilience to change. The range for this metric is 0 to 1,
with Instability=0 indicating a completely
stable package and Instability=1 indicating a
completely instable package.
Example:
SELECT ASSEMBLIES WHERE Instability > 0.15
You can also use the Abstracness keyword to order the rows in the result list.
SELECT TOP 10 ASSEMBLIES ORDER BY Instability DESC
Recommendations:
There is no particular recommendation for Instability values on ASSEMBLIES.
Applicable on: ASSEMBLIES
Remarks: The perpendicular normalized distance of an
assembly from the idealized line Abstracness + Instability = 1 (called main sequence). This metric
is an indicator of the assembly's balance between abstractness and stability.
An assembly squarely on the main sequence is optimally balanced with respect to
its abstractness and stability. Ideal assemblies are either completely abstract
and stable (Instability=0, Abstracness=1) or completely concrete and instable
(Instability=1, Abstracness=0).
The range for this metric is 0 to 1, with NormDistFromMainSeq=0 indicating an assembly that is
coincident with the main sequence and NormDistFromMainSeq=1 indicating an assembly that is as
far from the main sequence as possible. The picture in the report of NDepend
reveals if an assembly is in the zone of pain (Instability
and Abstracness both close to 0) or in the zone
of uselessness (Instability and Abstracness both close to 1).
Example:
SELECT ASSEMBLIES WHERE NormDistFromMainSeq > 0.5
You can also use the NormDistFromMainSeq keyword to order the rows in the result list.
SELECT TOP 10 ASSEMBLIES ORDER BY NormDistFromMainSeq DESC
Recommendations:
ASSEMBLIES WHERE NormDistFromMainSeq > 0.7 might be problematic. However, in the real
world it is very hard to avoid such assemblies. Therefore, you should allow a
small percentage of your assemblies to violate this constraint. WARN IF Percentage >
Applicable on: ASSEMBLIES
Remarks: The metric DistFromMainSeq is equal to NormDistFromMainSeq / Sqrt(2). The range for this
metric is thus 0 to 0.7071(…).
Example:
SELECT ASSEMBLIES WHERE DistFromMainSeq > 0.3
You can also use the DistFromMainSeq keyword to order the rows in the result list.
SELECT TOP 10 ASSEMBLIES ORDER BY DistFromMainSeq DESC
Recommendations:
See NormDistFromMainSeq recommendations.
Applicable on: ASSEMBLIES
Remarks: Average number of internal relationships per
type. Let R be the number of type relationships that are internal to this
assembly (i.e that do not connect to types outside the assembly). Let N be the
number of types within the assembly. RelationalCohesion
= (R + 1)/ N. The extra
Example:
SELECT ASSEMBLIES WHERE RelationalCohesion < 4
You can also use the RelationalCohesion keyword to order the rows in the result list.
SELECT TOP 10 ASSEMBLIES ORDER BY RelationalCohesion DESC
Recommendations:
As classes
inside an assembly should be strongly related, the cohesion should be high. On
the other hand, too high values may indicate over-coupling. A good range for RelationalCohesion is 1.5 to 4.0. ASSEMBLIES WHERE RelationalCohesion < 1.5 OR RelationalCohesion > 4.0 might be problematic.
Applicable on: ASSEMBLIES
Remarks: The number of types outside this assembly that
depend on types within this assembly. High afferent coupling indicates that the
concerned assemblies have many responsibilities.
Example:
SELECT ASSEMBLIES WHERE AsmCa > 10
You can also use the AsmCa keyword to order the rows in the result list.
SELECT TOP 10 ASSEMBLIES ORDER
BY AsmCa DESC
Recommendations:
There is no
particular recommendation for AsmCa values on ASSEMBLIES.
Applicable on: ASSEMBLIES
Remarks: The number of types inside this assembly that
depends on types outside this assembly. High efferent coupling indicates that
the concerned assembly is dependant.
Example:
SELECT ASSEMBLIES WHERE AsmCe > 10
You can also use the AsmCe keyword to order the rows in the result list.
SELECT TOP 10 ASSEMBLIES ORDER
BY AsmCe DESC
Recommendations:
There is no
particular recommendation for AsmCe values on ASSEMBLIES.
Coverage
metrics are not available if the metric NbLinesOfCode
is not available.
New in CQL version 1.7
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: Percentage
of code coverage by tests. Code coverage data are imported from coverage files.
If you are using the uncoverable attribute feature on a method for example, if all
sibling methods are 100% covered, then the parent type will be considered as
100% covered.
Related Link:
Example:
SELECT METHODS WHERE PercentageCoverage < 100
You can
also use the PercentageCoverage
keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY PercentageCoverage DESC
Recommendations: The closer to 100%, the better.
New in CQL version 1.7
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: The number
of lines of code covered by tests.
Related Link:
Example:
SELECT METHODS WHERE NbLinesOfCodeCovered == 0
You can
also use the NbLinesOfCodeCovered
keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY NbLinesOfCodeCovered DESC
New in CQL version 1.7
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: The
number of lines of not code covered by tests.
Related Link:
Example:
SELECT METHODS WHERE NbLinesOfCodeNotCovered > 0
You can
also use the NbLinesOfCodeNotCovered
keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY NbLinesOfCodeNotCovered DESC
New in CQL version 1.7
Applicable on: METHODS
Remarks: Branch
coverage is a more accurate measure of coverage than PercentageCoveragebecause it compensates for method
complexity. Since branch coverage is generated from the underlying opcodes, it
often does not map cleanly to source code. That means it’s difficult to take branch
coverage values and determine how to write tests that will improve coverage.
Branch coverage is only available if your
coverage data are imported from NCover™
coverage files.
Related Link:
Example:
SELECT METHODS WHERE PercentageBranchCoverage < 0
You can
also use the PercentageBranchCoverage
keyword to order the rows in the result list.
SELECT TOP 10 TYPES ORDER BY PercentageBranchCoverage DESC
Recommendations: The bottom line is:
·
Use
PercentageCoverage as your measure of
quality, but
·
Use
PercentageBranchCoverage to
determine which code statements need more testing.
It is also
interesting to observe branch coverage values in conjunction with Code Source
Cyclomatic Complexity values.
New in CQL version 1.7
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: The
keyword IsExcludedFromCoverage is used to define a condition that
matches ASSEMBLIES NAMESPACES TYPES or
METHODS that don’t have associated coverage
data. It doesn’t necessarily mean that the code element is not covered by tests
but it means that no coverage data have been gathered because:
·
No
coverage data is available for the code element or,
·
The
coverage file is not in-sync with the code or,
·
The
code element is tagged with the un-coverable attribute or,
·
The
code element only contains methods that match IsExcludedFromCoverage.
Example:
SELECT METHODS WHERE IsExcludedFromCoverage
Related Links:
·
Keep
your code structure clean
·
Hints
on how to componentize existing code
Enhanced in CQL
version 1.1
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: The keyword IsUsing
is used to select code elements (ASSEMBLIES NAMESPACES TYPES METHODS) which use directly or indirectly a
particular code element “XXX”. The column DepthOfIsUsing
“XXX” appears automatically in the table result. A code element which uses
directly the code element “XXX” has a DepthOfIsUsing
“XXX” value equal to
Since CQL
1.1, the code element referred by the IsUsing
clause is not necessarily at the same level as the code elements returned by
the query. In the following example the IsUsing
clause is referring to a namespace (System.Net)
while the query is returning some methods.
SELECT TYPES WHERE IsUsing "System.Net" ORDER BY DepthOfIsUsing
Example:
SELECT METHODS WHERE IsUsing "System.Xml.XmlWriter.WriteEndElement()"
SELECT TYPES WHERE IsUsing "System.Net.Sockets
"
SELECT NAMESPACES WHERE IsUsing "System.Net.Sockets.Socket"
SELECT ASSEMBLIES WHERE IsUsing "System.Net.Sockets.Socket"
In this
context, you can also use the DepthOfIsUsing
keyword to order the rows in the result list.
SELECT METHODS WHERE IsUsing "System.Xml.XmlWriter.WriteEndElement()"
BY DepthOfIsUsing
SELECT TYPES WHERE IsUsing "System.Net.Sockets
" ORDER BY DepthOfIsUsing
SELECT NAMESPACES WHERE IsUsing "System.Net.Sockets.Socket" ORDER BY DepthOfIsUsing
Enhanced in CQL
version 1.1
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: See the section IsUsing
ANTM for the definition of the DepthOfIsUsing
metric.
Since CQL
1.1, the code element referred by the DepthOfIsUsing
clause is not necessarily at the same level as the code elements returned by
the query. In the following example the DepthOfIsUsing
clause is referring to a namespace (System.Net)
while the query is returning some types.
SELECT TYPES WHERE DepthOfIsUsing "System.Net" <
3 ORDER BY DepthOfIsUsing
Examples:
SELECT METHODS WHERE DepthOfIsUsing "System.Xml.XmlWriter.WriteEndElement()"
< 3
SELECT TYPES WHERE DepthOfIsUsing "System.Net.Sockets.Socket" <
3
SELECT NAMESPACES WHERE DepthOfIsUsing "System.Net.Sockets" <
3
SELECT ASSEMBLIES WHERE DepthOfIsUsing "System" <
3
In this
context, you can also use the DepthOfIsUsing
keyword to order the rows in the result list.
SELECT METHODS WHERE DepthOfIsUsing "System.Xml.XmlWriter.WriteEndElement()"
< 3 ORDER BY DepthOfIsUsing
SELECT TYPES WHERE DepthOfIsUsing "System.Net.Sockets.Socket" <
3 ORDER BY DepthOfIsUsing
SELECT NAMESPACES WHERE DepthOfIsUsing "System.Net.Sockets" <
3 ORDER BY DepthOfIsUsing
SELECT ASSEMBLIES WHERE DepthOfIsUsing "System" <
3 ORDER BY DepthOfIsUsing
New in CQL version 1.1
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: The keyword IsDirectlyUsing
is used to select code elements (ASSEMBLIES NAMESPACES TYPES METHODS) which use directly a particular code
element “XXX”. The column DepthOfIsUsing
“XXX” appears automatically in the table result. The clause IsDirectlyUsing “XXX” is equivalent to the
clause DepthOfIsUsing “XXX” == 1.
Example:
SELECT METHODS WHERE IsDirectlyUsing "System.Xml.XmlWriter.WriteEndElement()"
In this
context, you can also use the DepthOfIsUsing
keyword to order the rows in the result list.
SELECT METHODS WHERE IsDirectlyUsing "System.Xml.XmlWriter.WriteEndElement()"
BY DepthOfIsUsing
Enhanced in CQL
version 1.1
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword IsUsedBy
is used to select code elements (ASSEMBLIES, NAMESPACES TYPES METHODS FIELDS) which
are directly or indirectly used by a particular code element “XXX”. The column DepthOfIsUsedBy “XXX” appears automatically
in the table result. The code element “XXX” has a DepthOfIsUsedBy “XXX” value equal to
Since CQL
1.1, the code element referred by the IsUsedBy
clause is not necessarily at the same level as the code elements returned by
the query. In the following example the IsUsedBy
clause is referring to a namespace (System.Net)
while the query is returning some types.
SELECT TYPES WHERE IsUsedBy "System.Net"
Examples:
SELECT METHODS WHERE IsUsedBy "System.Xml.XmlWriter.WriteEndElement()"
SELECT TYPES WHERE IsUsedBy "System.Net.Sockets.Socket"
SELECT NAMESPACES WHERE IsUsedBy "System.Net.Sockets"
SELECT ASSEMBLIES WHERE IsUsedBy "System"
In this
context, you can also use the DepthOfIsUsedBy
keyword to order the rows in the result list.
SELECT METHODS WHERE IsUsedBy "System.Xml.XmlWriter.WriteEndElement()" ORDER BY DepthOfIsUsedBy
SELECT TYPES WHERE IsUsedBy "System.Net.Sockets.Socket" ORDER BY DepthOfIsUsedBy
SELECT NAMESPACES WHERE IsUsedBy "System.Net.Sockets" ORDER BY DepthOfIsUsedBy
SELECT ASSEMBLIES WHERE IsUsedBy "System" ORDER BY DepthOfIsUsedBy
Enhanced in CQL
version 1.1
Applicable on: ASSEMBLIES NAMESPACES TYPES FIELDS
Remarks: See the section IsUsedBy
ANTMF for the definition of the DepthOfIsUsedBy
metric.
Since CQL
1.1, the code element referred by the DepthOfIsUsedBy
clause is not necessarily at the same level as the code elements returned by
the query. In the following example the DepthOfIsUsedBy
clause is referring to a namespace (System.Net)
while the query is returning some types.
SELECT TYPES WHERE DepthOfIsUsedBy "System.Net" <
3 ORDER BY DepthOfIsUsedBy
Examples:
SELECT METHODS WHERE DepthOfIsUsedBy "System.Xml.XmlWriter.WriteEndElement()" ORDER BY DepthOfIsUsedBy
SELECT TYPES WHERE DepthOfIsUsedBy "System.Net.Sockets.Socket" <
3
SELECT NAMESPACES WHERE DepthOfIsUsedBy "System.Net.Sockets" <
3
SELECT ASSEMBLIES WHERE DepthOfIsUsedBy "System" <
3
In this
context, you can also use the DepthOfIsUsedBy
keyword to order the rows in the result list.
SELECT METHODS WHERE DepthOfIsUsedBy "System.Xml.XmlWriter.WriteEndElement()" ORDER BY DepthOfIsUsedBy
SELECT TYPES WHERE DepthOfIsUsedBy "System.Net.Sockets.Socket" <
3 ORDER BY DepthOfIsUsedBy
SELECT NAMESPACES WHERE DepthOfIsUsedBy "System.Net.Sockets" <
3 ORDER BY DepthOfIsUsedBy
SELECT ASSEMBLIES WHERE DepthOfIsUsedBy "System" <
3 ORDER BY DepthOfIsUsedBy
New in CQL version 1.1
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword IsDirectlyUsedBy
is used to select code elements (ASSEMBLIES, NAMESPACES TYPES METHODS FIELDS) which
are directly used by a particular code element “XXX”. The column DepthOfIsUsedBy “XXX” appears automatically
in the table result. The clause IsDirectlyUsedBy
“XXX” is equivalent to the clause DepthOfIsUsedBy
“XXX” == 1.
Examples:
SELECT TYPES WHERE IsDirectlyUsedBy "System.Net.Sockets.Socket"
In this
context, you can also use the DepthOfIsUsedBy
keyword to order the rows in the result list.
SELECT TYPES WHERE IsDirectlyUsedBy "System.Net.Sockets.Socket" ORDER BY DepthOfIsUsedBy
Applicable on: METHODS
Remarks: The keyword CreateA
is used to select METHODS which call directly or
indirectly a constructor of a particular type “XXX”. The column DepthOfCreateA “XXX” appears automatically in
the table result. A constructor of the type “XXX” has a DepthOfCreateA “XXX” value equal to 0. A method which calls directly a constructor
of “XXX” has a DepthOfCreateA “XXX” value
equal to
Example:
SELECT METHODS WHERE CreateA "System.Xml.XmlWriter"
In this
context, you can also use the DepthOfCreateA
keyword to order the rows in the result list.
SELECT METHODS WHERE CreateA "System.Xml.XmlWriter" ORDER BY DepthOfCreateA DESC
Applicable on: METHODS
Remarks: See the section CreateA
M for the definition of the DepthOfCreateA
metric.
Example:
SELECT METHODS WHERE DepthOfCreateA "System.Xml.XmlWriter" < 3
In this
context, you can also use the DepthOfCreateA
keyword to order the rows in the result list.
Applicable on: TYPES
Remarks: The keyword DeriveFrom
is used to select TYPES which derive from directly
or indirectly a particular class “XXX”. The column DepthOfDeriveFrom “XXX” appears automatically
in the table result. The class “XXX” has a DepthOfDeriveFrom
“XXX” value equal to
Example:
SELECT TYPES WHERE DeriveFrom "System.Windows.Forms.Control"
In this
context, you can also use the DepthOfDeriveFrom
keyword to order the rows in the result list.
Applicable on: TYPES
Remarks: See the section DeriveFrom
T for the definition of the DepthOfDeriveFrom
metric.
Example:
SELECT TYPES WHERE DepthOfDeriveFrom "System.Windows.Forms.Control"> 3
In this
context, you can also use the DepthOfDeriveFromkeyword
to order the rows in the result list.
SELECT TYPES WHERE DepthOfDeriveFrom "System.Windows.Forms.Control"> 3
ORDER BY DepthOfDeriveFrom
Applicable on: TYPES
Remarks: The keyword Implement
is used to select TYPES which implement or extend
a particular interface “XXX”.
Example:
Applicable on: ASSEMBLIES TYPES METHODS FIELDS
Remarks: The keyword HasAttribute
is used to select ASSEMBLIES TYPES METHODS and FIELDS that are tagged with a particular attribute
“XXX”.
Example:
SELECT METHODS WHERE HasAttribute "NUnit.Framework.Test"
Applicable on: FIELDS
Remarks: The keyword IsOfType
is used to select FIELDS of a particular type
“XXX”.
Example:
SELECT FIELDS WHERE IsOfType "System.Uri"
New in CQL version 1.3
Applicable on: METHODS
Remarks: The keyword ReturnType
is used to select FIELDS of a particular type
“XXX”.
Example:
SELECT FIELDS WHERE IsOfType "System.Uri"
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword IsPublic
is used to define a condition that matches public TYPES,
METHODS or FIELDS.
Example:
SELECT METHODS WHERE IsPublic
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword IsInternal
is used to define a condition that matches internal TYPES,
METHODS or FIELDS
(in VB.NET the syntax for the internal
visibility is Friend).
Example:
SELECT TYPES WHERE IsInternal
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword IsProtected
is used to define a condition that matches protected TYPES,
METHODS or FIELDS.
Note that a type can be declared as protected only if it is nested in another
type.
Example:
SELECT METHODS WHERE IsProtected
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword IsProtectedOrInternal is used to define
a condition that matches protected or internal TYPES,
METHODS or FIELDS
(in VB.NET the syntax for the protected
internal visibility is Protected Friend). Note that a type can
be declared as protected or internal only if it is nested in another type.
Example:
SELECT METHODS WHERE IsProtectedOrInternal
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword IsProtectedAndInternal is used to
define a condition that matches protected internal TYPES,
METHODS or FIELDS.
Note that this visibility is provided by the IL language but is not supported
neither by C# nor VB.NET. Note that a type can be declared as protected
internal only if it is nested in another type.
Example:
SELECT METHODS WHERE IsProtectedAndInternal
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword IsPrivate
is used to define a condition that matches private TYPES,
METHODS or FIELDS.
Example:
SELECT METHODS WHERE IsPrivate
New in CQL version 1.1
Applicable on: NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword IsInFrameworkAssembly is used to
distinguish framework code elements from application code elements.
Example:
SELECT METHODS WHERE IsInFrameworkAssembly
New in CQL version 1.8
Applicable on: ASSEMBLIES
Remarks: The keyword IsFrameworkAssembly
is used to distinguish framework assemblies from application assemblies.
Example:
SELECT ASSEMBLIES WHERE IsFrameworkAssembly
Applicable on: FIELDS
Remarks: The keyword IsEnumValue
is used to define a condition that matches FIELDS
which are values of enumerations.
Example:
SELECT FIELDS WHERE IsEnumValue
Applicable on: METHODS
Remarks: The keyword IsConstructor
is used to define a condition that matches METHODS
which are instance constructors.
Example:
SELECT METHODS WHERE IsConstructor
Applicable on: METHODS
Remarks: The keyword IsPropertySetter
is used to define a condition that matches METHODS
which are property setters.
Example:
SELECT METHODS WHERE IsPropertySetter
Applicable on: METHODS
Remarks: The keyword IsPropertyGetter
is used to define a condition that matches METHODS
which are property getters.
Example:
SELECT METHODS WHERE IsPropertyGetter
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword IsStatic
is used to define a condition that matches static TYPES,
METHODS or FIELDS.
A static type is a class which declares only static members.
Example:
SELECT METHODS WHERE IsStatic
Applicable on: METHODS
Remarks: The keyword IsOverloaded
is used to define a condition that matches METHODS
which are overloaded.
Example:
SELECT METHODS WHERE IsOverloaded
Applicable on: METHODS
Remarks: The keyword IsVirtual
is used to define a condition that matches METHODS
which are virtual or override.
Example:
SELECT METHODS WHERE IsVirtual
Remarks: The keyword IsAbstract
is used to define a condition that matches TYPES
or METHODS which are abstract. Note that
interfaces and interfaces’ methods are considered as abstract.
Example:
SELECT TYPES WHERE IsAbstract AND !IsInterface
New in CQL version 1.1
Applicable on: METHODS
Remarks: The keyword IsExplicitInterfaceImpl is used to
define a condition that matches METHODS which
are explicit interface method implementation.
Example:
SELECT METHODS WHERE IsExplicitInterfaceImpl
Remarks: The keyword IsUsingBoxing
is used to define a condition that matches TYPES
or METHODS which are using the box IL instruction.
Example:
SELECT TYPES WHERE IsUsingBoxing
Remarks: The keyword IsUsingUnboxing
is used to define a condition that matches TYPES
or METHODS which are using the unbox IL instruction.
Example:
SELECT TYPES WHERE IsUsingUnboxing
New in CQL version 1.1
Remarks: The keyword IsUsingPinning
is used to define a condition that matches TYPES
or METHODS which are using pinning.
Example:
SELECT TYPES WHERE IsUsingPinning
Remarks: The keyword IsGeneric
is used to define a condition that matches TYPES
or METHODS which are generic.
Example:
SELECT TYPES WHERE IsGeneric
Remarks: The keyword IsUsingPointers
is used to define a condition that matches TYPES
or METHODS which are using pointers. Note that
in C# pointers can only be used in unsafe mode.
Example:
SELECT TYPES WHERE IsUsingPointers
New in CQL version 1.1
Applicable on: METHODS
Remarks: The keyword IsFinalizer
is used to define a condition that matches METHODS
which are finalizer (i.e that override the Object.Finalize()
method) .
Example:
SELECT METHODS WHERE IsFinalizer
New in CQL version 1.1
Applicable on: TYPES
Remarks: The keyword HasFinalizer
is used to define a condition that matches TYPES
which define a finalizer.
Example:
SELECT TYPES WHERE HasFinalizer
New in CQL version 1.2
Applicable on: TYPES
Remarks: The keyword HasLevel
is used to detect dependencies cycle in the structure of your code. More
details are available in the recommendation section of the Level metric.
Example:
SELECT NAMESPACES WHERE !HasLevel AND !IsInFrameworkAssembly
New in CQL version 1.2
Applicable on: TYPES
Remarks: These keywords allow to know which part of
your code contains dependency cycles. Typically, you’ll want to ensure that
there is no dependency cycle between namespaces of a same assembly but you’ll
accept dependency cycles between types of a same namespace and between methods
of a same type (this is recursion). Dependency cycles between assemblies are
detected at the analysis level and are pinpointed in the NDepend HTML report if
they exist
Example:
SELECT ASSEMBLIES WHERE ContainsNamespaceDependencyCycle
New in CQL version 1.1
Applicable on: METHODS
Remarks: The keyword IsEntryPoint
is used to define a condition that matches METHODS
which are entry point of their assemblies.
Example:
SELECT METHODS WHERE IsEntryPoint
Applicable on: METHODS
Remarks: The keyword IsOperator
is used to define a condition that matches METHODS
which are operator implementations.
Example:
SELECT METHODS WHERE IsOperator
Applicable on: METHODS
Remarks: The keyword IsIndexerSetter
is used to define a condition that matches METHODS
which are indexer setters.
Example:
SELECT METHODS WHERE IsIndexerSetter
Applicable on: METHODS
Remarks: The keyword IsIndexerGetter
is used to define a condition that matches METHODS
which are indexer getters.
Example:
SELECT METHODS WHERE IsIndexerGetter
Applicable on: FIELDS
Remarks: The keyword IsLiteral
is used to define a condition that matches FIELDS
which are literals. Literals fields are C# fields declared with the keyword const, VB.NET fields declared with the
keyword Const and enumeration values.
Example:
SELECT METHODS WHERE IsLiteral AND !IsEnumValue
Applicable on: FIELDS
Remarks: The keyword IsInitOnly
is used to define a condition that matches FIELDS
which are init only. Init only fields are C# fields declared with the keyword readonly and VB.NET fields declared with the keyword Readonly.
Example:
SELECT METHODS WHERE IsInitOnly
Applicable on: METHODS
Remarks: The keyword IsEventAdder
is used to define a condition that matches METHODS
which are event adders.
Example:
SELECT METHODS WHERE IsEventAdder
Applicable on: METHODS
Remarks: The keyword IsEventRemover
is used to define a condition that matches METHODS
which are event removers.
Example:
SELECT METHODS WHERE IsEventRemover
Applicable on: FIELDS
Remarks: The keyword IsEventDelegateObject is used to define a
condition that matches FIELDS which are event
delegate object. C# and VB.NET compilers define for each event an event adder,
an event remover, and a field typed with a delegate.
Example:
SELECT METHODS WHERE IsEventDelegateObject
Applicable on: METHODS
Remarks: The keyword IsClassConstructor
is used to define a condition that matches METHODS
which are class constructors (also sometimes referred as static constructors).
Example:
SELECT METHODS WHERE IsClassConstructor
Applicable on: TYPES
Remarks: The keyword IsClass
is used to define a condition that matches TYPES
which are classes.
Example:
SELECT METHODS WHERE IsEventRemover AND !IsDelegate
Applicable on: TYPES
Remarks: The keyword IsStructure
is used to define a condition that matches TYPES
which are structures.
Example:
SELECT METHODS WHERE IsStructure
Applicable on: TYPES
Remarks: The keyword IsEnumeration
is used to define a condition that matches TYPES
which are enumerations.
Example:
SELECT METHODS WHERE IsEnumeration
Applicable on: TYPES
Remarks: The keyword IsInterface
is used to define a condition that matches TYPES which
are interfaces.
Example:
SELECT METHODS WHERE IsInterface
Applicable on: TYPES
Remarks: The keyword IsSealed
is used to define a condition that matches TYPES
which are sealed. Note that static classes and structures and necessarily
marked as sealed.
Related Link: Rambling
on the sealed keyword
Example:
SELECT METHODS WHERE IsSealed
Applicable on: TYPES
Remarks: The keyword IsNested
is used to define a condition that matches TYPES
which are nested.
Example:
SELECT METHODS WHERE IsNested
Applicable on: TYPES
Remarks: The keyword IsSerializable
is used to define a condition that matches TYPES
which are serializable (with the same definition as the one used by the
framework property System.Type.IsSerializable{get;}).
Example:
SELECT METHODS WHERE IsSerializable
Applicable on: TYPES
Remarks: The keyword IsDelegate
is used to define a condition that matches TYPES
which are delegates. Note that a delegate type is also class.
Example:
SELECT METHODS WHERE IsDelegate
Applicable on: TYPES
Remarks: The keyword IsAttributeClass
is used to define a condition that matches TYPES
which are attribute classes. An attribute class is class which derives directly
or indirectly from the framework class System.Attribute.
Example:
SELECT METHODS WHERE IsAttributeClass
Applicable on: TYPES
Remarks: The keyword IsExceptionClass
is used to define a condition that matches TYPES
which are exception classes. An exception class is class which derives directly
or indirectly from the framework class System.Exception.
Example:
SELECT METHODS WHERE IsAttributeClass
New in CQL version 1.3
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword IsGeneratedByCompiler is used to define
a condition that matches TYPES METHODS and FIELDS
that are generated by the compiler to handle anonymous methods and iterators.
More anonymous methods here. More about iterators here.
Example:
SELECT METHODS WHERE IsGeneratedByCompiler
New in CQL version 1.3
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword IsObsolete
is used to define a condition that matches TYPES METHODS and FIELDS
that are tagged with the System.Obsolete attribute.
Example:
SELECT METHODS WHERE IsObsolete
New in CQL version 1.3
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword IsSpecialName
is used to define a condition that matches TYPES METHODS and FIELDS
that returns true for the SpecialName
property of System.Reflection.MethodBase
System.Reflection.FieldInfo
and System.Type.
Example:
SELECT METHODS WHERE IsSpecialName
Related Link:
Ensure
the quality of the code that will be developed this year
How
to avoid regression bugs while adding new features
New in CQL version 1.3
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword WasAdded
is used to define a condition that matches ASSEMBLIES
NAMESPACES TYPES
METHODS and FIELDS
that were added, i.e that exist in the newer build and not in the older one.
This keyword forces the CQL execution to be done against the newer build and is
then incompatible with keywords WasRemoved IsNotUsedAnymore IsInOlderBuild.
Example:
SELECT METHODS WHERE WasAdded
New in CQL version 1.3
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword WasRemoved
is used to define a condition that matches ASSEMBLIES
NAMESPACES TYPES
METHODS and FIELDS
that were removed, i.e that exist in the newer build and not in the older one.
This keyword forces the CQL execution to be done against the older build and is
then incompatible with keywords WasAdded IsUsedRecently and IsInNewerBuild.
Example:
SELECT METHODS WHERE WasRemoved
New in CQL version 1.3
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: The keyword CodeWasChanged
is used to define a condition that matches ASSEMBLIES
NAMESPACES TYPES
and METHODS where code were changed. An ASSEMBLIES, a NAMESPACES
or a TYPES is deemed as changed when it contains
at least one method where code was changed or if it contains a child that has
been added or deleted.
To know if
the code of a method is changed, we compute 2 hash values, one on the IL
instruction + name of other members called + string operand and the other one
on integer operand. We need the second hash value to avoid setting CodeWasChanged on methods where IL code was
just changed because of the modification of an enumeration type. Indeed, in
this case the values of the enumeration are directly inserted in the body of
the user methods by the compiler.
Example:
SELECT METHODS WHERE CodeWasChanged
New in CQL version 1.3
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS
Remarks: The keyword CommentsWereChanged is used to define a
condition that matches ASSEMBLIES NAMESPACES TYPES
and METHODS that where comments were changed. So
far, the algorithm to detect if comments were changed is just based on line
number and not on hash values meanings that this algorithm might miss some true
positive.
Example:
SELECT METHODS WHERE CommentsWereChanged
New in CQL version 1.3
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword VisibilityWasChanged is used to define a
condition that matches TYPES METHODS and FIELDS
where visibility was changed.
Example:
SELECT METHODS WHERE VisibilityWasChanged
New in CQL version 1.3
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword WasChanged
is used to define a condition that matches ASSEMBLIES
NAMESPACES TYPES
METHODS and FIELDS
that were changed.
·
A
method is deemed as changed if its ReturnType was
changed or its VisibilityWasChanged
or its CodeWasChanged or if its CommentsWereChanged.
·
A
field is deemed as changed if its IsOfTypewas
changed or its VisibilityWasChanged.
·
A
type is deemed as changed if its VisibilityWasChanged
or if its CommentsWereChanged or if it
contains a method or a field that WasChanged
or WasAdded or WasRemoved.
·
A
namespace is deemed as changed if it contains a type that WasChanged.
·
An
assembly is deemed as changed if it contains a namespace that WasChanged.
Example:
SELECT METHODS WHERE WasChanged
New in CQL version 1.3
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword BecameObsolete is used to define a
condition that matches TYPES METHODS and FIELDS
that was not tagged with the System.Obsolete attribute and is now tagged with this
attribute in the newer build.
Example:
SELECT METHODS WHERE BecameObsolete
New in CQL version 1.3
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword IsUsedRecently
is used to define a condition that matches framework ASSEMBLIES or NAMESPACES
TYPES METHODS and FIELDS declared in framework assemblies that were
not used by the older build and that are now used by the newer build. This
keyword forces the CQL execution to be done against the newer build and is then
incompatible with keywords WasRemoved IsNotUsedAnymore IsInOlderBuild.
Example:
SELECT METHODS WHERE IsUsedRecently
New in CQL version 1.3
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword IsNotUsedAnymore
is used to define a condition that matches ASSEMBLIES
or NAMESPACES TYPES
METHODS and FIELDS
declared in framework assemblies that were used by the older build and that are
now not used anymore by the newer build.
This keyword forces the CQL execution to be done against the older build
and is then incompatible with keywords WasAdded
IsUsedRecently and IsInNewerBuild.
Example:
SELECT METHODS WHERE IsNotUsedAnymore
New in CQL version 1.3
Applicable on: ASSEMBLIES NAMESPACES TYPES
Remarks: The keyword IsUsedDifferently
is used to define a condition that matches ASSEMBLIES
or NAMESPACES and TYPES declared in framework assemblies that
contains some code element (i.e NAMESPACES TYPES METHODS or FIELDS) that matches IsNotUsedAnymore or IsUsedRecently.
Example:
SELECT METHODS WHERE IsUsedDifferently
New in CQL version 1.3
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword IsInNewerBuild
is used to forces the CQL execution to be done against the newer build. It is
then incompatible with keywords WasRemoved IsNotUsedAnymore IsInOlderBuild.
Example:
SELECT METHODS WHERE IsInNewerBuild
New in CQL version 1.3
Applicable on: ASSEMBLIES NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword IsInOlderBuild
is used to forces the CQL execution to be done against the older build. It is then incompatible with keywords WasAdded IsUsedRecently
and IsInNewerBuild.
Example:
SELECT METHODS WHERE IsInOlderBuild
Related Link: Optimal
Encapsulation
New in CQL version 1.5
Applicable on: NAMESPACES TYPES METHODS FIELDS
Remarks: The keyword CouldBeInternal
is used to define a condition that matches public TYPES
METHODS and FIELDS
that could be declared as internal in C# (Friend in VB.NET) within the context of the analyzed assemblies. A code
element can be internal if it is not used outside of the assembly it is
declared in.
If you are
analyzing a framework, many of public code elements will be considered as CouldBeInternal because there is no
client code using them. You should then discard irrelevant CouldBeInternal constraints.
CouldBeInternal can also
apply to NAMESPACES although .NET languages
(C#, VB.NET etc) don’t allow visibility modifier on namespaces. A namespace is
considered as CouldBeInternal if it
contains only types that are not used inside the outer assembly and if at least
one of its types is declared as public.
Example:
SELECT METHODS WHERE CouldBeInternal
New in CQL version 1.5
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword CouldBeInternalProtected is used to
define a condition that matches public TYPES METHODS and FIELDS
that could be declared as protected internal in C# (Protected Friend in VB.NET) within the context of
the analyzed assemblies. A code element can be protected internal if it is not used outside of the assembly it is
declared in and if it is not used outside of the classes that derive from the
class it is declared in. You should read protected
internal as protected OR internal.
Notice that
a type declared in the global scope (i.e that is not nested inside a class)
cannot be declared as protected internal.
Example:
SELECT METHODS WHERE CouldBeInternalProtected
New in CQL version 1.5
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword CouldBeProtected
is used to define a condition that matches public or internal TYPES METHODS and FIELDS that could be declared as protected in C# (Protected in VB.NET) within the context of the
analyzed assemblies. A code element can be protected
if it is not used outside of the classes that derive from the class it is
declared in.
Notice that
a type declared in the global scope (i.e that is not nested inside a class)
cannot be declared as protected.
Example:
SELECT METHODS WHERE CouldBeProtected
New in CQL version 1.5
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword CouldBePrivate
is used to define a condition that matches public or internal TYPES METHODS and FIELDS that could be declared as private in C# (Private in VB.NET) within the context of the
analyzed assemblies. A code element can be private
if it is not used outside of the type it is declared in.
Notice that
a type declared in the global scope (i.e that is not nested inside a class)
cannot be declared as private.
Example:
SELECT METHODS WHERE CouldBePrivate
New in CQL version 1.5
Applicable on: TYPES METHODS FIELDS
Remarks: The keyword ShouldBePublic
is used to define a condition that matches internal TYPES
METHODS and FIELDS
that are used outside their declaring assembly thanks to the attribute System.Compilers.Services.InternalsVisibleToAttribute. In
general, having code elements that are considered as ShouldBePublic is not a problem because it is made on purpose.
However, it can be interesting to list them.
Example:
SELECT METHODS WHERE ShouldBePublic
For Type New in CQL
version 1.4
For Field New in CQL
version 1.8
Remarks on Immutable Types: The keyword IsImmutable is used to define a condition that
matches immutable TYPES (classes and structures).
A type is considered as immutable if its instance fields cannot be modified
once an instance has been built by a constructor.
·
A
stateless type (i.e a type without any instance field) is considered as
immutable.
·
A
type with at least one non-private instance field is considered as mutable
(because such a field can be eventually modified outside the type).
·
A
class that derives directly or indirectly from a mutable type is considered as
mutable.
·
Enumeration,
static type, type defined in framework assemblies and delegate classes are
never considered as immutable. Although these types might match the definition
of immutability, considering them as immutable would disturb developers while
they care for their own code immutable types.
·
Particularly,
classes that derive directly or indirectly from a class defined in a framework
assembly that is not the System.Object
class, is never considered as immutable.
·
Using
the C# readonly keyword on your own
instance field is a good way to achieve immutability.
·
Notice
that if a type T has some instance fields that are of reference type, the
object pointed by such a reference might be modified without breaking the
immutability of T.
It is still
possible to break immutability by using the C# keyword ref to allow a tier method to modify the state of an instance
field. As .NET framework designers considered that the immutability of the
class System.String can be broken
using advanced means such as reflection or unsafe code, you should consider
that using the C# keyword ref or
reflection or unsafe code are advanced means to break immutability of your own
types.
Immutable
types are especially useful when you have to deal with multi-threading
application. Indeed, accesses to instances of immutable types don’t need to be
synchronized because such objects can’t be modified; hence all accesses are
read-only accesses.
Remarks on Immutable Fields: The keyword IsImmutable is used to define a condition that
matches immutable FIELDS (both static fields and
instance fields). A static field is considered as immutable if it is private
and if it is only written by the static constructor. An instance field is
considered as immutable if it is private and if it is only written by its
type’s constructor(s) or its type’s static constructor. Literal fields, enum
value fields, fields defined in tier assemblies are never considered as
immutable to avoid noise in your search for immutable fields.
A field
that matches the IsInitOnly condition is always
considered as immutable. In addition, a field that matches the IsImmutable condition can be safely marked as readonly (i.e this will provoke matching
for IsInitOnly condition).
Related Link: Immutable
types: understand their benefits and use them
Example:
SELECT TYPES WHERE IsImmutable
SELECT FIELDS WHERE IsImmutable AND !IsInitOnly
New in CQL version 1.4
Applicable on: METHODS
Remarks: The keyword ChangesObjectState
is used to define a condition that matches METHODS
that explicitly modify an instance field
of their type. Notice that constructors are matched. A static method or a class
constructor can also be matched, for example, if it modifies the state of an
object passed by reference. Notice also that an instance method of a type T
that modifies an instance of T that is not the one referenced by the this reference is also matched. The idea
is that methods that match ChangesObjectState
complexify the program because they break type immutability (see IsImmutable).
Related Link: Immutable
types: understand their benefits and use them
Example:
SELECT METHODS WHERE ChangesObjectState
New in CQL version 1.4
Applicable on: METHODS
Remarks: The keyword ChangesTypeState
is used to define a condition that matches METHODS
that explicitly modify a static field
of their type. Notice that class constructor, constructors, instance methods
and static methods are matched.
Related Link: Immutable
types: understand their benefits and use them
Example:
SELECT METHODS WHERE ChangesObjectState
New in CQL version 1.8
Applicable on: METHODS
Remarks: The keyword ReadsMutableObjectState
is used to define a condition that matches METHODS
that reads at least one mutable instance field. Field mutability is defined in IsImmutable condition definition.
Example:
SELECT METHODS WHERE ReadsMutableObjectState
New in CQL version 1.8
Applicable on: METHODS
Remarks: The keyword ReadsMutableTypeState
is used to define a condition that matches METHODS
that reads at least one mutable static field. Field mutability is defined in IsImmutable condition definition.
Example:
SELECT METHODS WHERE ReadsMutableTypeState
New in CQL version 1.8
Applicable on: METHODS
Remarks: The keyword ReadsImmutableObjectState
is used to define a condition that matches METHODS
that reads at least one immutable instance field. Field mutability is defined
in IsImmutable condition definition.
Example:
SELECT METHODS WHERE ReadsImmutableObjectState
New in CQL version 1.8
Applicable on: METHODS
Remarks: The keyword ReadsImmutableTypeState
is used to define a condition that matches METHODS
that reads at least one immutable static field. Field mutability is defined in IsImmutable condition definition.
Example:
SELECT METHODS WHERE ReadsImmutableTypeState
New in CQL 1.4
Applicable on: METHODS
Remarks: The keyword IsWritingField
is used to select METHODS that write a particular
field “XXX”, i.e that changes the state of the field “XXX”. The keyword IsWritingField matches also methods that
indirectly write the field “XXX”, i.e that calls a method that writes the field
“XXX”.
The column DepthOfIsWritingField “XXX” appears
automatically in the table result. The methods that directly write the field
“XXX” have a DepthOfIsWritingField
“XXX” value equal to
An instance
constructor that initializes an instance field of its type is not matched.
A static
constructor that initializes a static field of its class is not matched.
Examples:
SELECT METHODS WHERE IsWritingField "MyNamespace.MyType.m_Field"
In this
context, you can also use the DepthOfIsWritingField
keyword to order the rows in the result list.
SELECT METHODS WHERE IsWritingField "MyNamespace.MyType.m_Field"
ORDER BY DepthOfIsWritingField DESC
New in CQL 1.4
Applicable on: METHODS
Remarks: See the section IsWritingField M for the definition of the DepthOfIsWritingField metric.
Example:
SELECT METHODS WHERE DepthOfIsWritingField "MyNamespace.MyType.m_Field"
< 3
In this
context, you can also use the DepthOfIsWritingField
keyword to order the rows in the result list.
SELECT METHODS WHERE DepthOfIsWritingField "MyNamespace.MyType.m_Field"
< 3
ORDER BY DepthOfIsWritingField DESC
New in CQL 1.4
Applicable on: METHODS
Remarks: The keyword IsDirectlyWritingField is used to select
METHODS that write a particular field “XXX”, i.e
that changes the state of the field “XXX”. The clause IsDirectlyWritingField “XXX” is
equivalent to the clause DepthOfIsWritingField
“XXX” == 1.
Example:
SELECT METHODS WHERE IsDirectlyWritingField "MyNamespace.MyType.m_Field"
New boolean conditions:
New metric conditions:
New code structure conditions :
Conditions enhanced:
Conditions deprecated:
IsUsing ANTM must be used instead of IsCalling M
DepthOfIsUsing ANTM must be used
instead of DepthOfIsCalling M
IsUsedBy ANTMF must be used instead of IsCalledBy M
DepthOfIsUsedBy ANTMF must be used
instead of DepthOfIsCalledBy M
To remain compatible IsCalling M,
DepthOfIsCalling M, IsCalledBy M and DepthOfIsCalledBy M are still supported in NDepend 2.0
New metric conditions:
New boolean conditions:
HasLevel ANTM
ContainsNamespaceDependencyCycles
A
ContainsTypeDependencyCycles N
ContainsMethodDependencyCycles T
Wildcard support for namespace names for example:
SELECT TYPES WHERE IsDirectlyUsing "System.Collections.*"
SELECT METHODS FROM
NAMESPACES "System.Collections.*" ORDER BY NbILInstructions DESC
New boolean conditions:
New boolean conditions dedicated to build comparison:
New code
structure condition:
New boolean conditions:
New
code structure conditions :
New feature:
New boolean conditions:
New metric conditions:
New code structure
conditions :
New metric conditions:
New boolean conditions:
New boolean conditions:
New metric conditions:
New
facility:
The Optional: Code Elements’ Name Prefix