2. Using GNATcheck
2.1. General GNATcheck Switches
The following switches control the general gnatcheck
behavior
--version
Display Copyright and version, then exit disregarding all other options.
--help
Display usage, then exit disregarding all other options.
-P file
Indicates the name of the project file that describes the set of sources to be processed. The exact set of argument sources depends on other options specified, see below.
-U
If a project file is specified and no argument source is provided, process all units of the closure of the argument project. If explicit argument sources are specified directly through the command-line alongside the
-U
flag, they will be considered as closure roots for source fetching and not as explicit source files. If explicit argument sources are passed through -files, this option has no effect.--no-subprojects
If a project file is specified and no argument source is explicitly specified (either directly or by means of
-files
option), process all the units of the root argument project. Otherwise this option has no effect.-Xname=value
Indicates that external variable name in the argument project has the value value. Has no effect if no project is specified as tool argument.
--subdirs=dir
Use the specified subdirectory of the project objects file (or of the project file directory if the project does not specify an object directory) for tool output files. Has no effect if no project is specified as tool argument.
--no_objects_dir
Put gnatcheck output files in the current directory instead of using the project file’s object directory.
-eL
Follow all symbolic links when processing project files. By default, symbolic links are not resolved and kept as is. In some cases, resolving the target of symbolic links is needed for proper loading of project files.
--ignore-project-switches
Ignore gnatcheck switches specified in the package
Check
of the main project file.--target=targetname
Specify a target for cross platforms, this is needed to locate the proper runtime library.
--RTS=rts-path
Specifies the default location of the runtime library.
-h
List all the rules checked by the given
gnatcheck
version.-j
nnnnUse nnnn processes to analyze the source files. On a multi-core machine, this speeds up processing by analyzing subset of files separately under multiple processes running in parallel. If
n
is 0, then the maximum number processes is the number of core processors detected on the platform.Attention
Please read the Performance and Memory Usage section before using this flag.
-l
Use full source locations references in the report file.
-log
Duplicate all the output sent to
stderr
into a log file. The log file is namedgnatcheck.log
. If a project file is specified asgnatcheck
parameter then it is located in the project objects directory (or in the project file directory if no object directory is specified). Otherwise it is located in the current directory.-m
nnnnMaximum number of diagnostics to be sent to
stdout
, where nnnn is in the range 0…1000; the default value is 0, which means that there is no limitation on the number of diagnostic messages to be output.-q
Quiet mode. All the diagnostics about rule violations are placed in the
gnatcheck
report file only, without duplication onstdout
.-s
Short format of the report file (no version information, no list of applied rules, no list of checked sources is included)
-xml
Generate the report file in XML format.
-nt
Do not generate the report file in text format. Enforces
-xml
.-files=filename
Take the argument source files from the specified file. This file should be an ordinary text file containing file names separated by spaces or line breaks. This switch can be specified only once, but can be combined with an explicit list of files. If you want to specify a source file with spaces, you need to surround it with double quotes (
"
). If a line in the file starts with--
then the whole line is ignored (considered as a comment).--ignore=filename
Do not process the sources listed in a specified file, using the same syntax as for the
-files
switch.--rule-file=filename
Load the given file as an LKQL rule options file (see LKQL Rule Files for more information). If not absolute, the provided path is relative to the current working directory.
-r, --rule [rule_name]
Enable the given
rule_name
for the current GNATcheck run; you can pass this option multiple times to enable more that one rule. Note that you can enable all rules by passing “all” asrule_name
. You cannot provide parameters to a rule through this command-line option, to do so, please use an LKQL Rule Files.--show-rule
Add the corresponding rule name to the diagnosis generated for its violation. If the rule has a user-defined synonym, both gnatcheck and user-defined rule names are used as rule annotation:
[user_synonym|gnatcheck_rule_name]
.--show-instantiation-chain
For reported generic instantiation constructs, display a chain of source location going from the generic unit to the instantiation.
--brief
Brief mode, report detections to Stderr. This switch also implies
-q
in terms of verbosity, and-s
.--check-redefinition
For a parametrized rule check if a rule parameter is defined more than once in the set of rule options specified and issue a warning if parameter redefinition is detected
--check-semantic
Check semantic validity of the source files by running gprbuild with the
-gnatc
switch, and report any legality error as part of the GNATcheck messages. By default, GNATcheck does not check that sources are semantically valid and will perform a best effort when encountering invalid source files. If you want to ensure and detect that your source files are valid as part of running GNATcheck, you should use this switch.--charset=charset
Specify the charset of the source files. By default,
ISO-8859-1
is used if no charset is specified.--lkql-path=dir
Specify directory to add to the
LKQL_PATH
environment variable when GNATcheck is spawning the LKQL engine. You can specify this option multiple times to add multiple directories.--rules-dir=dir
Specify an alternate directory containing rule files. You can specify this switch multiple times. Each of the directories specified will be scanned and all files with the extension
.lkql
will be loaded byGNATcheck
to provide additional rules.--include-file=file
Append the content of the specified text file to the report file
--emit-lkql-rule-file
Emit a file named
rules.lkql
containing the rule configuration of the current GNATcheck run. This file is emitted besides the given project file if there is one, otherwise, it is generated in the current directory. Be careful, if arules.lkql
file already exists, there will be an error.-t
Print out execution time.
-v
Verbose mode;
gnatcheck
generates version information and then a trace of sources being processed.-W, --warnings-as-errors
Treat warnings raised by GNATcheck as errors, ensuring an erroneous return code.
-o report_file
Set name of the text report file to report_file.
-ox report_file
Set name of the XML report file to report_file. Enforces
-xml
.-rules rules_options
Provide rule options for the current GNATcheck run through the command-line. All switches and options provided after this flag will be parse as rule options.
Attention
This CLI section is deprecated, consider converting your rule configuration to the new LKQL rule file format using the
--emit-lkql-rule-file
switch.
If a project file is specified and no argument source is explicitly
specified (either directly or by means of -files
option), and no
-U
or --no-subprojects
is specified, then the set of processed
sources is determined in the following way.
If root project file has attribute Main
declared and all specified
mains are Ada sources, then combined closure of those mains is processed.
if root project does not have attribute Main
declared, or at least
one of the mains is not an Ada source, then all sources of non-externally
built projects in the project hierarchy are processed.
If the argument project file is an aggregate project, and it aggregates more than one (non-aggregate) project, gnatcheck runs separately for each (non-aggregate) project being aggregated by the argument project, and a separate report file is created for each of these runs. Also such a run creates an umbrella report file that lists all the (non-aggregate) projects that are processed separately and for each of these projects contains the reference for the corresponding report file.
If the argument project file defines an aggregate project that aggregates only one (non-aggregate) project, the gnatcheck behavior is the same as for the case of non-aggregate argument project file.
2.2. The Check GPR Package
In addition to the command-line options, you can use attributes offered by the
Check
package to configure a GNATcheck run. In order to do this you may add
the Check
package in the GPR file you’re providing to GNATcheck through the
-P
command line options, example given:
project My_Project is
package Check is
...
end Check;
end My_Project;
Inside this package you can define the following attributes to configure GNATcheck:
Rules
Value is a list of rules to enable when invoking
gnatcheck
on this project. Values provided in this attribute behave as the ones provided with the--rule
switch.If the
--rule
switch is set when callinggnatcheck
on a project file defining this attribute, then, values are concatenated.Rule_File
Value is a path to a LKQL rule file. If not absolute, the path is relative to the project file that defines this attribute. See LKQL Rule Files for more information.
If the
--rule-file
switch is set when callinggnatcheck
on a project file defining this attribute, then, an error is emitted andgnatcheck
will exit with an error code.Lkql_Path
Value is a list of directories to add to the
LKQL_PATH
environment variable when GNATcheck is spawning the LKQL engine. This variable is used to resolve module importations in LKQL sources. If not absolute, paths provided through this attribute are relatives to the project file defining it.This attributes may work combined with the
--lkql-path
switch, in that case, all directories are added to theLKQL_PATH
environment variable.Switches
Index is a language name. Value is a list of additional switches to be used when invoking
gnatcheck
.If a switch is provided in both command-line and
Switches
attribute, then, the value provided through the command-line is used.Attention
There are several command-line switches that you cannot pass through the
Switches
attribute:--version
--help
-P
-U
-Xname=value
-eL
-r, --rule [rule_name]
(useRules
attribute instead)--rule-file=filename
(useRule_File
attribute instead)--lkql-path=dir
(useLkql_Path
attributes instead)--target
(use theTarget
GPR attribute instead)--RTS
(use theRuntime
GPR attribute instead)
If you’re providing one of those switches through the
Switches
or theDefault_Switches
attribute, GNATcheck will emit an error message and exit with an error code.Default_Switches
Same as
Switches
, but provided additional switches will apply only if there is no applicableSwitches
attribute.
2.3. Sources pre-processing
GNATcheck is handling Ada sources pre-processing, meaning that sources lines that are “excluded” by the Ada pre-processor are also ignored during the GNATcheck analysis. For example, given the following source:
procedure Main is
begin
# if Foo = "Bar" then
goto lbl;
# else
null;
# end if;
end Main;
Running GNATcheck with the Goto_Statements
rule enabled on this Ada code
will flag the goto lbl;
if, and only if, the preprocessor symbol Foo
is set to "Bar"
.
To configure pre-processing, you can use the following GPR attributes:
Builder.Global_Compilation_Switches
Builder.Default_Switches
Builder.Switches
Compiler.Default_Switches
Compiler.Switches
Attention
There is a limitation to the GNATcheck’s pre-processing handling regarding
conditioned with
clauses. Meaning that no matter how symbols are defined,
all with
clauses are going to be analyzed and used by GNATcheck to
resolve the closure of files to analyze.
2.4. LKQL Rule Files
You can configure GNATcheck rules using an LKQL file, provided through the
--rule-file
command-line option or implicitly fetched by GNATcheck (as
described in the following paragraph).
By default, GNATcheck will look for a rules.lkql
file besides the specified
project file if any. If one is found and no other rule configuration has been
provided (either through the LKQL –rule-file option, or by the now deprecated
legacy -rules options), GNATcheck will load the rule configuration file as if
it was provided by the –rule-file option.
Note
You can use the --emit-lkql-rule-file
CLI switch to generate an LKQL rule
file from a legacy rule configuration provided by the -rules
section.
An LKQL rule file can be any valid LKQL file, the only requirement is that it
must export a rules
top-level symbol. This symbol defines an object value
containing rules configuration; keys are GNATcheck rules to enable; and values
are list of objects, each one representing an instance of the rule with its
parameters. A rule parameter value can be of the boolean, the integer, the
string, or the list of strings type, as shown in the simple example below:
val rules = @{
Goto_Statements,
Forbidden_Attributes: {Forbidden: ["GNAT"], Allowed: ["First", "Last"]}
}
Using the “@” object notation is strongly advised to make your configuration file way more understandable:
Please read the Predefined Rules documentation to view examples on how to provide parameters to rules through LKQL rule files.
Attention
You cannot provide the same key twice; thus, the following code will result in a GNATcheck error.
val rules = @{
Forbidden_Attributes,
Forbidden_Attributes: {Forbidden: ["GNAT"], Allowed: ["First", "Last"]}
}
If you want to create multiple instances of the same rule, you can associate
a list value to the rule name in the rule configuration object. Elements of
this list must be parameter objects containing an additional
instance_name
parameter defining the name of the instance described by
the enclosing object. If none is provided, the instance is named after the
rule it is instantiated from, as shown in the following example:
val rules = @{
Goto_Statements,
Forbidden_Attributes: [
# "Forbidden_Attributes" instance of the "Forbidden_Attributes" rule, checking for 'First and 'Last
{Forbidden: ["First", "Last"]},
# "Length_Attr" instance of the "Forbidden_Attributes" rule, checking for 'Length
{Forbidden: ["Length"], instance_name: "Length_Attr"}
]
}
Moreover, each instance must be identifiable through a unique name, thus the following configuration is invalid and will lead to a GNATCheck error:
val rules = @{
Forbidden_Attributes: [
{Forbidden: ["First", "Last"], instance_name: "Instance"},
{Forbidden: ["Length"], instance_name: "Instance"},
]
}
Additionally to the rules
top-level symbol, an LKQL rule file may export
ada_rules
and spark_rules
symbols to enable associated rules,
respectively, only on Ada code or only on SPARK code. Those symbols must also
refer to an object value formatted like the rules
value.
# Rules to run on both Ada and SPARK code
val rules = @{
Goto_Statements
}
# Rules to run only on Ada code
val ada_rules = @{
Forbidden_Attributes: {Forbidden: ["GNAT"]}
}
# Rules to run only on SPARK code
val spark_rules = @{
Ada_2022_In_Ghost_Code
}
Please note that compiler based rules (Warnings, Restrictions and Style_Checks) cannot be restricted to Ada or SPARK code. Consequently, the following configuration will raise an error:
val spark_rules = @{
Warnings: {Arg: "a"}
}
Attention
Instance uniqueness must also be respected between all rule sets, meaning that such config is invalid:
val rules = @{
# Clashing with "Goto_Statement" in ada_rules
Goto_Statements,
# Clashing with "Forbid_Attr" instance in spark_rules
Forbidden_Attributes: {Forbidden: ["GNAT"], instance_name: "Forbid_Attr"}
}
val ada_rules = @{
Goto_Statements
}
val spark_rules = @{
Forbidden_Attributes: {Forbidden: ["Length"], instance_name: "Forbid_Attr"}
}
You cannot provide more than one LKQL rule file when running GNATcheck. In order to compose a rule file with another you have to use the LKQL importation mechanism and combine rule objects. Here is an example of LKQL rule file composition:
# common_rules.lkql
val rules = @{
Goto_Statements
}
# specific_rules.lkql
import common_rules
val rules = common_rules.rules.combine(
@{ Redundant_Null_Statements }
)
Then you can run GNATcheck with the specific_rules.lkql
file as coding
standard to perform rules defined in common_rules.lkql
combined to the ones
defined in specific_rules.lkql
.
Note
You can use the --lkql-path
command-line switch and the
Check'Lkql_Path
GPR attribute to configure directories LKQL rule files
are going to be searched in.
You can enable the same rule in multiple files, but the constraint about the instance name uniqueness remains valid, meaning that such configuration is invalid:
# common_rules.lkql
val rules = @{
Forbidden_Attributes: {Forbidden: ["First"], instance_name: "Forbid_Attr"}
}
# specific_rules.lkql
import common_rules
val rules = common_rules.rules.combine(@{
Forbidden_Attributes: {
Forbidden: ["Last"],
instance_name: "Forbid_Attr"
}
})
# error: This rule configuration defines two instances with the same name: "Forbid_Attr"
2.5. GNATcheck Rule Options
Attention
Rules options are deprecated, consider converting your rule
configuration to the new LKQL rule file format
using the --emit-lkql-rule-file
CLI switch.
The following options control the processing performed by gnatcheck
. You
can provide as many rule options as you want after the -rules
switch.
+R[:instance_name:]rule_id[:param{,param}]
Create and enable an instance of the specified rule with the specified parameter(s), if any. rule_id must be the identifier of one of the currently implemented rules (use
-h
for the list of implemented rules). Rule identifiers are not case-sensitive.Each param item must be a non-empty string representing a valid parameter for the specified rule. If the part of the rule option that follows the colon character contains any space characters then this part must be enclosed in quotation marks.
instance_name is a user-defined name for the created rule instance. If this is not specified, the instance name is set to the rule name (normalized to lower case). You can create as much instances as you want for a single rule, as long as they have distinct names (names aren’t case sensitive either). If an instance of the same rule with the same name already exists GNATcheck will raise an error.
For example:
-- Create and enable an instance of "Goto_Statements" named -- "goto_statements". +RGoto_Statements -- Create and enable an second instance of "Goto_Statements" named -- "custom_name". +R:custom_name:Goto_Statements -- Create and enable an instance of "Recursive_Subprograms" named -- "other_name". +R:other_name:Recursive_Subprograms -- This will cause a GNATcheck error because the "goto_statement" instance -- already exists. +RGoto_Statements
This feature can be used to map
gnatcheck
rules onto a user’s coding standard.-R[:instance_name:]rule_id
Remove the designated rule instance, disabling it at the same time.
Note
By removing a rule instance, all previously given instance parameter(s) are cleared from the GNATcheck memory.
Attention
No parameters are allowed for the
-R
rule option. Since rule instances are immutable, you cannot modify a parameter set once the instance has been created by a+R
option.-from=rule_option_filename
Read the rule options from the text file rule_option_filename, referred to as a ‘coding standard file’ below.
The default behavior is that all the rule checks are disabled.
If a rule option is given in a rule file, it can contain spaces and line breaks. Otherwise there should be no spaces between the components of a rule option.
If more than one rule option is specified for the same rule, with the same instance name, GNATcheck will raise an error and stop its execution.
Attention
Unlike in older versions of GNATcheck, rule instances aren’t mutable, so you cannot change options for an instance after its instantiation.
A coding standard file is a text file that contains a set of rule options described above.
The file may contain empty lines and Ada-style comments (comment lines and end-of-line comments). There can be several rule options on a single line (separated by a space).
A coding standard file may reference other coding standard files by including
more -from=rule_option_filename
options, each such option being replaced with the content of the
corresponding coding standard file during processing. In case a
cycle is detected (that is, rule_file_1
reads rule options
from rule_file_2
, and rule_file_2
reads
(directly or indirectly) rule options from rule_file_1
),
processing fails with an error message.
If the name of the coding standard file does not contain a path information in absolute form, then it is treated as being relative to the current directory if gnatcheck is called without a project file or as being relative to the project file directory if gnatcheck is called with a project file as an argument.
2.6. Mapping GNATcheck Rules Onto Coding Standards
If you want to use GNATcheck
to check if your code
follows a given coding standard, you can use the following approach
to simplify mapping your coding standard requirements onto
GNATcheck
rules:
when specifying rule configuration, use instance names that are relevant to your coding standard:
val rules = @{ Gnatcheck_Rule_1: {instance_name: "My_Coding_Rule_1", param1: "value"}, ... Gnatcheck_Rule_N: {instance_name: "My_Coding_Rule_N"} }
or with the deprecated rule options:
+R:My_Coding_Rule_1:Gnatcheck_Rule_1:param1 ... +R:My_Coding_Rule_N:Gnatcheck_Rule_N
call
gnatcheck
with the--show-rule
flag that adds the rule names the generated diagnoses. If a instance name is defined in the rule configuration, then this name will be used to annotate the diagnosis of the rule name:foo.adb:2:28: something is wrong here [My_Coding_Rule_1|Gnatcheck_Rule_1] ... bar.ads:17:3: this is not good [My_Coding_Rule_N|Gnatcheck_Rule_N]
Attention
A custom coding rule name can be any sequence of non-whitespace characters. Moreover, the “:” (colon) character is forbidden in those names for parsing purposes.
2.7. GNATcheck Exit Codes
gnatcheck
returns the following exit codes at the end of its run:
0
: No tool failure, no missing argument source and no rule violation was detected.1
: No tool failure, no missing argument source and at least one rule violation was detected.2
: A tool failure was detected (in this case the results of the gnatcheck run cannot be trusted).3
: No tool failure, no problem with rule specification, but there is at least one missing argument source.4
: Provided rule configuration file doesn’t exist.5
: The name of an unknown rule in a rule option or some problem with rule parameters.6
: Any other problem with specifying the rules to check.
If the exit code corresponds to some problem with defining the rules to check then the result of the gnatcheck run cannot be fully trusted because the set of rules that has been actually used may be different from user intent.
If gnatcheck is called with the --brief
option, it will return the exit code
0
instead of 1
when some violation is detected (and no tool failure).
2.8. Format of the Report File
The gnatcheck
tool outputs on stderr
all messages concerning
rule violations except if running in quiet mode. By default it also creates a
text file that contains the complete report of the last gnatcheck run, this file
is named gnatcheck.out
. A user can specify generation of
the XML version of the report file (its default name is gnatcheck.xml
)
If gnatcheck
is called with a project
file, the report file is located in the object directory defined by the project
file (or in the directory where the argument project file is located if no
object directory is defined), if --subdirs
option is specified, the
file is placed in the subdirectory of this directory specified by this option.
Otherwise it is located in the
current directory; the -o
or -ox
option can be used to
change the name and/or location of the text or XML report file.
This text report contains:
general details of the
gnatcheck
run: date and time of the run, the version of the tool that has generated this report, full parameters of thegnatcheck
invocation, reference to the list of checked sources and applied rules (coding standard);summary of the run (number of checked sources and detected violations);
list of exempted coding standard violations;
list of non-exempted coding standard violations;
list of problems in the definition of exemption sections;
list of language violations (compile-time errors) detected in processed sources;
The references to the list of checked sources and applied rules are
references to the text files that contain the corresponding information.
These files could be either files supplied as gnatcheck
parameters or
files created by gnatcheck
; in the latter case
these files are located in the same directory as the report file.
The content of the XML report is similar to the text report except that it explores the set of files processed by gnatcheck and the coding standard used for checking these files.
2.9. Rule Exemption
One of the most useful applications of gnatcheck
is to
automate the enforcement of project-specific coding standards,
for example in safety-critical systems where particular features
must be restricted in order to simplify the certification effort.
However, it may sometimes be appropriate to violate a coding standard rule,
and in such cases the rationale for the violation should be provided
in the source program itself so that the individuals
reviewing or maintaining the program can immediately understand the intent.
The gnatcheck
tool supports this practice with the notion of
a ‘rule exemption’ covering a specific source code section. Normally
rule violation messages are issued both on stderr
and in a report file. In contrast, exempted violations are not listed on
stderr
; thus users invoking gnatcheck
interactively
(e.g. in its GNAT Studio interface) do not need to pay attention to known and
justified violations. However, exempted violations along with their
justification are documented in a special section of the report file that
gnatcheck
generates.
2.9.1. Using pragma Annotate
to control rule and instance exemption
Rule and instance exemption is controlled by pragma Annotate
when its first
argument is ‘gnatcheck’. The syntax of gnatcheck
’s exemption control
annotations is as follows:
<pragma_exemption> ::= pragma Annotate (gnatcheck, <exemption_control>, <exempted_name> [, <justification>]);
<exemption_control> ::= Exempt_On | Exempt_Off
<exempted_name> ::= <string_literal>
<justification> ::= <expression>
An expression used as an exemption justification should be a static string expression. A string literal is enough in most cases, but you may want to use concatenation of string literals if you need a long message but you have to follow line length limitation.
When a gnatcheck
annotation has more than four arguments, gnatcheck
issues a warning and ignores the additional arguments. If the arguments do not
follow the syntax above, gnatcheck
emits a warning and ignores the
annotation.
The exempted_name
argument should be the name of some existing gnatcheck
rule, or the name of a rule instance. Otherwise a warning message is generated
and the pragma is ignored. If exempted_name
doesn’t denote an activated rule
or a valid instance in the given gnatcheck
call, the pragma is ignored and
no warning is issued. The exception from this rule is that exemption sections
for Warnings
rule are fully processed when Restrictions
rule is
activated.
Attention
Please not that for now it isn’t possible to provide an exempted name which designates an instance of a compiler-based rule (Warnings, Style_Checks and Restrictions) with a custom name.
A source code section where an exemption is active for a given rule is
delimited by an exempt_on
and exempt_off
annotation pair:
pragma Annotate (gnatcheck, Exempt_On, "Rule_Name", "justification");
-- source code section
pragma Annotate (gnatcheck, Exempt_Off, "Rule_Name");
Using such annotations will exempt all violations of the rule designated by
Rule_Name
inside the exempted source section. But you can also provide the
name of a rule instance to only exempt violations raised by this instance.
For some rules it is possible specify rule parameter(s) when defining an exemption section for a rule or an instance of it. This means that only the checks corresponding to the given rule parameter(s) are exempted in this section:
pragma Annotate (gnatcheck, Exempt_On, "Rule_Name: Par1, Par2", "justification");
-- source code section
pragma Annotate (gnatcheck, Exempt_Off, "Rule_Name: Par1, Par2");
A parametric exemption section can be defined for a rule if a rule has
parameters and these parameters change the scope of the checks performed by a
rule. For example, if you define an exemption section for ‘Restriction’ rule
with the parameter ‘No_Allocators’, then in this section only the checks for
No_Allocators
will be exempted, and the checks for all the other
restrictions from your coding standard will be performed as usual.
See the description of individual rules to check if parametric exemptions
are available for them and what is the format of the rule parameters to
be used in the corresponding parameters of the Annotate
pragmas.
If a rule has a parameter, but its documentation does not explicitly say that the parameter can be used when defining exemption sections for the rule, this means that the parametric exemption cannot be used for this rule.
You may also use pragma GNAT_Annotate
instead of pragma Annotate
, this
pragma has exactly the same format. This may be needed if you are using an old
version of the GNAT compiler that does not support the format of
pragma Annotate
given above. Old GNAT versions may issue warning about
unknown pragma when compiling a source that contains pragma GNAT_Annotate
.
2.9.2. GNATcheck Annotations Rules
An
Exempt_Off
annotation can only appear after a corresponding ‘Exempt_On’ annotation.An
Exempt_On
annotation should have a justification. Conversely, anExempt_Off
annotation should not have a justification.Exempted source code sections are only based on the source location of the annotations. Any source construct between the two annotations is part of the exempted source code section.
Exempted source code sections for different rules are independent. They can be nested or intersect with one another without limitation. Creating nested or intersecting source code sections for the same rule is not allowed.
A matching ‘Exempt_Off’ annotation pragma for an ‘Exempt_On’ pragma that defines a parametric exemption section is the pragma that contains exactly the same set of rule parameters for the same exempted name.
Parametric exemption sections for the same rule with different parameters can intersect or overlap in case if the parameter sets for such sections have an empty intersection.
Malformed exempted source code sections are reported by a warning, and the corresponding rule exemptions are ignored.
When an exempted source code section does not contain at least one violation of the exempted name, a warning is emitted on
stderr
.If an ‘Exempt_On’ annotation pragma does not have a matching ‘Exempt_Off’ annotation pragma in the same compilation unit, a warning is issued and the exemption section is considered to last until the end of the compilation unit source.
2.9.3. Using comments to control rule and instance exemption
As an alternative to the pragma Annotate
syntax, it is also possible to use
a syntax based on comments, with the following syntax:
<comment_exemption> ::= --## rule (on | off) <exempted_name> [## <exemption_justification>]
Here is an example:
--## rule off implicit_in ## Exemption justification
procedure Bar (A : Integer);
--## rule on implicit_in
Attention
Please note that a comment starting with --##
but not
respecting the above syntax will not trigger a warning, in order to not emit
false positives.
Also note that in its current iteration, this syntax does not support passing
parameters to rule names
The rules mentioned in GNATcheck Annotations Rules are relaxed, in particular:
Justifications are not checked and are optional;
Anything between the exempted name and
##
will be ignored;Rules regarding parametric exemption do not apply, as per the notice above.
The rule on
marker corresponds to Exempt_Off
and rule off
corresponds
to Exempt_On
. Apart from that, you can expect those rule exemptions to work
in a similar fashion as the ones described above.
In addition, a shorthand syntax is available to exempt a rule just for one line:
<line_comment_exemption> ::= --## rule line off <exempted_name> [## <rule_justification>]
For instance, from the previous example:
procedure Bar (A : Integer); --## rule line off implicit_in ## Exemption justification
This will exempt the given rule or instance only for the line on which this comment is placed, and automatically turn it back on on the next line.
2.10. Using GNATcheck as a Known Problem Detector
If you are a GNAT Pro Assurance customer, you have access to a special
packaging of GNATcheck called gnatkp
(GNAT Known Problem detector)
where the gnatcheck
executable is replaced by gnatkp
, and the
coding standard rules are replaced by rules designed to detect constructs
affected by known problems in official compiler releases. Note that GNATkp
comes in addition and not as a replacement of GNATcheck.
You can use the command gnatkp --help
to list all the switches
relevant to GNATkp. GNATkp mostly accepts the same command arguments as
GNATcheck and behaves in a similar way, but there are some differences that
are described below.
The easiest way to use GNATkp is by specifying the version of GNAT Pro that
you have and letting gnatkp
run all known problem detectors
registered for this version, via the switch --kp-version
. For example:
gnatkp -Pproject --kp-version=21.2 --target=<my_target> --RTS=<my_runtime>
will run all detectors relevant to GNAT Pro 21.2 on all files in the
project. The list of detectors will be displayed as info messages, and will
also be listed in the file gnatkp-rule-list.out
. The list of detected
source locations will be generated on standard error, as well as in a file
called gnatkp.out
.
You can display the list of detectors without running them by specifying
additionally the -h
switch, e.g.:
gnatkp --kp-version=21.2 -h --target=<my_target> --RTS=<my_runtime>
You can also combine the --kp-version
switch with the --target
switch
to filter out detectors not relevant for your target, e.g:
gnatkp -Pproject --kp-version=21.2 --target=powerpc-elf --RTS=<my_runtime>
will only enable detectors relevant to GNAT Pro 21.2 and to the powerpc-elf
target.
Note that you need to have the corresponding target GNAT compiler installed to use this option. By default, detectors for all targets are enabled.
It is also possible to specify the custom list of detectors for GNATkp to run
using the switch -r
:
gnatkp -Pproject --target=<my_target> --RTS=<my_runtime> -r kp_xxxx_xxx [-r kp_xxxx_xxx]
where kp_xxxx_xxx
is the name of a relevant known-problem to detect. You
can get the list of available detectors via the command gnatkp -h
. When
combined with the --kp-version
and possibly --target
switches,
gnatkp -h
will only list the detectors relevant to the version
(and target) specified.
Attention
You must provide explicit target and runtime (either through the command-line or with a provided project file) when running GNATkp to ensure the result soundness.
Note
The exemption mechanism is available for GNATkp as well but you have to
change pragmas and comments a bit to avoid conflict with GNATcheck
exemptions. Thus, pragmas annotations’ first argument must be gnatkp
instead of gnatcheck
:
pragma Annotate (gnatkp, Exempt_On, "kp_19198", "Justification");
And exemption comments’ first word must be kp
instead of rule
,
example:
--## kp off kp_19198 ## Justification
You can check via the GNAT Tracker interface which known problems are relevant to your version of GNAT and your target before deciding which known problems may impact you: most known problems are only relevant to a specific version of GNAT, a specific target, or a specific usage profile. Do not hesitate to contact the AdaCore support if you need help identifying the entries that may be relevant to you.
2.11. Performance and Memory Usage
GNATcheck performances are closely related to rules you’re enabling and to the
size of the codebase you’re running it on, and sometimes it can take a lot of
time to perform all checks.
You can use the -j
switch to run GNATcheck in multi-core mode and decrease
the checking time. However, you have to be careful about memory usage when
running GNATcheck with this mode enabled:
You should count around 3.5 GB of available memory per million source code
lines, per process. Meaning that for a project with l
source code lines, if
you run GNATcheck while providing n
as parameter of the -j
switch, you
will need (l / 1,000,000) * 3.5 * n
GB of available memory (this formula
isn’t valid if n = 0
).
Attention
Out-of-memory errors are hard to debug and can lead to system freezes, invalid results, or non-deterministic behavior. Thus, make sure you have enough memory before running GNATcheck.
2.12. Transition from ASIS-based GNATcheck
Originally gnatcheck
was implemented on top of the ASIS technology and
starting with version 23, it was re-implemented on top of the libadalang
technology. This new implementation has kept most of the old gnatcheck interface
and functionality, so transition from the old gnatcheck
to the current
version should be smooth and transparent, except possibly for a few aspects to
be taken into account by users of the old technology.
2.12.1. Switches No Longer Supported
The following switches from the old gnatcheck
are no longer supported:
-a
In order to process GNAT Run-Time library units, you need to explicitly include them in a project file.
--incremental
GNATcheck no longer makes the distinction between “local” and “global” rules, so this switch is no longer supported. You can use the
-j
switch instead which provides a significant speed up compared to the old version.--write-rules=template_file
This switch is no longer supported. You can use the GNAT Studio rule editor instead to create a coding standard file.
2.12.2. The new rule instance system
The new gnatcheck
implementation is introducing a new rule instance system
which allows you to instantiate a rule multiple times under different names,
and with potentially different rule parameters.
You can now define more that one “alias” for the same rule to map your coding
standard on the gnatcheck
rules.
However, rules aren’t mutable anymore, which means that you cannot modify
parameters of a rule once it has been created (instantiated).
For example:
-- The rule "Goto_Statements" is instantiated here
+RGoto_Statements
-- We try to create a new instance of the "Goto_Statements", this will fail
+RGoto_Statements:Only_Unconditional
While with the old system this rule file would just mutate the previously
enabled “Goto_Statements” rule, with the new instance system, this will cause
an error during the gnatcheck
run, telling you that the “goto_statement”
instance already exists.
To correct this error, you have define a custom name for the second
“Goto_Statements” instance:
-- The rule "Goto_Statements" is instantiated here
+RGoto_Statements
-- The rule "Goto_Statements" is also instantiated here,
-- under the "Uncond_Goto" name.
+R:Uncond_Goto:Goto_Statements:Only_Unconditional
The same way, you have to rewrite rule options such as:
+RForbidden_Pragmas:GNAT
+RForbidden_Pragmas:Annotate
+RForbidden_Pragmas:Assert
into a single rule option using the comma separated notation, like:
+RForbidden_Pragmas:GNAT,
Annotate,
Assert
This new instance system also suppress the possibility to disable a rule (or
an instance) with a parameter. Thus, the -R
rule option doesn’t accept
parameters anymore.
2.12.3. Rule Aliases No Longer Supported
Because of historical reasons the old gnatcheck
allowed aliases for
some rules. These aliases are not documented, but there is some possibility that
they could be used in some legacy rule files. GNATcheck
no longer supports
these aliases. Here is the (alphabetically ordered) list of all the
aliases formerly accepted and their replacement:
Old Rule Alias |
Replacement |
---|---|
Abstr_Types |
Abstract_Type_Declarations |
Bool_Relation_Ops |
Boolean_Relational_Operators |
Contr_Types |
Controlled_Type_Declarations |
Control_Structure_Nesting |
Overly_Nested_Control_Structures |
Decl_Blocks |
Declarations_In_Blocks |
Default_Par |
Default_Parameters |
Derived_Types |
Non_Tagged_Derived_Types |
Discr_Rec |
Discriminated_Records |
Explicit_Discrete_Ranges |
Explicit_Full_Discrete_Ranges |
Functionlike_Procedures |
Function_Style_Procedures |
Global_Loop_Exit |
Outer_Loop_Exits |
Goto |
GOTO_Statements |
Implicit_IN_Parameter_Mode |
Implicit_IN_Mode_Parameters |
LL_Subpr |
Library_Level_Subprograms |
Local_Pckg |
Local_Packages |
Misnamed_Identifiers |
Identifier_Suffixes |
Missing_Small_For_Fixed_Point_Type |
Implicit_SMALL_For_Fixed_Point_Types |
Non_Marked_BEGIN_In_Package_Body |
Uncommented_BEGIN_In_Package_Bodies |
Non_Named_Blocks_And_Loops |
Unnamed_Blocks_And_Loops |
One_Entry_In_PO |
Multiple_Entries_In_Protected_Definitions |
Parameter_Mode_Ordering |
Parameters_Out_Of_Order |
Positional_Component_Associations |
Positional_Components |
Positional_Generic_Associations |
Positional_Generic_Parameters |
Positional_Parameter_Associations |
Positional_Parameters |
Pragma_Usage |
Forbidden_Pragmas |
Predefined_Exceptions |
Raising_Predefined_Exceptions |
Proper_Returns |
Improper_Returns |
Qualified_Aggr |
Non_Qualified_Aggregates |
Restrict_Name_Space |
Name_Clashes |
Simple_Loop_Exit_Names |
Expanded_Loop_Exit_Names |
SPARK_Attributes |
Non_SPARK_Attributes |
Unconstr_Array_Return |
Unconstrained_Array_Returns |
Universl_Ranges |
Universal_Ranges |
Unreasonable_Places_For_Instantiations |
Improperly_Located_Instantiations |
Use_Pckg_Clauses |
USE_PACKAGE_Clauses |
Use_Of_Non_Short_Circuit |
Non_Short_Circuit_Operators |
Visible_Exceptions |
Raising_External_Exceptions |
Volatile_Requires_Addr_Clause |
Volatile_Objects_Without_Address_Clauses |
2.12.4. New Defaults For Recursive_Subprograms Rule
The Recursive_Subprograms
rule now defaults to skipping dispatching calls
and a new parameter Follow_Dispatching_Calls
is available (the old
Skip_Dispatching_Calls
is still accepted for compatibility and is ignored
since it’s the default). In addition, implicit calls made via default
object initialization are not taken into account.
2.12.5. Argument Sources Legality And Project Files
The old gnatcheck
compiled its argument sources to create the
so-called ASIS tree files. This had two important consequences: first,
gnatcheck
could analyze only legal Ada sources, and second, for each
legal argument source gnatcheck
had full static semantic information.
The situation with the current gnatcheck
is different.
First, gnatcheck
can now analyze Ada sources that are not legal, and it
is trying to do its best to check the rules specified. This may result in
false negatives caused by the absence of necessary semantic information or
by some other problems in the argument source that impede a full check of
some rules. You can use the --check-semantic
option to check if your
Ada sources are legal sources.
Second, if gnatcheck
is called for some Ada source and it does not have a
project file as a parameter, it will see only the information contained
in the sources specified and will not follow the semantic dependencies on other
sources if any. This is why it is strongly recommended to call gnatcheck
with a project file. When called with a project file, gnatcheck
follows
all the semantic dependencies for sources located in the project file source
directories.