Monday, September 5, 2011

Suppressing messages for particular files in FlexeLint

A commonly asked question regarding Flexelint is how one can suppress some or all messages for a particular file.  Although there isn't an individual option to accompish this, like there is for suppressing messages for specific symbols, types, etc., there are several ways to achieve the same effect.

A Note about the -efile option

Although there is a -efile option, it doesn't work to suppress messages within a particular file but rather messages that are about a particular file.  For example, Error 7 - "Unable to open include file 'FileName'" includes the name of the file in its message, -efile could be used to suppress this message based on the filename inside but cannot be used to suppress messages that do not include the parameterized filename as part of the message (and most do not).

Selective Linting

If you wish to suppress all messages for a particular file, the most obvious solution is to exclude it from the list of files being linted.  The downside with this approach is that you lose the benefits of multi-module linting for the file(s) in question as well as missing out on any potentially serious errors within the file.  This "selective linting" method is not recommended for these reasons.

Options for individual files

A better approach is to use the -w# option to change the warning level for just the file in question.  FlexeLint processes options in the order in which they appear so if you ran lint as:

flint file1.c file2.c -w1 file3.c

the -w1 option would only be in effect for file3.c  A similar approach can be used for individual message suppression:

flint file1.c file2.c -e438 -e529 file3.c

It usually makes sense to create a project file that contains the names of the modules to lint instead of having to specify them on the command lint each time.  An equivalent project.lnt file would look like:
    file1.c
    file2.c
    -e438 -e529
    file3.c
You can then run lint like so:

flint project.lnt

There is subtle problem with this approach.  By default, the -w and -e options will remain in effect for all future files linted.  If you later add files to the end of the project list, the suppressions will remain in effect, perhaps inadvertantly, for those files as well.  You may think that adding +e438 +e529 after file3.c would address the issue:
    file1.c
    file2.c
    -e438 -e529
    file3.c
    +e438 +e529
    file4.c
    ...
but the problem with this approach is that the +e/-e options work as boolean flags and as such, messages 438 and 529 will be enabled for future files regardless of whether they were originally enabled or not.  The proper way to handle this is to use the -save/-restore options:
    file1.c
    file2.c
    -save -e438 -e529
    file3.c
    -restore
    file4.c
    ...
which will only enable the messages if they were enabled when the -save option was encountered.  The same approach can be used with -w#.

Using -efunc and -esym

Another strategy is to use the -efunc and/or -esym options.  This has the benefit of limiting the effect of the suppressions to a smaller area which is a less blunt approach.

The -efunc option can suppress messages within a specific function.
The -esym option can suppress messages for specific symbols as well as several other parameterizations when using the +fsn flag.

For example, many MISRA C messages are grouped together under Note 960 but you may want to only suppress a small number of MISRA rules for a given file.  The way to do this is with -esym(960, <rule-num>), for example:
    file1.c
    file2.c
    -esym(960, 10.1)
    file3.c
    +esym(960, 10.1)
    file4.c
    ...
will have the effect of suppressing MISRA rule 10.1 for file3.c.  Since -save/-restore do not work with the esym options we can't use them here.  Instead we take advantage of the fact that identical esym options with opposite signs cancel each other out so despite previous and future esym options, the suppression will be in effect for file.3 without affecting other files.

If you have a large number of functions or symbols in the file that you wish to suppress message for though, this can be tedious.  Additionally, if you suppress messages for names that are used in other files, you will want to make sure to provide equivalent +esym options as descibed above to prevent the suppressions from spilling into other files.  Of course, if you are trying to suppress messages that aren't parameterized in a way that -efunc/-esym can match then this approach won't work.

Using Library Files

Lastly note that FlexeLint supports a different class of suppression options for what is calls "library" files which typically includes header files provided by the implementation (compiler and standard library) and third-party source and header files.  In is usually desired to inhibit a larger number of warnings for such files since they typically cannot be modified.  If you are trying to suppress messages for such files, a better approach is probably to use the existing facilities to mark these files as library files.

3 comments:

  1. I am looking for a solution for the following problem:
    - there is a macro definition in osFile.h which violates MISRA rule 10.1
    - I use this macro in sourceFile.c which I want to check with PCLint
    - I would like to filter out all messages from soureFile.c which are caused by the definition in osFile.h

    Obviously PCLint does not check where the macro definition comes from. It just replaces the code in the source file and finds a violation. Therefore, the +libdir option does not help to suppress the message. Any idea? Thank you!

    ReplyDelete
  2. Hi TK,

    Did you try using -emacro()? MISRA Rule 10.1 is enforced via three different PC-Lint messages: 524, 653, and 960. After you determine which message is being used to report your specific violation, try using -emacro to suppress the messages. For example, if the message is 960 and the name of the macro is MY_MACRO, try using -emacro(960, MY_MACRO).

    ReplyDelete
  3. Thanks, the following suppresses the message:
    -emacro( (960), MY_MACRO ) or
    -emacro( (*), MY_MACRO )

    Parentheses are mandatory!

    ReplyDelete