2.3. Exclude, Suppress and Justify Analysis Results

2.3.1. Exclude files from the Analysis

If you want to restrict some analysis to certain parts of the code, you can choose among different options:

  • When using axivion_ci or axivion_analysis, you can configure the option global_excludes on the Analysis root node. This will suppress all violations where the filename matches one of the configured glob patterns. This can be used, for example, to suppress all messages in 3rd-party code. System headers are excluded by default.

  • You can use each rule’s option excludes to define such exclusions for selected rules only. There is also the option includes to limit rules to a provided whitelist of directories. This can be used, for example, to apply different rules to different parts of the code, e.g. if you want to run only a subset of MISRA® checks on generated code.

  • If you want to run some rule with different settings for different parts of the code, you can create copies of the rule and configure them independently; also use the above-mentioned options includes/excludes to limit these copies to different code parts. This can be used, for example, to apply a rule to both generated and hand-written code, but with different (maybe relaxed) settings on the generated code.

  • Several rules report different kinds of messages. If you want to suppress a specific kind of message (but continue to see all others), you can disable the message in the graphical configuration interface under the option msg of the rule. You will see the messages generated by the rule there, and for each such message you will find the nested option disabled that you can set to True in order to suppress this specific kind of message. If you only want to change the wording of the message, you can do so here as well by setting the option text of the message to the desired text.

  • To disable individual issues, you can place special code annotations (markup comments) in the code. Some code annotations can also be specified in configuration files if you want to avoid modifying the code. Code annotations are described in Justifications and Suppressions with Code Annotations. You can also use this feature to only mark affected issues as suppressed, but still import them into the database, so you can inspect them in the dashboard or include them in reports.

2.3.2. Justifications and Suppressions with Code Annotations

You can place special comments and pragmas in the source code in order to suppress the reporting of specific issues in the dashboard, or to attach some justification (permit, annotation) to reported issues. These special comments are called control comments or commentary activators. The following features are supported:

  • Suppressing issues (both with in-code annotations and from configuration)

  • Adding justifications to issues (both with in-code annotations and from configuration)

  • Checking for presence of a justification

  • Checking the contents of a justification

  • Showing suppressed issues in the dashboard

  • Respecting code annotations created for other tools

  • Using your own syntax for the code annotations

  • Affecting different code portions with different code annotations

  • Selecting affected issues based on different issue properties

  • Reporting stale (unused) code annotations

This chapter helps you to get started with the code annotation feature. It shows you how to use the default suppressions and justifications at:

As well as how to:

And some example uses.

2.3.2.1. Suppressions and Justifications at Line level

To suppress and justify issues in specific lines in the source code, proceed as follows:

  1. In the graphical configuration interface, navigate to Analysis/AnalysisControl/CodeAnnotations/Suppressions/LineBasedSuppressions/NextLine and activate that rule.

  2. In your source code, in the line immediately preceding the line in which you want to suppress an issue, write a corresponding comment, for example:

// AXIVION Next Line MisraC2012-20.5: AUTOSAR permitted

This comment would suppress issues from rule MisraC2012-20.5 in the next line. Additionally, this comment provides a justification for the suppression, namely the text behind the colon.

If you instead prefer to write the comment in the same line in which the issue is reported or in the next one, then simply activate rule SameLine or PreviousLine instead of NextLine.

Note

If you intend to use 2 NextLine suppressions in the following way:

// AXIVION Next Line MisraC2012-1.2: justification
// AXIVION Next Line MisraC2012-1.3: justification
<code here>

then you should instead use NextCodeLine as the <code here> example above would only have MisraC2012-1.3 suppresssed.

2.3.2.2. Suppressions and Justifications at Region level

There are multiple ways to suppress sections of code. The pre-configured suppression formats that Axivion provides and which will be explained in this chapter are:

Each of these formats serves different needs and provides flexibility in how you manage suppressions across multiple lines of code. Let us look at how to configure and use each of these formats.

Enable/Disable Suppressions

To suppress and justify issues in sections of the source code with EnableDisable, proceed as follows:

  1. In the graphical configuration interface, navigate to Analysis/AnalysisControl/CodeAnnotations/Suppressions/EnableDisable and activate that rule.

  2. In your source code, write a comment that disables the reporting of issues in the following lines, for example:

    // AXIVION DISABLE Style MisraC2012-20.5: AUTOSAR permitted
    

    This comment would suppress issues of kind Stylechecks from rule MisraC2012-20.5 in the following lines. Additionally, this comment provides a justification for the suppression, namely the text after the colon.

  3. To re-enable issue reporting, write a comment that enables the reporting of issues in the following lines, for example:

    // AXIVION ENABLE Style MisraC2012-20.5
    

    This comment would re-enable issues from rule MisraC2012-20.5 in the following lines.

    Note

    The enable comment can also be used to re-enable all issues that were disabled by a previous disable comment, by not specifying a rule name.

If you wish to to have some files with a rule suppressed by default, but that can still be enabled in the file itself, you can additionally follow the steps below:

  1. In the graphical configuration interface, navigate to AnalysisControl/CodeAnnotations/ExternalCodeAnnotations/InitialExternalAnnotations and activate that rule.

  2. That rule on the right-hand side of the GUI has an option initial_comments in which you can write the code annotations that should apply to issues in selected files. Double-click on that option to change its value and create new entries, for example:

    • Filename pattern *.inc and value AXIVION DISABLE

    • Filename pattern *MemMap*.h and values

    AXIVION DISABLE Style MisraC2012-20.5: AUTOSAR permitted
    AXIVION DISABLE STYLE MisraC-1.1 : nesting level of #if is not in scope of memmap (AUTOSAR)
    

    These comments would suppress the rules mentioned in the comment (MisraC2012-20.5 resp. MisraC-1.1) in all files matching the given globbing patterns (extension .inc for the first case and header filenames containing the substring MemMap for the second). Additionally, these comments provide a justification for the suppressions, namely the text after the colon.

    Note

    These examples used the keyword Style to restrict the comment to stylecheck issues. In general, when a format allows the selection of issue kind like this, you can use the following keywords:

    • Style or Stylecheck for stylecheck issues

    • Metric or Metrics for metric issues

    • Architecture for architecture issues

    • Clone or Clones for clone issues

    • Cycle or Cycles for cycle issues

    • Dead or DeadCode for dead code issues

    • All for all issue kinds

Construct-Based Suppressions

  1. In the graphical configuration interface, navigate to Analysis/AnalysisControl/CodeAnnotations/Suppressions/ConstructBasedSuppressions and activate one of the rules bellow.

  2. The construct-based suppressions allow you to suppress issues in specific code constructs (statements/declarations). The following types are available:

    • NextCodeline: Suppresses issues in the first line of the next statement, declaration, #line or #pragma

    • NextConstruct: Suppresses issues in the next construct (statement/declaration)

    • PreviousConstruct: Suppresses issues in the previous construct

    • SameConstruct: Suppresses issues in the same construct

    For example, using Next Construct:

    /* AXIVION Next Construct MisraC2012-15.4: Suppresses the entire if statement */
    if (condition) {
       // This line is suppressed
       doSomething();
       // This line is suppressed too
    }
    

    The format is similar for all types, just replace Next Construct with the appropriate type.

Routine-Based Suppressions

  1. In the graphical configuration interface, navigate to Analysis/AnalysisControl/CodeAnnotations/Suppressions/RoutineBasedSuppressions and activate one of the rules bellow.

  2. Routine-based suppressions allow you to suppress issues in entire functions. The following types are available:

    • NextRoutine: Suppresses issues in the next routine

    • PreviousRoutine: Suppresses issues in the previous routine

    • SameRoutine: Suppresses issues in the current routine

    • SelectedRoutine: Suppresses issues in a specifically named routine

    For example, using Selected Routine:

    /* AXIVION Selected Routine MyFunction MisraC2012-15.4: Suppresses the entire routine */
    void MyFunction(void) {
        // This line is suppressed
        doSomething();
        // This line is suppressed too
        doSomethingElse();
    }
    

    The format is similar for all types (except Selected Routine which requires the routine name), just replace Selected Routine MyFunction with the appropriate type.

File-Wide Suppressions

  1. In the graphical configuration interface, navigate to Analysis/AnalysisControl/CodeAnnotations/Suppressions/FileWide and activate that rule.

  2. FileWide suppressions allow you to suppress issues in an entire source file by placing a single comment anywhere in the file. For example:

    /* AXIVION FILE Style MisraC2012-20.1: my justification */
    

    This comment would suppress all issues from rule MisraC2012-20.1 in the entire file. Additionally, this comment provides a justification for the suppression, namely the text after the colon.

2.3.2.3. Suppressions and Justifications at Project level

To suppress and justify issues in the complete project, proceed as follows:

  1. In the graphical configuration interface, navigate to Analysis/AnalysisControl/CodeAnnotations/Suppressions/ProjectWide and activate that rule.

  2. ProjectWide suppressions allow you to suppress issues in the entire project by placing a single comment anywhere in the analyzed code. For example:

    /* AXIVION EXCEPTION Style MisraC2012-20.1 *MemMap*.h: my justification */
    

    This comment would suppress all issues from rule MisraC2012-20.1 in the entire project, where the file name matches the pattern *MemMap*.h. Additionally, this comment provides a justification for the suppression, namely the text after the colon.

  3. If you do not want to place the comment randomly in the code, you can also use an additional rule that allows Axivion Suite to internally add the comment to the project. In the graphical configuration interface, navigate to AnalysisControl/CodeAnnotations/ExternalCodeAnnotations/ProjectWideExternalAnnotations and activate that rule.

  4. That rule on the right-hand side of the GUI has an option project_comments in which you can write the code annotations that should apply to all of the analyzed code. Double-click on that option to change its value and create new entries, for example:

    AXIVION EXCEPTION STYLE MisraC2012-20.1 \*MemMap\*.h : AUTOSAR permitted
    AXIVION EXCEPTION STYLE MisraC-19.6 \*START_SEC\* : THIS IS PERMITTED for Memmap defines
    

    These comments would suppress the rules mentioned in the comment (MisraC2012-20.1 resp. MisraC-19.6), but only those cases where the reported entity matches the given name pattern (\*MemMap\*.h resp. \*START_SEC\*). Additionally, these comments provide a justification for the suppressions, namely the text behind the colon.

2.3.2.4. Suppressed Issues in Reports and in the Dashboard

By default, issues suppressed by such code annotation comments will not be reported. In case you need to know about these suppressed issues (e.g., for a complete MISRA® audit report), you can import them into the database. This can be done by setting option /Results/Database/import_suppressed_issues to True in the graphical configuration interface. With this option, suppressed issues are

  • imported into the database,

  • shown in the dashboard,

  • and available for reports.

Alternatively, you can also select comment formats which just add justifications to issues, without suppressing them. You will find them in the graphical configuration interface inside the rule group AnalysisControl/CodeAnnotations/NonSuppressingIssueComments. Therefore you can distinguish these scenarios:

  • Issue is not suppressed and has no justification (e.g. an issue in your code that still needs inspection)

  • Issue is not suppressed but has a justification (e.g. an issue in your code that was already inspected and dealt with in form of a deviation)

  • Issue is suppressed and has no justification (e.g. an issue in third-party code which was not inspected)

  • Issue is suppressed but has a justification (e.g. an issue in third-party code which was inspected)

The last two cases are only shown when the above-mentioned flag is set, so you can choose whether you want to see issues in third-party code or not.

2.3.2.5. Defining a code annotation format

The above examples show simple uses of the code annotation feature. You can start with them to get familiar with the topic. In every case you have to select the comment format(s) that you want to support in your code annotation comments. Several such formats are already included in the standard installation so that it is sufficient to just activate them as needed. They differ, for example, in the comment syntax or the code region being affected.

But if you want to enable more advanced use-cases, you need to tell the Axivion Suite the format of the comments that should be recognized as special code annotations. The available comment formats can be selected in the graphical configuration interface under AnalysisControl/CodeAnnotations. There, subcategory Suppressions provides predefined formats for comments that should suppress issues (and optionally do more, like adding a suppression), while subcategory NonSuppressingIssueComments provides predefined formats that only add justifications without suppressing.

Choose the format(s) that match your needs, and if necessary, adapt the options to e.g. use your company’s name instead of Axivion in the comments. As with other configuration items, you can copy and rename such formats to create independent copies that have independent configurations. This can be used to design your own comment formats instead of changing one of the predefined formats.

A Code Annotation’s format field expects a regular expression (regex) pattern that can contain capture groups. A capture group is created by enclosing a part of the pattern in parentheses ().

Example using default settings of Selected Routine regex with 3 groups:

\s*AXIVION\s+Selected\s+Routine\s+(\S*)\s+([^:]*)(:.*)?

Group 0  - The full matched string
Group 1  - (\S*)
Group 2  - ([^:]*)
Group 3  - (:.*)?

Then, for each option of the suppression’s rule, such as entity, kind, justification, rule etc etc, you can select it to either:

  • Not apply to this suppression, by setting the value to None

  • To apply with a static value, which is selected in axivion_config, by setting the value to the desired const

  • To apply and have a dynamic value that will depend on the value set, and on one of the regex groups of the suppression comment.

As an example, for the default values that are set on the Selected Routine example from above, we have the following options configured:

  • Action - Statically set to SUPPRESS

  • Entity - does not apply

  • Justification - Due to value being set to AFTER_COLON it will dynamically catch whatever comes in the 3rd group of the regex - (:.*)?

  • Kind - Statically set to STYLE

  • Macro - does not apply

  • Message - does not apply

  • Message_key - does not apply

  • Rule - Due to value being set to AXIVION_NAMES it will dynamically catch whatever rule comes in the 2nd group of the regex - ([^:]*)

  • Scope - Due to value being set to ROUTINE_BY_NAME it will dynamically catch whatever routine comes in the 1st group of the regex - (S*)

To understand what each value expects, please read the descriptiom of it in the UI of axivion_config.

To suppress architecture violations, you can access the rule name of an issue as for style check issues. Additionally, the message_key of the comment can be used to limit affected architecture violations by the type of the reflexion edge (e.g., Divergence), and the message can be used to limit by the type of the causing edge (e.g., Static_Call).

Python configuration and custom parser

Some options may not (yet) be supported in the graphical configuration interface; in that case, add a Python layer to your configuration and in that file set the remaining properties (see configuration system).

This is especially the case if for some option you need a different approach for parsing the required field information from a comment than those being available for selection. In such a case, select the option CUSTOM_PARSER as the option’s value and on the Python side set the attribute custom_parser to your Python function.

The signature of such a custom parser should be def my_parser(comment, text) or def my_parser(comment, text, issue) where the first two parameters denote a representation of the full comment and the string that matched the specified group in the format’s regular expression. The optional third parameter provides details on the issue for which the comment is checked (i.e., issue kind and rule name).

Note: Because the Axivion Suite analysis is distributed over multiple processes, a custom parser using the three-parameter form might be serialized (using Python pickle) and deserialized in another process. Effectively, this means you can only use top-level Python functions, not lambdas.

2.3.2.6. Code annotations outside source files

Besides special comments in the code, the Axivion Suite also supports code annotations from within the configuration. This can be useful if

  • you do not want to touch the source files,

  • if the files are generated and thus changes would be lost,

  • if you want to affect issues in line 1 of a file,

  • or if you want to suppress certain issues project-wide.

For project-wide code annotations, use the graphical configuration interface and select the format AnalysisControl/CodeAnnotations/Suppressions/ProjectWide as well as AnalysisControl/CodeAnnotations/ExternalCodeAnnotations/ProjectWideExternalAnnotations. This rule has an option project_comments in which you can write the code annotations that should apply to all of the analyzed code. The annotations here have to match the format AnalysisControl/CodeAnnotations/Suppressions/ProjectWide or any other selected format with the scope Project. Again, adapt the syntax of the project-wide comment format to your needs or create copies of the format as necessary.

To add other code annotations from within the configuration, select AnalysisControl/CodeAnnotations/ExternalCodeAnnotations/InitialExternalAnnotations. The code annotations configured here in option initial_comments are considered like comments at the very beginning of each affected file and should match one of your selected comment formats.

2.3.2.7. Checking justifications

The justifications which can be attached to issues by code annotations are free-form text. However, you may want to impose certain rules for these strings, e.g. that they have to refer to a Misra permit. This can be done by setting a custom Python function as value of the option justification_checker which is present at all rules generating issues (each such rule can have a different callback). As this must be a Python function, it can only be configured in a Python configuration layer. This callback function can update the issue, for example to remove the disabled-Flag when the justification does not match the required format. An example using this feature (it forbids suppressing issues without providing a justification):

def disallow_unjustified_deviations(issue):
   # forbid suppressing without justification
   if issue.disabled:
      if not issue.justification:
         issue.disabled = False

import axivion.config
analysis = axivion.config.get_analysis()
for rule_name in analysis.get_active_rules():
   if hasattr(analysis[rule_name], 'justification_checker'):
      analysis[rule_name].justification_checker = disallow_unjustified_deviations

2.3.2.8. Example Uses

Besides standard issue suppressing and justification, the flexibility of scriptable code annotation formats also allows more sophisticated uses. The examples provided here leverage the ability to map the rule identification as written in the comment to something else.

2.3.2.9. Migrating from one coding standard to another

When your organization switches from an older standard to a newer one, rule names may have changed in those standards although the rules still cover similar or identical aspects. This means you have to update all code annotations to replace the old name with the new one. For example, when migrating from Misra-C:2004 to Misra-C:2012, an annotation suppressing MisraC-2.1 has to be changed to mention MisraC2012Directive-4.3 instead.

To simplify this migration, a comment format can be used that accepts the old (Misra-C:2004) rule names, but returns corresponding new (Misra-C:2012) rule names as rule selection. This would allow to use the old code annotations for cases where the new standard has a counterpart. To define a suitable comment format, set its rule value to CUSTOM_PARSER and, in a Python configuration file, set the rule custom parser field to a Python function that returns the desired list of Axivion rule names:

def rule_parser_for_migration(comment, text):
   # text is the  part of the comment denoting the rule (as written in the comment)
   # now map those names to the desired new rule names
   updated_rules = [...]
   return updated_rules

import axivion.config
from axivion.config import code_annotations
analysis = axivion.config.get_analysis()
analysis['YourCommentFormat'].rule.value = code_annotations.Rule.CUSTOM_PARSER
analysis['YourCommentFormat'].rule.custom_parser = rule_parser_for_migration

You can also use standard-independent, generic rule names and map those to actual rule names from either or both standards.

2.3.2.10. Migrating from lint and other tools

If you previously used other static code analysis tools (like lint), you may already have code annotations for these tools. Instead of rewriting them you can also define a comment format that syntactically accepts the format of the other tool, but returns Axivion rule names instead. Such a mapping between rule names can be done with CSV files, for example, that are read in the Python function listed as rule-selection parser.

2.3.2.11. Using multiple analysis tools

If you use multiple analysis tools (for example, Axivion, lint, and self-made checkers), you can import the results of the other tools into the Axivion database using the analysis rules ImportExternalAnalysisOutput or :code`Generic-ImportCSV`. They will be imported like style violations using as rule name what the CSV file provides in column errno.

To avoid having to write multiple code annotations - one per tool - for the same issue, you can also come up with your own general rule names and map those in the rule-selection parser to actual rule names for the different tools (the mapping can return a list of rules for a single code annotation). For example, your general rule name could be mapped to

['MisraC-2.1', 'lint-123', 'MyCompany-ABC']

As the code annotations are also used for imported style violations, you can in this way suppress or justify third-party messages. Just ensure the rule names returned by your rule-selection parser match the errno field from the CSV file. Then you have a setup where all tools can be executed with the combined set of messages being displayed in a single dashboard, and being suppressed and justified in a common way without duplicating code annotations.

Referring to Permits

In safety-critical projects a suppression for an issue usually requires some kind of permit to do so. This reference to a permit can be put into the justification of a code annotation, and the justification_checker feature can be used to ensure that all suppressions refer to an appropriate permit (see section Checking justifications).

This example creates a comment format that allows comments like this one:

Example code with comment referring to permits
#define _MY_MACRO // Permit 21.1-DPS211 Permit 17.0.1-DPS1701

Here we assume that the piece of code is checked by both MisraC2012-21.1 and MisraC++-17.0.1 (e.g. a header in a mixed C/C++ project). Both these rules report a violation in the given line, and the comment should suppress those and refer to a different permit per rule.

For this comment format, we start by copying the existing format SameLine and give the copy its own name, for example Misra Permits. This new rule is then activated, and a few options of it must be changed. That can be done in the graphical configuration interface, but we show it here in Python, as the subsequent configuration parts require Python anyway:

Python configuration layer for Misra Permits comment format
import re
import axivion.config
from axivion.config import code_annotations
analysis = axivion.config.get_analysis()

format_permits = analysis.copy('SameLine', 'Misra Permits')
analysis.activate('Misra Permits')

# .. utility functions described below, have to be inserted here ..

format_permits.format = '(\s*Permit\s+(\d+\.\d+\.*\d*)-DPS(\d*))+'
format_permits.rule.group = 0
format_permits.rule.value = code_annotations.Rule.CUSTOM_PARSER
format_permits.rule.custom_parser = extract_rulename
format_permits.justification.group = 0
format_permits.justification.value = code_annotations.Justification.CUSTOM_PARSER
format_permits.justification.custom_parser = extract_permit

This example uses custom parser functions which can only be defined in Python. They are used here to extract the rule name from the comment, and to extract the appropriate permit. Let us first look at the utility function to extract the rule name:

Custom Python parser to extract the rulename from the comment
def extract_rulename(comment, text):
'''Returns the Axivion rule name(s) to disable based on the comment.
   The result can be a globbing pattern.
   The text argument in this case is the complete string as this is the only way
   to access all subgroups in all repetitions.'''

   pattern = r'\s*Permit\s+(\d+\.\d+\.*\d*)-DPS(\d*)\s*'
   rules = []
   for match in re.findall(pattern, text):
      rulenumber = match[0]
      if rulenumber.count('.') == 2:
            rulename = 'MisraC++-%s' % rulenumber
      else:
            rulename = 'MisraC2012-%s' % rulenumber
      rules.append(rulename)
   return rules

This function is used to return the proper rule names to look for when checking whether an issue is affected by the comment. In our example, the comment is Permit 21.1-DPS211 Permit 17.0.1-DPS1701 and the function returns the rule names ['MisraC++-17.0.1', 'MisraC2012-21.1'].

For the associated permit, we need another custom parser, and this function requires the issue details in order to match the issue with the appropriate part of the comment. The Python function looks like this:

Custom Python parser to extract the permit for an issue
def extract_permit(comment, text, issue):
'''Returns the justification to use for suppressing the message.
   The input text will be the complete string as this is the only way
   to access all subgroups in all repetitions.'''

   assert issue.kind == code_annotations.IssueKind.STYLE
   rule_name = issue.rule_name
   pattern = r'\s*Permit\s+(\d+\.\d+\.*\d*)-DPS(\d*)\s*'
   permits = []
   for match in re.findall(pattern, text):
      rulenumber = match[0]
      if rulenumber.count('.') == 2:
            this_rulename = 'MisraC++-%s' % rulenumber
      else:
            this_rulename = 'MisraC2012-%s' % rulenumber
      if this_rulename == rule_name:
            permit = 'Permit %s-DPS%s' % (match[0], match[1])
            permits.append(permit)
   result = '; '.join(permits)
   return result

This function returns the permit given in the comment for the rule name of the issue. For example, for the MisraC2012-21.1 issue, it returns Permit 21.1-DPS211, and that will be used as the justification of the suppressed issue.

The justification_checker feature can now be used to ensure that all suppressions refer to an appropriate permit (see section Checking justifications).