· CQL is a SQL-like language (SELECT..FROM..WHERE) for static analysis of .NET code.
· It is a nice complement to code contracts, & is usable in unit tests. If you've ever looked at creating custom FxCop rules using the archaic and undocumented Introspection API (see
http://www.binarycoder.net/fxcop/html/index.html ), then you will appreciate the elegant CQL syntax for static analysis!
How It Works
· Lets dive into a contrived example - a CQL query that returns the top 10 methods of your application with more than 200 IL instructions:
SELECTTOP 10 METHODS
WHERENbILInstructions > 200
ORDERBYNbILInstructionsDESC
WARNIFCount > 0IN
SELECTMETHODS
WHERENbILInstructions > 200
· CQL supports many metric clauses that can be leveraged as constraints in WHERE & ORDERBY statements, using logical operators such as AND, OR
· The types of elements which a SELECTclause can refer to include: METHODS/ FIELDS/ TYPES/ NAMESPACESand ASSEMBLIES
· The resultset can be filtered to retrieve matching elements using the NameLike / NameIs , FullNameLike or FullNameIs clauses (e.g. WHERENameLike"XXX") . There is an additional FROM / OUTOFclause that can refine a query against specific assemblies, namespaces or types:
SELECTMETHODS
OUTOFNAMESPACES"MyNS1","MyNS2" , "System.Xml"
WHERENbILInstructions > 200
ORFullNameLike"Control..ctor(String)"
· NDepend stores CQL queries and constraints in the project file - to store CQL queries and constraints directly in source code, must reference the assembly ./Lib/NDepend.CQL.dll and use the attribute NDepend.CQL.CQLConstraintAttribute:
using System.Collections.Generic;
using NDepend.CQL;
…
[CQLConstraint(
@"WARN IF Count != 1 IN SELECT TYPES WHERE FullNameIs ""Test.C1<I,J>""")]
class C1<I, J> :
IGenericInterface<I, J>, INonGenericInterface, IInterfaceInAnonymousNamespace
{
[CQLConstraint(
@"WARN IF Count != 1 IN
SELECT METHODS
WHERE FullNameIs ""Test.C1<I,J>.IInterfaceInAnonymousNamespace.NonGenericMethod(Int16)""")]
int IInterfaceInAnonymousNamespace.NonGenericMethod(short i)
{
return i;
}
· The OPTIONAL: prefix indicate to the CQL compiler that if the code element is not found, an error should not be emitted;
WARN IF Count> 0IN
SELECTMETHODS
WHEREIsDirectlyUsing"OPTIONAL:System.Threading.Thread.Sleep(Int32)"
· The OPTIONAL: prefix must always appear before an ASSEMBLY: NAMESPACE: TYPE: METHOD: or FIELD prefix.
· The following tables detail the relevant metrics. Applicability is abbreviated as follows:
o A - ASSEMBLIES
o N - NAMESPACES
o T - TYPES
o M - METHODS
o F - FIELDS
CQL metric conditions
|
Metric
|
Applicability
|
Return / Match
|
Code Smell
|
|
NbLinesOfCode
|
ANTM
|
#Lines of code
|
|
|
NbILInstructions
|
ANTM
|
#Lines of IL instructions
|
|
|
NbLinesOfComment
|
ANTM
|
#Lines of comments
|
|
|
PercentageComment
|
ANTM
|
%code that is comments
|
<20 OR > 40
|
|
NbMethods
|
ANT
|
#methods
|
TYPES WHERE NbMethods > 20
|
|
NbFields
|
ANT
|
#fields
|
TYPES WHERE NbFields > 20
|
|
NbTypes
|
AN
|
#Types
|
|
|
NbNamespaces
|
A
|
#Namespaces
|
|
|
NbInterfacesImplemented
|
T
|
# interfaces implemented by a type
|
|
|
NbParameters
|
M
|
#Parameters
|
METHODS WHERE NbParameters > 5
|
|
NbVariables
|
M
|
#Variables
|
METHODS WHERE NbVariables > 8
|
|
NbOverloads
|
M
|
#overloads
* Helps reduce # ctors
|
METHODS WHERE NbOverloads > 6
|
|
CyclomaticComplexity
|
TM
|
#decisions that can be taken in a procedure
|
METHODS WHERE CC > 15
|
|
ILCyclomaticComplexity
|
TM
|
# jump/branch IL instructions
|
METHODS WHERE ILCC > 20
|
|
ILNestingDepth
|
M
|
max # encapsulated scopes inside a method body
|
METHODS WHERE ILND > 4
|
|
SizeOfInst
|
TF
|
Byte size of instances of a type
|
TYPES WHERE SizeOfInst > 64 - consider FlyWeight pattern
|
|
TypeRank
|
T
|
homothety of center – via PageRank à importance of type
|
|
|
MethodRank
|
M
|
"
|
|
|
DepthOfInheritance
|
T
|
# base classes
|
TYPES WHERE DOI > 6
|
|
NbChildren
|
T
|
# derived classes
|
|
|
FieldCa
|
F
|
Afferent Coupling - # methods that directly use the field
|
|
|
MethodCe
|
M
|
Efferent Coupling - #methods the method directly depends on
|
|
|
MethodCa
|
M
|
Afferent Coupling - # methods that directly use the method
|
|
|
TypeCe
|
T
|
Efferent Coupling - #types the type directly depends on
|
|
|
TypeCa
|
T
|
Afferent Coupling - # types that directly use the type
|
|
|
NamespaceCe
|
N
|
Efferent Coupling - #namespaces the namespace directly depends on
|
|
|
NamespaceCa
|
N
|
Afferent Coupling - # namespaces that directly use the namespace
|
|
|
ABT
|
T
|
Association Between Types - # members of others types it directly uses in the bodies of its methods
|
|
|
LCOM
|
T
|
Lack of cohesion of methods
|
TYPES WHERE LCOM > 0.8 AND NbFields > 10 AND NbMethods >10
|
|
LCOMHS
|
T
|
Lack Of Cohesion Of Methods
(Henderson-Sellers)
|
TYPES WHERE LCOMHS > 1.0 AND NbFields > 10 AND NbMethods >10
|
|
AssemblyLevel A / NamespaceLevel N / TypeLevel T / MethodLevel T
|
T
|
# of non BCL namespaces used
à discover dependency cycles
|
|
|
Abstractness
|
A
|
Ratio of abstract to concrete types
|
|
|
Instability
|
A
|
ratio of efferent coupling (AsmCe) to total coupling
|
|
|
NormDistFromMainSeq
|
A
|
High level indicator of assembly's balance between abstractness and stability
|
ASSEMBLIES WHERE NormDistFromMainSeq > 0.7
|
|
DistFromMainSeq
|
A
|
NormDistFromMainSeq / Sqrt(2)
|
|
|
RelationalCohesion
|
A
|
# internal relationships per type.
classes inside an assembly should be strongly related
|
ASSEMBLIES WHERE RelationalCohesion < 1.5 OR RelationalCohesion > 4.0
|
|
AsmCa
|
A
|
# types outside an assembly that depend on types within it
|
|
|
AsmCe
|
A
|
# types inside an assembly that depend on types outside it
|
|
CQL test coverage metrics conditions
|
Metric
|
Applicability
|
Return / Match
|
|
PercentageCoverage
|
ANTM
|
% of code coverage by tests
The closer to 100%, the better
|
|
NbLinesOfCodeCovered
|
ANTM
|
# lines of code covered
|
|
NbLinesOfCodeNotCovered
|
ANTM
|
# lines of code not covered
|
|
PercentageBranchCoverage
|
M
|
generated from underlying opcodes - compensates for method complexity.
determine which code statements need more testing.
|
|
IsExcludedFromCoverage
|
ANTM
|
|
|
Metric
|
Applicability
|
Return / Match
|
|
IsUsing
DepthOfIsUsing
|
ANTM
|
Code elements that directly / indirectly use a particular code element “XXX”
|
|
IsDirectlyUsing
|
ANTM
|
Code elements that directly use a particular code element “XXX”
|
|
IsUsedBy
DepthOfIsUsedBy
|
ANTMF
|
Code elements that are directly / indirectly used-by a particular code element “XXX”
|
|
IsDirectlyUsedBy
|
ANTMF
|
Code elements that are directly used by a particular code element “XXX”
|
|
CreateA
DepthOfCreateA
|
M
|
METHODS which directly / indirectly call a constructor of a particular type “XXX”
|
|
DeriveFrom
DepthOfDeriveFrom
|
T
|
TYPES which directly / indirectly derive from a particular type “XXX”
|
|
Implement
|
T
|
TYPES which implement a particular interface “XXX”
|
|
HasAttribute
|
ATMF
|
Code elements that are tagged with a particular attribute “XXX”
|
|
IsOfType
|
F
|
FIELDS of a particular type “XXX”
|
|
ReturnType
|
M
|
METHODS that return a particular type “XXX”
|
CQL boolean conditions
|
Metric
|
Applicability
|
Return / Match
|
|
IsPublic
IsInternal
IsProtected
IsProtectedAndInternal
IsPrivate
|
TMF
|
Elements that match the scope
|
|
IsInFrameworkAssembly
IsFrameworkAssembly
|
NMTF
A
|
distinguish framework code elements from application code elements.
|
|
|
F
|
FIELDS which are values of enumerations.
|
|
|
M
|
METHODS which are instance constructors
|
|
|
M
|
|
|
|
M
|
|
|
|
TMF
|
|
|
|
M
|
|
|
|
M
|
METHODS which are virtual or override
|
|
|
TM
|
TYPES or METHODS which are abstract. Note that interfaces and interfaces’ methods are considered as abstract
|
|
|
M
|
METHODS which are explicit interface method implementation
|
|
|
TM
|
|
|
|
TM
|
|
|
|
TM
|
|
|
|
TM
|
|
|
|
TM
|
TYPES or METHODS which are using pointers. ( in unsafe mode).
|
|
|
M
|
METHODS which override Object.Finalize()
|
|
|
T
|
TYPES which define a finalizer
|
|
|
ANTM
|
detect dependencies cycle in the code structure
|
|
ContainsTypeDependencyCycle
ContainsMethodDependencyCycle
|
A
T
M
|
determine which part of code contains dependency cycles
|
|
IsEntryPoint
|
M
|
METHODS which are entry point of their assemblies
|
|
|
M
|
METHODS which are operator implementations
|
|
|
M
|
|
|
|
M
|
|
|
|
F
|
FIELDS which are literals - Const and enum values
|
|
|
F
|
|
|
|
M
|
|
|
|
M
|
|
|
|
F
|
FIELDS which are event delegate object
|
|
IsClassConstructor
|
M
|
METHODS which are class constructors
|
|
|
T
|
|
|
|
T
|
TYPES which are structures
|
|
|
T
|
|
|
|
T
|
TYPES which are interfaces
|
|
|
T
|
matches TYPES which are sealed. Note static classes and structures are marked as sealed
|
|
|
T
|
|
|
|
T
|
TYPES which are serializable
|
|
|
T
|
TYPES which are delegates
|
|
|
T
|
TYPES which are attribute classes (derived from System.Attribute)
|
|
|
T
|
TYPES which are exception classes (derive from System.Exception )
|
|
|
TMF
|
Code elements that are generated by the compiler to handle anonymous methods and iterators
|
|
IsObsolete
|
TMF
|
|
|
|
TMF
|
Code elements that returns true for Type / FieldInfo SpecialName property
|
CQL boolean conditions dedicated to Build Comparison
|
Metric
|
Applicability
|
|
WasAdded
|
ANTMF
|
|
|
ANTMF
|
|
|
ANTM
|
|
CommentsWereChanged
|
ANTM
|
|
VisibilityWasChanged
|
TMF
|
|
|
ANTMF
|
|
BecameObsolete
|
TMF
|
|
IsUsedRecently
|
ANTMF
|
|
IsNotUsedAnymore
|
ANTMF
|
|
IsUsedDifferently
|
ANT
|
|
IsInNewerBuild
|
ANTMF
|
|
IsInOlderBuild
|
ANTMF
|
|
Metric
|
Applicability
|
Return / Match
|
|
CouldBeInternal
|
NTMF
|
|
|
|
TMF
|
|
|
|
TMF
|
|
|
|
TMF
|
|
|
|
TMF
|
internal TYPESMETHODS and FIELDS that are used outside their declaring assembly via InternalsVisibleToAttribute
|
|
Metric
|
Applicability
|
Return / Match
|
|
|
TF
|
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.
|
|
|
M
|
METHODS that explicitly modify an instance field of their type.
|
|
|
M
|
METHODS that explicitly modify a static field of their type.
|
|
|
M
|
METHODS that reads at least one mutable instance field.
|
|
|
M
|
METHODS that reads at least one mutable static field.
|
|
|
M
|
METHODS that reads at least one immutable instance field.
|
|
|
M
|
METHODS that reads at least one immutable static field
|
|
|
M
|
METHODS that write a particular field “XXX”, i.e that changes the state of the field “XXX”.
|
|
|
M
|
A method that directly calls a method that directly write the field “XXX” has a DepthOfIsWritingField “XXX” value equal to 1. etc…
|
|
|
M
|
|
cheers,
Josh