diff --git a/c/misra/src/rules/RULE-2-5/UnusedMacroDeclaration.ql b/c/misra/src/rules/RULE-2-5/UnusedMacroDeclaration.ql index b7ea9f64de..2b5a8e8c1d 100644 --- a/c/misra/src/rules/RULE-2-5/UnusedMacroDeclaration.ql +++ b/c/misra/src/rules/RULE-2-5/UnusedMacroDeclaration.ql @@ -19,7 +19,18 @@ import codingstandards.c.misra from Macro m where not isExcluded(m, DeadCodePackage::unusedMacroDeclarationQuery()) and + // We consider a macro "used" if there is a macro access not exists(MacroAccess ma | ma.getMacro() = m) and + // Or if there exists a check whether the macro is defined which the extractor + // hasn't been able to tie to a macro (usually because this use came before + // the macro was defined e.g. a header guard) + not exists(PreprocessorBranchDirective bd | + // Covers the #ifdef and #ifndef cases + bd.getHead() = m.getName() + or + // Covers the use of defined() to check if a macro is defined + m.getName() = bd.getHead().regexpCapture(".*defined *\\(? *([^\\s()]+) *\\)?\\.*", 1) + ) and // We consider a macro "used" if the name is undef-ed at some point in the same file, or a file // that includes the file defining the macro. This will over approximate use in the case of a // macro which is defined, then undefined, then re-defined but not used. diff --git a/c/misra/test/rules/RULE-2-5/test.c b/c/misra/test/rules/RULE-2-5/test.c index f37acb1509..15930f68d1 100644 --- a/c/misra/test/rules/RULE-2-5/test.c +++ b/c/misra/test/rules/RULE-2-5/test.c @@ -13,4 +13,55 @@ void test() { MACRO2; HEADER_MACRO2; -} \ No newline at end of file +} + +#define CHECKED_MACRO_1 // COMPLIANT - used in branch +#define CHECKED_MACRO_2 // COMPLIANT - used in branch +#define CHECKED_MACRO_3 // COMPLIANT - used in branch + +#ifdef CHECKED_MACRO_1 +#endif + +#ifndef CHECKED_MACRO_2 +#endif + +#if defined(CHECKED_MACRO_3) +#endif + +// In the case above, the extractor will identify macro accesses with each use +// of the macro. In the case above, the extractor does not tie them together, +// but the standard considers this acceptable usage. Notably, this type of +// pattern occurs for header guards. + +#ifdef CHECKED_MACRO_BEFORE_1 +#endif + +#ifndef CHECKED_MACRO_BEFORE_2 +#endif + +#if defined(CHECKED_MACRO_BEFORE_3) +#endif + +// clang-format off + +#if defined (CHECKED_MACRO_BEFORE_4) +#endif + +#if defined( CHECKED_MACRO_BEFORE_5 ) +#endif + +#if defined ( CHECKED_MACRO_BEFORE_6 ) +#endif + +#if defined CHECKED_MACRO_BEFORE_7 +#endif + +// clang-format on + +#define CHECKED_MACRO_BEFORE_1 // COMPLIANT - used in branch +#define CHECKED_MACRO_BEFORE_2 // COMPLIANT - used in branch +#define CHECKED_MACRO_BEFORE_3 // COMPLIANT - used in branch +#define CHECKED_MACRO_BEFORE_4 // COMPLIANT - used in branch +#define CHECKED_MACRO_BEFORE_5 // COMPLIANT - used in branch +#define CHECKED_MACRO_BEFORE_6 // COMPLIANT - used in branch +#define CHECKED_MACRO_BEFORE_7 // COMPLIANT - used in branch \ No newline at end of file diff --git a/change_notes/2024-10-22-rule-2-5.md b/change_notes/2024-10-22-rule-2-5.md new file mode 100644 index 0000000000..6de3f0be11 --- /dev/null +++ b/change_notes/2024-10-22-rule-2-5.md @@ -0,0 +1,2 @@ + - `RULE-2-5` - `UnusedMacroDeclaration.ql`: + - Exclude false positives where a macro was used before definition, for example a header guard. \ No newline at end of file