Code bases may be very large and contain a great deal of diversity even within a single project. For instance, part of your code might be legacy code that cannot yet conform to modern code guidelines because the legacy compiler does not yet support these constructs.
To that end, TICS has introduced the concept of a dynamic ruleset. When a dynamic ruleset is used, TICS selects the appropriate ruleset to use from a set of subrulesets. For instance, a common use case for dynamic rulesets is that a ruleset split is made between C++ code that is compiled with a C++11 compatible compiler, and C++ code that isn't.
At its most basic, the configuration of a dynamic ruleset is done by creating
a DYNAMICRULESET: 1
property in the base ruleset (see
this page) and
creating a rules.json file.
This file will require the following contents
(with various examples further down in the page):
SELECTION
property) which define by which source file properties TICS makes the
decision which subruleset to use.SCOPE
parameter showing whether the dynamic ruleset
should be chosen once for the entire project, or should be decided for each
file individually.SELECTION
property
There are several possibilities for a SELECTION
property. Note
that you can also specify multiple selection parameters. In that case,
if TICS cannot resolve the decision on the first selection parameter, it will
use the next parameter(s) until a conclusive decision can be made.
COMPILERVERSION
: A ruleset is picked based on the
compiler version used for a source file.PYTHONVERSION
: A ruleset is picked based on the Python
version that is used by the project (either Python 2 or 3).RULESETTARGET
: A ruleset is picked based on the target
used to compile a source file. Note that a source file may be analyzed
for multiple targets; in that case, TICS will use the ruleset of the
first matching target.SCOPE
: A ruleset is picked based on the location on disk
of a source file.SCOPE
property
It is possible to set the SCOPE
property. Currently, this has only
one possibility: SCOPE: PROJECT
. This signifies that for the entire
project, a dynamic ruleset should only be selected once, on the basis of
the first file passed to TICS. If the parameter is not set, then TICS will
select this for each file individually.
SCOPE
parameter needs to be set to
PROJECT
in the case you are using a dynamic ruleset to analyze
Abstract Interpretation or Security. This is because for these metrics, analysis
is typically done on project level for an entire language. Therefore, the
analysis done and the violations reported should be for the same ruleset from
this project.
RULESETS
property
Each rules.json should contain at least two rulesets in the RULESETS
property. These are the subrulesets of the dynamic ruleset. Of these
subrulesets, the following properties are always mandatory, regardless of which
selection parameter is used:
NAME
: The name of your subruleset. This will also be shown in
the TICS viewer as the ruleset you used to analyze the file.DIR
: The directory (relative to the rules.json file)
containing your RULES.txt
and IMPL.txt
. For more
information on the contents of RULES and IMPL: see
RULES/IMPL.txt.
Furthermore, each ruleset can also have optional properties for configuring
location and rules for a coding standard viewer. Like at the ruleset level in
SERVER.yaml/PROJECTS.yaml
, this is done with the
DOCNAME
, DOCSUF
, SEP
and ANCHOR
properties. An explanation of these properties is given
earlier in this document.
In the case a dynamic ruleset is made to select on compiler versions, then
TICS will go through all the rulesets from top to bottom. If a
REQUIREDVERSION
property is present for the compiler used and the
version of the compiler is equal to or higher than the
REQUIREDVERSION
, it will use that ruleset. Since different compilers
might be used, it is also necessary to specify the version for individual compilers.
So in the end, the contents end up looking as follows:
"REQUIREDVERSION": { "Gcc": "4.9", "VC": "10" }
One of the most common cases is splitting up the C++ ruleset by Pre-11 and Post-11 dependent on whether the compilers used support C++11 or not. Let's give the rules.json for this setup in its entirety, and explain what all of these properties do.
{ "SELECTION": ["COMPILERVERSION"], "RULESETS": [ { "IMPLDIR": "cpptest_pre11", "NAME": "Cpp Pre-11 Coding Standard", "DIR": "CPP-PRE11", "DOCNAME": "https://csviewer.tiobe.com/api/redirect?setid=36545283-5fc1-485c-ab92-08635db7b7d9&" }, { "IMPLDIR" : "cpptest", "NAME": "Cpp Post-11 Coding Standard", "DIR": "CPP-POST11", "DOCNAME": "https://csviewer.tiobe.com/api/redirect?setid=778E38D6-1B0D-4A7C-AF05-02E9456740A3&", "REQUIREDVERSION": { "Gcc": "4.9", "VC": "10" } } ] }
"SELECTION": ["COMPILERVERSION"]
property means that a
decision will be made based on the compiler version.REQUIREDVERSION
property that defines the
minimum version that a compiler must be to make use of this ruleset.
So, if a C++ file is passed to TICS, and it is analyzed with Gcc 4.8, it will now pick the Pre-11 Coding Standard ruleset. If it has been analyzed with Gcc 4.9, it will pick the Post-11 Coding Standard ruleset.
Each subruleset should be marked with a REQUIREDVERSION
property
for PYTHON
. TICS will then detect which Python version is used
for running the Python tools (eg. pylint), and use the correct subruleset
dependent on the Python version that has been found.
There is no default choice of subruleset as Python should always be available if a Python checker is used.
{ "SELECTION": ["PYTHONVERSION"], "SCOPE": "PROJECT", "RULESETS": [ { "IMPLDIR": "", "NAME": "Python3 Coding Standard", "DIR": "PYTHON3", "REQUIREDVERSION": { "PYTHON": "3", } }, { "IMPLDIR" : "", "NAME": "Python2 Coding Standard", "DIR": "PYTHON2", "REQUIREDVERSION": { "PYTHON": "2", } } ] }
In the case your code is often compiled for different targets and the
compiler settings used depend heavily on these targets, another logical split to
make in your ruleset is to split analysis by target. This is done by
specifying a list of targets in RULESETTARGET
for which a
subruleset is applicable. If a target is used for a file, then TICS will pick
that subruleset.
"RULESETS": [ ... { ... "RULESETTARGET": ["x86", "x86_linux"], } ]
One ruleset is allowed to not have any targets; this is then the default choice. If no targets match on the other rulesets then this will be the ruleset used.
{ "SELECTION": ["RULESETTARGET"], "RULESETS": [ { "IMPLDIR": "cpptest_pre11", "NAME": "Cpp Pre-11 Coding Standard", "DIR": "CPP-PRE11", "DOCNAME": "https://csviewer.tiobe.com/api/redirect?setid=36545283-5fc1-485c-ab92-08635db7b7d9&" }, { "IMPLDIR" : "cpptest", "NAME": "Cpp Post-11 Coding Standard", "DIR": "CPP-POST11", "DOCNAME": "https://csviewer.tiobe.com/api/redirect?setid=778E38D6-1B0D-4A7C-AF05-02E9456740A3&", "RULESETTARGET: ["x86", "x86_linux"], } ] }
"SELECTION": ["RULESETTARGET"]
property means that a
decision will be made based on the target.x86
and x86_linux
targets specified. If any one of these targets is used, TICS will use the
second ruleset to analyze this file.Sometimes, the code archive is neatly separated by compatibility, because one part of the archive has been migrated to a newer version while the other part hasn't had this migration yet. In that case a subruleset can be picked dependent on scope.
To mark a certain scope of the archive to use a subruleset, use the
SCOPEPARAMS
property. This contains two subproperties:
SCOPE
is mandatory and is a regular expression which matches the
scope of the subruleset, while PROJECTS
is optional and specifies
for which projects this scope is valid. To give an example of a subruleset:
{ "IMPLDIR" : "cpptest", "NAME": "Cpp Post-11 Coding Standard", "DIR": "CPP-POST11", "DOCNAME": "https://csviewer.tiobe.com/api/redirect?setid=778E38D6-1B0D-4A7C-AF05-02E9456740A3&", "SCOPEPARAMS": { "SCOPE": "unit_already_migrated" } }
One ruleset is allowed to not have any scope; this is then the default choice. If no scopes match on the other rulesets then this will be the ruleset used.
{ "SELECTION": ["SCOPE"], "RULESETS": [ { "IMPLDIR": "cpptest_pre11", "NAME": "Cpp Pre-11 Coding Standard", "DIR": "CPP-PRE11", "DOCNAME": "https://csviewer.tiobe.com/api/redirect?setid=36545283-5fc1-485c-ab92-08635db7b7d9&" }, { "IMPLDIR" : "cpptest", "NAME": "Cpp Post-11 Coding Standard", "DIR": "CPP-POST11", "DOCNAME": "https://csviewer.tiobe.com/api/redirect?setid=778E38D6-1B0D-4A7C-AF05-02E9456740A3&", "SCOPEPARAMS": { "SCOPE": "unit_already_migrated" } } ] }
"SELECTION": ["SCOPE"]
property means that a
decision will be made based on the scope.x86
and x86_linux
targets specified. If any one of these targets is used, TICS will use the
second ruleset to analyze this file.