Code
Query Language 1.8 Specification
CQL
1.8
CQL
1.8 is supported by CppDepend
Copyright
SMACCHIA.COM S.A.R.L 2006/2007/2008
All
right reserved
The CQL language and real-world
needs
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)
ContainsNamespaceDependencyCycles A
ContainsTypeDependencyCycles T
ContainsMethodDependencyCycles M
CQL boolean conditions dedicated to
Build Comparison
CQL boolean conditions dedicated to
Purity / Side-Effects / Mutability
CQL is a
language which allows writing queries on the code structure of any.NET and C++
application.
For example, the following CQL query returns
all the methods of your application with more than 200 lines, ordered from the
biggest to the smallest:
SELECT METHODS WHERE NbLinesOfCode > 200 ORDER BY NbLinesOfCode DESC
You might
wish to avoid methods with more than 200 lines 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 VisualCppDepend
allows the editing and execution of CQL queries and constraints. A GUI allows
you to have a unique understanding of your application. VisualCppDepend
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 projects, 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 >
CppDepend
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.
WARN IF Count >
// METHODS WHERE NbLinesOfCode > 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 >
WARN IF Count >
// As classes inside an project 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 >
!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]"
// 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 >
// 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 project.
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.