Metrics provide access to valuable information about your program and can be used to enforce coding guidelines or
measure code quality. A wide variety of statistics are available for a range of subjects including functions, classes,
and files.
The two primary forms of output associated with metrics are reports and violations. A metric report provides the
values of all metrics, or a nominated subset, in a standard format at the end of analysis. A metric check can be
registered which will trigger violation messages when an entity does not meet the conditions of the check.
A metric subject represents the abstract notion of all entities of a certain kind. For example, file and function are
metric subjects. A defined list of metrics are associated with each subject, but values of collected metrics
are a property of instances of that subject. Each individual file or function (instance) present in the
program will collect values for metrics associated with the file or function subjects respectively.
The value of each metric is either a number, an entity, or a collection of entities. A numeric metric is classified as
either a measure or a count. A defined quantity such as Halstead volume or cyclomatic complexity is a measure
while a metric such as “number of forward goto statements” representing how many entities matching some criteria
exist is a count. A collection is an array of instances of a particular metric subject, for example file.functions is a
collection of metric data for each function defined within a particular file. Collections can be used with built-in
operations including count, sum, and filter. See 10.3 Metric Expressions for more details on these operations.
See 10.6 Built-in Metrics for a list of metric subjects and their metrics.
The +metric_report option can be used to generate customized reports. The +metric option can check for
violations of metric-based conditions, nominate metrics for inclusion in the report, and create new custom metrics.
All options relating to metrics must be appear prior to the first module.
The +metric_report option is used to request a metric report at the end of analysis. By default, all metrics are
included in the report. If the +metric option has been used to nominate any metrics for explicit inclusion in the
report then only nominated metrics will appear. This can be overridden by providing as an argument to the
optional scope sub-option to +metric_report either all or nominated which determines conclusively
whether all metrics are included or only nominated metrics (even if no metrics have been nominated).
The +metric_report option accepts the following optional sub-options:
scope — Valid values are all and nominated. Explicitly determines whether all metrics are included in the report or only nominated metrics. The default behavior is nominated if any metrics have been nominated and all otherwise.
format — Valid values are xml, json, or csv. The default is csv. Note that CSV fields containing literal commas, double quotes, or newlines will be enclosed in double quotes and within such a field literal double quotes will be doubled.
filename — Specifies an output filename where the metric report will be written. If no filename is specified the report will be written to standard error.
For example, the option +metric_report(scope=all, format=xml, filename=path/file.xml) will request a report containing all metrics to be written to the file path/file.xml in XML format.
Metrics are nominated using a +metric option that simply names a metric using its subject and metric name. For
example, +metric(file.num_lines) nominates the values of file.num_lines to appear on the report for all files.
The metric report includes function and class definitions as well as templates and specializations thereof, but it does not include instantiations.
The metric report provides the subject, entity_name, id (metric name), value, and location for each instance of an included metric. In the CSV format, fields appear in the listed order and column names are not included. In the JSON and XML formats, the indicated names are used and the entries appear enclosed in an outer metrics object. The location field uses the format file:line:col and is filled only for entries with the function subject.
Metrics use a C-like expression grammar with function calls (to built-in functions), simple assignment, parenthetical grouping, identifiers, numeric literals with optional decimal places, the dot operator, and arithmetic, logical, and comparison operators. Built-in functions are listed below. The assignment operator is available only in the context of defining a custom metric. Identifiers denote the name of a metric or a metric subject, and they may contain letters, underscores, and non-leading digits. Numeric literals are always decimal and consist of a whole number part optionally followed by a period and fractional part. The dot operator takes a metric subject or instance thereof on the left and a metric name on the right; this forms a metric designator which refers to that metric name of that subject, analogous to structure access in C. An expression is considered to “evaluate to true” if the result is a non-zero numeric value. Evaluation errors may yield an empty value and evaluation of a sub-expression to an empty value will typically cause evaluation of the enclosing expression to fail in turn. When a metric subject appears in an expression, it generally leads to implicit iteration in the enclosing context where the expression will be executed multiple times, once with each instance of that subject substituted in place of the abstract subject.
count(collection) (numeric) — Returns the size of the provided collection.
sum(collection, expression) (numeric) — Returns the sum of the results of evaluating the provided expression for each item in the provided collection.
average(collection, expression) (numeric) — Returns the arithmetic mean of the results of evaluating the provided expression for each item in the provided collection.
median(collection, expression) (numeric) — Returns the median of the results of evaluating the provided expression for each item in the provided collection.
min(collection, expression) (numeric) — Returns the minimum value of the provided expression for any item in the provided collection.
max(collection, expression) (numeric) — Returns the maximum value of the provided expression for any item in the provided collection.
min_item(collection, expression) (entity) — Returns the entity in the provided collection for which the minimum value of the provided expression occurred.
max_item(collection, expression) (entity) — Returns the entity in the provided collection for which the maximum value of the provided expression occurred.
filter(collection, condition) (collection) — Returns a new collection containing the items from the provided collection for which the provided condition evaluates to true.
ln(number) (numeric) — Evaluates the natural logarithm, , of the provided expression.
exp(number) (numeric) — Evaluates the natural exponential function, , of the provided expression.
abs(number) (numeric) — Evaluates the absolute value, , of the provided expression.
If the expression provided to a +metric option is a comparison operator (possibly within a logical operator) then it
introduces a new metric check. The expression must contain at least one metric designator and the subject (left
component) of all metric designators in the top-level expression must match. Multiple metric names for the same
subject may appear. The provided expression will be evaluated at the end of analysis for each instance of that
subject (e.g. for the subject file the expression would be evaluated separately using the metric values for each file).
The check is considered to be violated if the expression evaluates to true. A message in the info category will be
issued reporting this violation. By default this will be 888 , although this is configurable using the msgno sub-option.
As an example, the option +metric(function.num_return_stmts > 1) will cause a message to be emitted when a function contains multiple return statements. If a function f with two return statements is defined in the presence of this option then PC-lint Plus will emit:
info 888: number of return statements (2) in function 'f' is greater than 1
Multiple metric designators involving the same subject may appear, for example +metric(file.num_comment_lines /
file.num_lines < 0.10) will cause a message to emitted if fewer than 10% of lines in a file are comment lines (see
Definitions below for the precise specification of terms like “comment line”).
When registering a metric check, the +metric option accepts the following sub-options:
msgno — Specifies a custom message number to use when reporting a violation instead of 888 . The criteria for custom message numbers are the same as for the +message option.
append — Specifies text to append to the end of the message when reporting a violation. This text will be appended prior to any text that may also be appended based on the message number by the general -append option.
For example, violations reported in response to the option +metric(file.num_lines >= 100 &&
file.num_comment_lines < 10, msgno=8042, append=[example]) will be emitted with message number 8042
and [example] appended to the message text.
Metric checks are generally performed during or after global wrap-up and can incorporate information from multiple modules. In unit checkout mode, metric checks for functions, classes, and modules are performed locally at module wrap-up. Metric data for each module is independent when performing metric checks in unit checkout mode.
Metric violation messages are generated automatically based on the provided expression and the circumstances of
the individual violation. The previous example demonstrates that a violation involving the expression
function.num_return_stmts > 1 can produce a message rendered as number of return statements (2)
in function ’f’ is greater than 1 (where 2 is the number of return statements present in f).
When using a more complex expression, the message text may change not only in value parameterization but also in form. For example:
+metric( (function.num_backward_goto_stmts > 0) || (function.num_forward_goto_stmts > 0 && (function.num_labels > 1 || !function.isExternC)) ,msgno=8001 )
This check enforces that goto statements may only be used for the purposes of jumping to a single cleanup label at the end of an extern "C" function. Different violations of this requirement produce different messages. For example:
extern "C" void f() { goto clean; clean: return; }
does not violate the check.
void w() { begin: goto begin; }
violates the check because w contains a backwards goto statement which is never permitted. This emits:
info 8001: number of backward goto statements (1) in function 'w' is greater than 0
In the alternative example:
void h() { goto clean; clean: return; }
the message is again reported but the text is now:
info 8001: number of forward goto statements (1) in function 'h' is greater than 0 and not isExternC of function 'h'
which highlights a different portion of the requirement.
Metric checks for a class or function can utilize Queries to access AST information. Single argument Query Functions that match the metric subject can be accessed by name in the same manner as a built-in metric. For example, the previously discussed option:
+metric( (function.num_backward_goto_stmts > 0) || (function.num_forward_goto_stmts > 0 && (function.num_labels > 1 || !function.isExternC)) )
creates a metric check which will report general usage of goto while allowing extern "C" functions to follow a permitted pattern of exception handling using a cleanup label. This uses the query function isExternC to determine whether the function is declared as extern "C".
If the expression provided to a +metric option is an assignment then the left operand must be a metric designator
and the right operand must be an expression which may include other metric designators referring to different
metrics about the same subject as the assignment target.
Custom metrics may be defined in terms of other custom metrics, but evaluation of a custom metric recursively on
the same object will cause an error. Note that unevaluated recursion is permitted; the computation of a custom
metric may involve evaluation of the same custom metric of a different object if it is defined in a way that leads to a
base case. See the 10.5.1.2 Number of inheritance edges in class hierarchy example below for an application of
recursion.
Metric designators referring to custom metrics can be nominated or used in checks like built-in metrics. A custom
metric cannot redefine a built-in metric nor a previously defined custom metric.
Assignments may not appear (and by extension, custom metrics may not be created) within a larger expression of
any +metric option. A custom metric can only be created when a +metric option specifies exactly one top-level
assignment.
The sub-option nominate, taking no arguments, may be specified to additionally nominate the newly created metric in a manner equivalent to an explicit +metric nomination option referring to the metric designator being assigned to.
Percentage of functions in a file with multiple return statements return_ratio.lnt:
// Create a new custom metric called 'funcs_with_multiple_returns' for any 'file'. // This custom metric is a collection and consists of all functions from the built-in // 'file.functions' where the condition 'function.num_return_stmts > 1' is true. +metric(file.funcs_with_multiple_returns = filter(file.functions, function.num_return_stmts > 1)) // Create a new custom metric called 'multiple_return_ratio' for any 'file'. // This custom metric is numeric and is the ratio of the sizes of the // 'funcs_with_multiple_returns' and 'functions' collections. The size of a collection is found // using the 'count' function. +metric(file.multiple_return_ratio = count(file.funcs_with_multiple_returns) / count(file.functions)) // Nominate 'multiple_return_ratio' to appear on the report. +metric(file.multiple_return_ratio) // Request a metric report. It will be emitted to standard error at the end of analysis. // Because a metric was nominated, only nominated metrics will be displayed. // Only 'multiple_return_ratio' has been nominated. The default format is CSV. +metric_report
test.cpp:
Example report output:
file,test.cpp,multiple_return_ratio,0.250
Number of inheritance edges in class hierarchy For example, consider the class hierarchy:
struct X { }; struct Y : X { }; struct Z { }; struct A : Z, Y { }; struct B { }; struct C : A, B { }; struct D : C { };
To compute the total number of inheritance edges in the hierarchy for each class, a custom metric can be created:
+metric( class.hierarchy_edges = count(class.immediate_bases) + sum(class.immediate_bases, class.hierarchy_edges) )
This option defines the custom metric class.hierarchy_edges recursively to the sum of the number of immediate base classes of all base classes in the hierarchy. The recursion eventually ends when a class has no immediate bases, which yields a sum of 0 without evaluating hierarchy_edges. This produces the report:
class,A,hierarchy_edges,3 class,B,hierarchy_edges,0 class,C,hierarchy_edges,5 class,D,hierarchy_edges,6 class,X,hierarchy_edges,0 class,Y,hierarchy_edges,1 class,Z,hierarchy_edges,0
Ratio of number of lines in member function to average number of lines in member functions of the containing class This example creates a custom metric, metric_length_ratio, representing the ratio of the number of lines in a member function to the average number of lines in member functions of the containing class. The first option creates a custom metric called avg_method_lines which calculates the average number of lines across methods in a class. The second option uses this avg_method_lines metric from the enclosing class to define method_length_ratio for each function.
+metric(class.avg_method_lines = average(class.non_static_member_functions, function.num_lines)) +metric(function.method_length_ratio = function.num_lines / function.parent_class.avg_method_lines)
Comment line – A comment line is a line that contains any portion of a comment. This includes blank lines within C-style comments as well as lines that consist entirely of a /* or // comment introducer or */ comment terminator if they are part of a comment.
Code Line – A code line is a line that contains one or more non-whitespace characters that appear outside of comments.
Empty Line – An empty line is a line outside of a comment that does not contain any non-whitespace characters.
Line – The total number of lines in a file is counted using the POSIX definition of a line, but non-empty files that do not end in a newline are processed as if a trailing newline had been inserted.
Halstead metrics, from Halstead’s “software science”, are defined by equations based on the classification of program
tokens as operators or operands [?].
Note that in C++, the standard grammar term function-try-block refers to a construct of the form:
void f() try { } catch (...) { }
where the compound statement typically encompassing a function body is replaced with a top-level try-catch.
defined classes – classes (collection)
A collection of classes defined in the project. This includes all class/struct/union definitions arising from any alternative preprocessing branches or macro definitions that could arise when a file is included multiple times or in multiple translation units.
defined functions – functions (collection)
A collection of functions defined in the project. This includes all function definitions arising from any alternative preprocessing branches or macro definitions that could arise when a file is included multiple times or in multiple translation units.
number of distinct files – num_distinct_files (count)
The number of distinct files processed across all translation units. Each source or header file is counted once even if it is utilized multiple times.
The identity of a single file referenced using different paths will generally be consolidated, but this is not necessarily possible if a single logical file is inconsistently referenced through link, junction, mount point, or network filesystem arrangements.
number of elective messages emitted – num_elective_messages_emitted (count)
The number of messages emitted in the elective note category. See 306 number of messages emitted for general information.
number of error messages emitted – num_error_messages_emitted (count)
The number of messages emitted in the error category. See 306 number of messages emitted for general information.
number of info messages emitted – num_info_messages_emitted (count)
The number of messages emitted in the informational category. See 306 number of messages emitted for general information.
number of messages emitted – num_messages_emitted (count)
number of physical code lines – num_physical_code_lines (count)
The number of physical code lines in the project is the total number of code lines in all distinct files. Note that “distinct” is used with regard to the files whose lines are counted, not the content of the lines.
number of physical comment lines – num_physical_comment_lines (count)
The number of physical comment lines in the project is the total number of comment lines in all distinct files. Note that “distinct” is used with regard to the files whose lines are counted, not the content of the lines.
number of physical lines – num_physical_lines (count)
The number of physical lines in the project is the total number of lines in all distinct files. Note that “distinct” is used with regard to the files whose lines are counted, not the content of the lines.
number of recursive cycles – num_recursive_cycles (count)
The number of independent recursive cycles in the project call graph.
For example:
void f() { f(); } void g() { g(); }
contains two recursive cycles, and:
void a(), b(), c(); void a() { b(); } void b() { c(); } void c() { a(); }
contains one recursive cycle.
Recursive cycles must be independent:
void x(), y(), z(); void x() { y(); z(); } void y() { x(); } void z() { x(); }
contains only one recursive cycle.
This value will exclude recursive cycles in library code unless fml and flf are enabled.
number of supplemental messages emitted – num_supplemental_messages_emitted (count)
The number of messages emitted in the supplemental category. See 306 number of messages emitted for general information.
number of translation units – num_translation_units (count)
The number of translation units in a project.
number of warning messages emitted – num_warning_messages_emitted (count)
The number of messages emitted in the warning category. See 306 number of messages emitted for general information.
translation units – translation_units (collection)
This collection includes all of the translation units (modules) within the project.
main file – main_file (entity)
The file associated with the main file of this translation unit. This is the C or C++ file that was provided as an argument and processed as a module.
maximum include depth – max_include_depth (count)
The maximum depth of nested #include directives. A source file with no #include directives has a value of zero. A source file that includes only headers that do not themselves contain #include directives has a value of one. A source file that includes a header that itself includes a second header has a value of two, and so on.
number of distinct files – num_distinct_files (count)
The number of distinct files in a translation unit. Each source or header file is counted once even if it is utilized multiple times.
The identity of a single file referenced using different paths will generally be consolidated, but this is not necessarily possible if a single logical file is inconsistently referenced through link, junction, mount point, or network filesystem arrangements.
number of physical code lines – num_physical_code_lines (count)
The number of physical code lines in a translation unit is the total number of code lines in all distinct files. Note that “distinct” is used with regard to the files whose lines are counted, not the content of the lines.
number of physical comment lines – num_physical_comment_lines (count)
The number of physical comment lines in a translation unit is the total number of comment lines in all distinct files. Note that “distinct” is used with regard to the files whose lines are counted, not the content of the lines.
number of physical lines – num_physical_lines (count)
The number of physical lines in a translation unit is the total number of lines in all distinct files. Note that “distinct” is used with regard to the files whose lines are counted, not the content of the lines.
defined classes – classes (collection)
A collection of classes defined in a file. This includes all class definitions arising from any alternative preprocessing branches or macro definitions that could arise when a file is included multiple times.
defined functions – functions (collection)
A collection of functions defined in a file. This includes all function definitions arising from any alternative preprocessing branches or macro definitions that could arise when a file is included multiple times.
Halstead bugs – halstead_bugs (measure)
The Halstead bugs delivered, , of the original text of a single file before preprocessing.
Halstead difficulty – halstead_difficulty (measure)
The Halstead difficulty, , of the original text of a single file before preprocessing.
Halstead effort – halstead_effort (measure)
The Halstead effort, , of the original text of a single file before preprocessing.
Halstead length – halstead_length (measure)
The Halstead length, , of the original text of a single file before preprocessing.
Halstead level – halstead_level (measure)
The Halstead level, , of the original text of a single file before preprocessing.
Halstead time – halstead_time (measure)
The Halstead time, , of the original text of a single file before preprocessing.
Halstead vocabulary – halstead_vocabulary (measure)
The Halstead vocabulary, , of the original text of a single file before preprocessing.
Halstead volume – halstead_volume (measure)
The Halstead volume, , of the original text of a single file before preprocessing.
number of code lines – num_code_lines (count)
The number of code lines in a file prior to preprocessing.
number of comment lines – num_comment_lines (count)
The number of comment lines in a file prior to preprocessing.
number of empty lines – num_empty_lines (count)
The number of empty lines in a file prior to preprocessing.
number of include directives – num_include_directives (count)
The number of lines with the grammatical form of an include directive written within a file prior to preprocessing. This includes directives within conditionally disabled regions.
number of lines – num_lines (count)
The number of lines in a file prior to preprocessing.
average scope nesting depth – avg_scope_nesting_depth (measure)
The average nesting depth of compound statements enclosing each statement in a function. That is, the sum for each integral nesting level of the product of that nesting level and the number of statements with that nesting level, divided by the number of statements.
cyclomatic complexity – cyclomatic_complexity (measure)
The McCabe cyclomatic complexity of a function.
Halstead bugs – halstead_bugs (measure)
The Halstead bugs delivered, , of the text of a function.
Halstead difficulty – halstead_difficulty (measure)
The Halstead difficulty, , of the text of a function.
Halstead effort – halstead_effort (measure)
The Halstead effort, , of the text of a function.
Halstead length – halstead_length (measure)
The Halstead length, , of the text of a function.
Halstead level – halstead_level (measure)
The Halstead level, , of the text of a function.
Halstead time – halstead_time (measure)
The Halstead time, , of the text of a function.
Halstead vocabulary – halstead_vocabulary (measure)
The Halstead vocabulary, , of the text of a function.
Halstead volume – halstead_volume (measure)
The Halstead volume, , of the text of a function.
maximum cases in switch – max_cases_in_switch (count)
The maximum number of cases for a single switch statement within a function. The default label, if present, is included in the number of cases.
maximum catch handlers in try – max_catch_handlers_in_try (count)
The maximum number of catch handlers for a single try statement within a function.
maximum if else chain paths – max_if_else_chain_paths (count)
The maximum number of paths through any single if...else chain within a function. An if...else chain is a continuous structure of the form:
if (a) { /* ... */ } else if (b) { /* ... */ } else if (c) { /* ... */ } else { /* ... */ }
In this example, there are four paths as control may pass through a, b, c, or else. Note that if the final else is deleted, the number of paths is still four because control may pass through a, b, c, or none.
An isolated if:
if (a) { /* ... */ }
has two paths.
maximum loop nesting depth – max_loop_nesting_depth (count)
The maximum number of nested for, while, and do statements in a function. A single top-level loop statement yields a depth of 1.
maximum scope nesting depth – max_scope_nesting_depth (count)
The maximum depth of compound statement nesting in a function. The top-level compound statement of an empty function (or the top-level compound statements of a function-try-block) have a depth of 1.
NPATH – npath (measure)
The Nejmeh NPATH metric measures the exponential combinations of possible paths through a function. It is distinguished from cyclomatic complexity by its sensitivity to nesting.
number of backward goto statements – num_backward_goto_stmts (count)
The number of backward goto statements within a function. A backward goto statement is one where the destination label occurs before the goto statement.
This includes instances where a goto statement returns to an earlier label such as:
LABEL1: x += 5; if (x > 100) { break; } goto LABEL1;
as well as cases where the goto statement targets a label of which it is a sub-statement, e.g.:
LABEL2: goto LABEL2;
Uses of the non-standard “address of label” (void* p = &&LABEL;) and “computed goto” (goto *p;) language extensions are not counted.
number of called functions – num_called_functions (count)
The number of distinct functions defined within the analyzed project called by this function. Each function called at least once is only counted once regardless of how many different calls to it appear within the body of this function. This metric does not count called functions existing only as declarations that are never defined anywhere within the analyzed project.
number of calling functions – num_calling_functions (count)
The number of distinct functions that contain at least one call to this function. Each function containing at least one call to this function is only counted once regardless of how many different calls to this function appear within the body.
number of calls – num_calls (count)
The number of calls within a function definition. This includes all direct, explicit function calls written within the function body. This includes calls to member functions and calls through function pointers. It does not include invocations of constructors or destructors. Calls to overloaded operators are not included when invoked implicitly using operator syntax. Multiple distinct call sites that each call the same destination function are counted as separate calls.
number of catch handlers – num_catch_handlers (count)
The total number of catch handlers across all try statements within a function. This includes catch(...) handlers as well as any handlers of a function-try-block.
number of code lines – num_code_lines (count)
The number of code lines in a lexical function definition.
number of comment lines – num_comment_lines (count)
The number of comment lines in a lexical function definition.
number of control statements – num_control_stmts (count)
The number of a control statements within a function. A control statement refers to any of: do, if, switch, for, or while.
number of do statements – num_do_stmts (count)
The number of do statements within a function.
number of uses of else – num_else (count)
The number of uses of else within a function. All uses of else are counted (including uses in the else if pattern).
number of empty lines – num_empty_lines (count)
The number of empty lines in a lexical function definition.
number of expression statements – num_expr_stmts (count)
The number of expression statements within a function. This is a subset of Number of Statements that includes only those statements which are expressions (as opposed to declarations or control statements).
number of for statements – num_for_stmts (count)
The number of for statements within a function. All for statements are counted, including ranged-based for.
number of forward goto statements – num_forward_goto_stmts (count)
The number of forward goto statements within a function. A forward goto statement is one where the destination label occurs after the goto statement.
Uses of the non-standard “address of label” (void* p = &&LABEL;) and “computed goto” (goto *p;) language extensions are not counted.
number of global variables referenced – num_global_vars_referenced (count)
The number of distinct global variables referenced within a function. This counts the number of distinct variables that are referenced at least once without regard for the number of times a single distinct global variable may be repeatedly referenced.
number of if statements – num_if_stmts (count)
The number of if statements within a function. All if statements are counted (including those used in the else if pattern).
number of incoming calls – num_incoming_calls (count)
The number of distinct, direct calls to this function. This is the number of call sites where this function is called directly (not through an intermediate function pointer). Multiple written calls to this function in the body of a single function are each counted as separate call sites. Recursive call sites (calls made within this function itself) are included.
number of instance data members read – num_instance_data_members_read (count)
For a non-static member function, the number of distinct non-static instance data members read in the function body.
number of instance data members referenced – num_instance_data_members_referenced (count)
For a non-static member function, the number of distinct non-static instance data members referenced in the function body.
number of instance data members written – num_instance_data_members_written (count)
For a non-static member function, the number of distinct non-static instance data members written to in the function body.
number of jump statements – num_jump_stmts (count)
The number of return, break, continue, and goto statements within a function.
number of labels – num_labels (count)
The number of identifier labels within a function. This does not include case or default labels.
number of lines – num_lines (count)
The number of lines in a lexical function definition.
number of loops – num_loops (count)
The number of while, for, and do statements within a function.
number of monocarpic do statements – num_monocarpic_do_stmts (count)
The number of do...while statements that serve only to group statements because the controlling expression is false or 0. See message 717 .
number of mutable instance data members read – num_mutable_instance_data_members_read (count)
For a non-static member function, the number of distinct non-static mutable data members read in the function body.
number of mutable instance data members written – num_mutable_instance_data_members_written (count)
For a non-static member function, the number of distinct non-static mutable data members written to in the function body.
number of non-static calls with base other than this – num_non_static_calls_non_this (count)
The number of calls to non-static member functions on objects other than ‘this‘. This does not include constructors, destructors, or invocations through an overloaded operator.
number of non-static local variables – num_non_static_local_vars (count)
The number of non-static local variables defined within a function. This does not include parameters.
number of loops with facially non-terminating conditions – num_non_term_cond_loops (count)
The number of for, while, and do statements within a function that have constant conditions of 1 or true. This also includes for statements with the condition omitted.
These loops may or may not contain control flow to escape from an otherwise infinite loop.
number of parameters – num_parameters (count)
The number of parameters for a function. An ellipsis denoting variable arguments does not affect the value. The implicit object argument (this) of a member function is not counted. Parameters with default arguments are counted.
number of parameters with default arguments – num_parameters_with_default_args (count)
The number of parameters with default arguments for a function.
number of return statements – num_return_stmts (count)
The number of return statements within a function. The implicit return at the end of main or a function defined as returning void (or a catch clause of a function-try-block thereof) is not included. A return statement within a lamda body or a method of a local class is not attributed to the enclosing function.
number of selection statements – num_selection_stmts (count)
The number of if and switch statements within a function.
number of static local variables – num_static_local_vars (count)
The number of static local variables defined within a function. This includes thread_local variables.
number of statements – num_stmts (count)
The number of statements within a function. Every statement within the body of any compound statement is counted. Two important implications of this methodology are:
number of switch cases – num_switch_cases (count)
The total number of case and default cases across all switch statements within a function.
number of switch statements – num_switch_stmts (count)
The number of switch statements within a function.
number of switch statements without default – num_switch_stmts_without_default (count)
The number of switch statements without a default within a function. All switch statements without a written default are counted. A switch statement that covers its entire integral or enumeration type domain with case labels but has no written default will still be counted.
number of throw exprs – num_throw_exprs (count)
The number of throw expressions within a function.
number of try statements – num_try_stmts (count)
The number of try statements within a function. This includes a function-try-block.
number of while statements – num_while_stmts (count)
The number of while statements within a function. This does not include the appearance of the keyword while in the syntax of a do statement condition.
parent class – parent_class (entity)
For a non-static member function, parent_class refers to the class of which it is a member.
immediate bases – immediate_bases (collection)
This collection includes all of the immediate base classes of a class. Immediate base classes are those that the class inherits from directly. If X inherits from Y and Y inherits from Z, then Y is an immediate base of X and Z is an immediate base of Y, but Z is not an immediate base of X.
To see how this can be used recursively to define custom metrics that consider an entire base class hierarchy, refer to 10.7.1 Levels of Inheritance to Most Distant Base .
immediate children – immediate_children (collection)
This collection includes all of the immediate derived (child) classes of a class. Immediate derived classes are those that inherit from the class directly. If X inherits from Y and Y inherits from Z, then X is an immediate child of Y and Y is an immediate child of Z, but X is not an immediate child of Z.
To see how this can be used recursively to define custom metrics that consider an entire derived class hierarchy, refer to 10.7.1 Depth of Inheritance Tree .
instance data implementation partition – instance_data_implementation_partition (measure)
The instance data implementation partition measure conveys the independence or entanglement of groups of non-static data members. It is scaled from 0 to 100 and is calculated based on the relative difference of the number of independent groups of inseparable non-static data members and the total number of non-static data members. All non-static data members referenced within any single member function are inseparable, and inseparability is transitive. For example, in:
class X { public: int f1() { return a + b; } void f2() { b = c; } void f3() { d = 0; } int f4() { return e ? f : g; } private: int a; int b; int c; int d; int e; int f; int g; };
The independent, inseparable groups are:
a, b, c
d
e, f, g
With seven non-static data members () and three inseparable groups (), the measure evaluates to .
If a class only referenced at most one of its non-static data members per member function then the measure would be . If a class had a single member function that referenced all of its non-static data members, the measure would be . The measure of a typical class illustrates where it falls between these two extremes.
Note that non-static data members that are not referenced in any of the considered non-static member functions are not included in nor . References within constructors, destructors, and assignment operators are ignored.
lack of cohesion in methods – lack_of_cohesion_in_methods (measure)
Lack of cohesion in methods is the Chidamber-Kemerer LCOM metric. Each combination of two methods is classified based on whether they access any common instance data members, and the value of this metric is the number of such pairs that do not minus the number of such pairs that do. Negative values are clamped to zero.
non-static member functions – non_static_member_functions (collection)
A collection of non-static member functions in a class.
number of code lines – num_code_lines (count)
The number of code lines in a lexical class definition.
number of comment lines – num_comment_lines (count)
The number of comment lines in a lexical class definition.
number of const member functions – num_const_member_functions (count)
The number of non-static member functions declared with the const qualifier. Member functions of base classes are not included.
number of empty lines – num_empty_lines (count)
The number of empty lines in a lexical class definition.
number of inline definition member functions – num_inline_def_member_functions (count)
The number of non-static member functions with inline definitions provided within the class definition. This includes member functions defined within the class definition even without an explicit use of the inline keyword. Member functions of base classes are not included. User-declared constructors and destructors are included, while special member functions implicitly declared by the compiler are not.
number of lines – num_lines (count)
The number of lines in a lexical class definition.
number of mutable data members – num_mutable_data_members (count)
The number of mutable non-static data members. Data members of base classes are not included.
number of non-static data members – num_non_static_data_members (count)
The number of non-static data members within a class. Data members inherited from base classes are not included.
number of non-static member functions – num_non_static_member_functions (count)
The number of non-static member functions in a class. Member functions of base classes are not included. User-declared constructors and destructors are included, while special member functions implicitly declared by the compiler are not.
number of pointer data members – num_pointer_data_members (count)
The number of non-static data members of pointer type. A data member of type reference to pointer is not counted as a pointer. Data members of base classes are not included.
number of private data members – num_private_data_members (count)
The number of non-static data members with private access. Data members of base classes are not included.
number of private member functions – num_private_member_functions (count)
The number of non-static member functions with private access. Member functions of base classes are not included. User-declared constructors and destructors are included, while special member functions implicitly declared by the compiler are not.
number of protected data members – num_protected_data_members (count)
The number of non-static data members with protected access. Data members of base classes are not included.
number of protected member functions – num_protected_member_functions (count)
The number of non-static member functions with protected access. Member functions of base classes are not included. User-declared constructors and destructors are included, while special member functions implicitly declared by the compiler are not.
number of public data members – num_public_data_members (count)
The number of non-static data members with public access. Data members of base classes are not included.
number of public member functions – num_public_member_functions (count)
The number of non-static member functions with public access. Member functions of base classes are not included. User-declared constructors and destructors are included, while special member functions implicitly declared by the compiler are not.
number of public virtual member functions – num_public_virtual_member_functions (count)
The number of virtual non-static member functions with public access. Member functions of base classes are not included. Public virtual destructors are included.
number of pure virtual member functions – num_pure_virtual_member_functions (count)
The number of pure virtual non-static member functions. Pure virtual functions for which an out of class definition is provided are included. Member functions of base classes are not included.
number of reference data members – num_reference_data_members (count)
The number of non-static data members of reference type. Data members of base classes are not included.
number of virtual member functions – num_virtual_member_functions (count)
The number of virtual non-static member functions. Member functions of base classes are not included. Virtual destructors are included.
response for class – response_for_class (measure)
Response for class is the Chidamber-Kemerer RFC metric. This is total number of distinct functions in a set containing all methods of the class and all functions directly called by methods of the class.
Constructors, destructors, assignment operators, and implicit special member functions are not considered to be methods. Invocations of overloaded operators or destructors within methods do not contribute to the response set.
Project hosts provide dynamic metrics of the form num_message_N_emitted where N is a message number emitted at least once during analysis. For example, if two instances of message 9001 are emitted, then the dynamic metric project.num_message_9001_emitted will have a value of 2 on the report. Dynamic metrics are not available in metric checks.
The flexibility of metric expressions provides wide latitude to derive ratios, averages, and entirely new metrics from the data listed in the previous section. The definitions of common derived metrics are provided as a sample of what can be accomplished with metric options.
levels of inheritance to most distant base – levels_to_base (count)
+metric(class.levels_to_base = count(class.immediate_bases) == 0 ? 0 : 1 + max(class.immediate_bases, class.levels_to_base))
depth of inheritance tree – depth_of_inheritance (count)
+metric(class.depth_of_inheritance = count(class.immediate_children) == 0 ? 0 : 1 + max(class.immediate_children, class.depth_of_inheritance))
percentage of non-static member functions with public access – public_member_function_percentage (measure)
+metric(class.public_member_function_percentage = class.num_public_member_functions / class.num_non_static_member_functions)
weighted methods per class – weighted_methods_per_class (measure)
This metric can be defined in terms of the sum of a chosen member function metric such as cyclomatic complexity or NPATH. For example, one possible choice is: +metric(class.weighted_methods_per_class = sum(class.non_static_member_functions, function.cyclomatic_complexity))