[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
gnatmetric
The gnatmetric
tool is an ASIS-based utility
for computing various program metrics.
It takes an Ada source file as input and generates a file containing the
metrics data as output. Various switches control which
metrics are computed and output.
16.1 Switches for gnatmetric
To compute program metrics, gnatmetric
invokes the Ada
compiler and generates and uses the ASIS tree for the input source;
thus the input must be legal Ada code, and the tool should have all the
information needed to compile the input source. To provide this information,
you may specify as a tool parameter the project file the input source belongs to
(or you may call gnatmetric
through the gnat
driver (see 12.2 The GNAT Driver and Project Files). Another possibility is to specify the source search
path and needed configuration files in `-cargs' section of gnatmetric
call, see the description of the gnatmetric
switches below.
If the set of sources to be processed by gnatmetric
contains sources with
preprocessing directives
then the needed options should be provided to run preprocessor as a part of
the gnatmetric
call, and the computed metrics
will correspond to preprocessed sources.
The gnatmetric
command has the form
$ gnatmetric [switches] {filename} [-cargs gcc_switches] |
where
gnatmetric
Switches).
Including both a `-files' switch and one or more
filename arguments is permitted.
gcc
. They will be passed on to all compiler invocations made by
gnatmetric
to generate the ASIS trees. Here you can provide
`-I' switches to form the source search path,
and use the `-gnatec' switch to set the configuration file,
use the `-gnat05' switch if sources should be compiled in
Ada 2005 mode etc.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
gnatmetric
The following subsections describe the various switches accepted by
gnatmetric
, organized by category.
16.1.1 Output File Control 16.1.2 Disable Metrics For Local Units 16.1.3 Specifying a set of metrics to compute 16.1.4 Other gnatmetric
Switches
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
gnatmetric
has two output formats. It can generate a
textual (human-readable) form, and also XML. By default only textual
output is generated.
When generating the output in textual form, gnatmetric
creates
for each Ada source file a corresponding text file
containing the computed metrics, except for the case when the set of metrics
specified by gnatmetric parameters consists only of metrics that are computed
for the whole set of analyzed sources, but not for each Ada source.
By default, the name of the file containing metric information for a source
is obtained by appending the `.metrix' suffix to the
name of the input source file. If not otherwise specified and no project file
is specified as gnatmetric
option this file is placed in the same
directory as where the source file is located. If gnatmetric
has a
project file as its parameter, it places all the generated files in the
object directory of the project (or in the project source directory if the
project does not define an objects directory), if `--subdirs' option
is specified, the files are placed in the subrirectory of this directory
specified by this option.
All the output information generated in XML format is placed in a single
file. By default the name of this file is `metrix.xml'.
If not otherwise specified and if no project file is specified
as gnatmetric
option this file is placed in the
current directory.
Some of the computed metrics are summed over the units passed to
gnatmetric
; for example, the total number of lines of code.
By default this information is sent to `stdout', but a file
can be specified with the `-og' switch.
The following switches control the gnatmetric
output:
gnatmetric
output includes the name(s) of the Ada source file(s) from which the metrics
are computed. By default each name includes the absolute path. The
`-sfn' switch causes gnatmetric
to exclude all directory information from the file names that are output.)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
gnatmetric
relies on the GNAT compilation model -
one compilation
unit per one source file. It computes line metrics for the whole source
file, and it also computes syntax
and complexity metrics for the file's outermost unit.
By default, gnatmetric
will also compute all metrics for certain
kinds of locally declared program units:
These kinds of entities will be referred to as eligible local program units, or simply eligible local units, in the discussion below.
Note that a subprogram declaration, generic instantiation, or renaming declaration only receives metrics computation when it appear as the outermost entity in a source file.
Suppression of metrics computation for eligible local units can be obtained via the following switch:
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
By default all the metrics are computed and reported. The switches described in this subsection allow you to control, on an individual basis, whether metrics are computed and reported. If at least one positive metric switch is specified (that is, a switch that defines that a given metric or set of metrics is to be computed), then only explicitly specified metrics are reported.
16.1.3.1 Line Metrics Control 16.1.3.2 Syntax Metrics Control 16.1.3.3 Complexity Metrics Control 16.1.3.4 Coupling Metrics Control
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
For any (legal) source file, and for each of its
eligible local program units, gnatmetric
computes the following
metrics:
gnatmetric
sums the values of the line metrics for all the
files being processed and then generates the cumulative results. The tool
also computes for all the files being processed the average number of code
lines in bodies.
You can use the following switches to select the specific line metrics to be computed and reported.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
gnatmetric
computes various syntactic metrics for the
outermost unit and for each eligible local unit:
"Each of the following is defined to be a declaration: any basic_declaration; an enumeration_literal_specification; a discriminant_specification; a component_declaration; a loop_parameter_specification; a parameter_specification; a subprogram_body; an entry_declaration; an entry_index_specification; a choice_parameter_specification; a generic_formal_parameter_declaration."
This means for example that each enumeration literal adds one to the count, as well as each subprogram parameter.
Thus the results from this metric will be significantly greater than might be expected from a naive view of counting semicolons.
For the outermost unit in the file, gnatmetric
additionally computes
the following metrics:
Along with the total number of public types, the following types are counted and reported separately:
By default, all the syntax metrics are computed and reported. You can use the following switches to select specific syntax metrics.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
For a program unit that is an executable body (a subprogram body (including
generic bodies), task body, entry body or a package body containing
its own statement sequence) gnatmetric
computes the following
complexity metrics:
The McCabe cyclomatic complexity metric is defined in http://www.mccabe.com/pdf/mccabe-nist235r.pdf
According to McCabe, both control statements and short-circuit control forms should be taken into account when computing cyclomatic complexity. For Ada 2012 we have also take into account conditional expressions and quantified expressions. For each body, we compute three metric values:
statement complexity
in gnatmetric
output),
expression complexity
in gnatmetric
output), and
cyclomatic complexity
in gnatmetric
output).
The cyclomatic complexity is also computed for Ada 2012 expression functions. An expression function cannot have statements as its components, so only one metric value is computed as a cyclomatic complexity of an expression function.
The origin of cyclomatic complexity metric is the need to estimate the number
of independent paths in the control flow graph that in turn gives the number
of tests needed to satisfy paths coverage testing completeness criterion.
Considered from the testing point of view, a static Ada loop
(that is,
the loop
statement having static subtype in loop parameter
specification) does not add to cyclomatic complexity. By providing
`--no-static-loop' option a user
may specify that such loops should not be counted when computing the
cyclomatic complexity metric
The Ada essential complexity metric is a McCabe cyclomatic complexity metric
counted for the code that is reduced by excluding all the pure structural Ada
control statements. An compound statement is considered as a non-structural
if it contains a raise
or return
statement as it subcomponent,
or if it contains a goto
statement that transfers the control outside
the operator. A selective accept statement with terminate
alternative
is considered as non-structural statement. When computing this metric,
exit
statements are treated in the same way as goto
statements unless `-ne' option is specified.
The Ada essential complexity metric defined here is intended to quantify the extent to which the software is unstructured. It is adapted from the McCabe essential complexity metric defined in http://www.mccabe.com/pdf/mccabe-nist235r.pdf but is modified to be more suitable for typical Ada usage. For example, short circuit forms are not penalized as unstructured in the Ada essential complexity metric.
When computing cyclomatic and essential complexity, gnatmetric
skips
the code in the exception handlers and in all the nested program units. The
code of assertions and predicates (that is, subprogram preconditions and
postconditions, subtype predicates and type invariants) is also skipped.
By default, all the complexity metrics are computed and reported. For more fine-grained control you can use the following switches:
exit
statements as goto
s when
computing Essential Complexity
return
statements and raise statements in case when the
raised exception is not handled in the same body. In case of a function this
metric subtracts 1 from the number of exit points, because a function body
must contain at least one return
statement.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Coupling metrics measure the dependencies between a given entity and other entities in the program. This information is useful since high coupling may signal potential issues with maintainability as the program evolves.
gnatmetric
computes the following coupling metrics:
Two kinds of coupling metrics are computed:
Object-oriented coupling metrics measure the dependencies between a given class (or a group of classes) and the other classes in the program. In this subsection the term "class" is used in its traditional object-oriented programming sense (an instantiable module that contains data and/or method members). A category (of classes) is a group of closely related classes that are reused and/or modified together.
A class K
's fan-out coupling is the number of classes
that K
depends upon.
A category's fan-out coupling is the number of classes outside the
category that the classes inside the category depend upon.
A class K
's fan-in coupling is the number of classes
that depend upon K
.
A category's fan-in coupling is the number of classes outside the
category that depend on classes belonging to the category.
Ada's object-oriented paradigm separates the instantiable entity (type) from the module (package), so the definition of the coupling metrics for Ada maps the class and class category notions onto Ada constructs.
For the coupling metrics, several kinds of modules that define a tagged type or an interface type -- library packages, library generic packages, and library generic package instantiations -- are considered to be classes. A category consists of a library package (or a library generic package) that defines a tagged or an interface type, together with all its descendant (generic) packages that define tagged or interface types. Thus a category is an Ada hierarchy of library-level program units. Class coupling in Ada is referred to as "tagged coupling", and category coupling is referred to as "hierarchy coupling".
For any package serving as a class, its body and subunits (if any) are considered together with its spec when computing dependencies, and coupling metrics are reported for spec units only. Dependencies between classes mean Ada semantic dependencies. For object-oriented coupling metrics, only dependencies on units treated as classes are considered.
Similarly, for unit and control coupling an entity is considered to be the
conceptual construct consisting of the entity's specification, body, and
any subunits (transitively).
gnatmetric
computes
the dependencies of all these units as a whole, but
metrics are only reported for spec
units (or for a subprogram body unit in case if there is no
separate spec for the given subprogram).
For unit coupling, dependencies are computed between all kinds of program units. For control coupling, the dependencies of a given unit are limited to those units that define subprograms. Thus control fan-out coupling is reported for all units, but control fan-in coupling is only reported for units that define subprograms.
The following simple example illustrates the difference between unit coupling and control coupling metrics:
package Lib_1 is function F_1 (I : Integer) return Integer; end Lib_1; package Lib_2 is type T_2 is new Integer; end Lib_2; package body Lib_1 is function F_1 (I : Integer) return Integer is begin return I + 1; end F_1; end Lib_1; with Lib_2; use Lib_2; package Pack is Var : T_2; function Fun (I : Integer) return Integer; end Pack; with Lib_1; use Lib_1; package body Pack is function Fun (I : Integer) return Integer is begin return F_1 (I); end Fun; end Pack; |
If we apply gnatmetric
with the `--coupling-all' option to
these units, the result will be:
Coupling metrics: ================= Unit Lib_1 (C:\customers\662\L406-007\lib_1.ads) control fan-out coupling : 0 control fan-in coupling : 1 unit fan-out coupling : 0 unit fan-in coupling : 1 Unit Pack (C:\customers\662\L406-007\pack.ads) control fan-out coupling : 1 control fan-in coupling : 0 unit fan-out coupling : 2 unit fan-in coupling : 0 Unit Lib_2 (C:\customers\662\L406-007\lib_2.ads) control fan-out coupling : 0 unit fan-out coupling : 0 unit fan-in coupling : 1 |
The result does not contain values for object-oriented coupling because none of the argument units contains a tagged type and therefore none of these units can be treated as a class.
The Pack
package (spec and body) depends on two
units -- Lib_1
and Lib_2
-- and so its unit fan-out coupling
is 2. Since nothing depends on it, its unit fan-in coupling is 0, as
is its control fan-in coupling. Only one of the units Pack
depends
upon defines a subprogram, so its control fan-out coupling is 1.
Lib_2
depends on nothing, so its fan-out metrics are 0. It does
not define any subprograms, so it has no control fan-in metric.
One unit (Pack
) depends on it , so its unit fan-in coupling is 1.
Lib_1
is similar to Lib_2
, but it does define a subprogram.
Its control fan-in coupling is 1 (because there is one unit
depending on it).
When computing coupling metrics, gnatmetric
counts only
dependencies between units that are arguments of the gnatmetric
invocation. Coupling metrics are program-wide (or project-wide) metrics, so
you should invoke gnatmetric
for
the complete set of sources comprising your program. This can be done
by invoking gnatmetric
with the corresponding project file
and with the `-U' option.
By default, all the coupling metrics are disabled. You can use the following switches to specify the coupling metrics to be computed and reported:
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
gnatmetric
Switches
Additional gnatmetric
switches are as follows:
gnatcheck
behavior when it is called with the project file from the
GNAT driver. Has no effect if no project is specified.
gnatmetric
. You also can combine this switch with
an explicit list of files.
gnatmetric
generates version information and then
a trace of sources being processed.
If a project file is specified and no argument source is explicitly specified (either directly or by means of `-files' option), and no `-U' is specified, then the set of processed sources is all the immediate units of the argument project.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |