From 8bcf85d6cd68d607f67689d42ca452b3cda8ec08 Mon Sep 17 00:00:00 2001 From: Jan Schlosser Date: Sat, 25 Jul 2026 14:45:45 +0200 Subject: [PATCH] Fix RULE-5-10-1 false positives on compiler-predefined function identifiers RULE-5-10-1 (poorly-formed identifier) flagged the compiler-predefined function identifiers __func__, __FUNCTION__ and __PRETTY_FUNCTION__ for containing double underscores / leading underscores. These are not user-defined identifiers: __func__ is mandated by the C++ standard and __FUNCTION__/__PRETTY_FUNCTION__ are GCC/Clang extensions, synthesized once per enclosing function. They frequently surface via assert-style macros, producing one finding per macro invocation site (on this codebase, 228 findings, ~79% of the rule's results). The shared IdentifierIntroduction library already excludes `variable.isCompilerGenerated()`, but the extractor does not mark these predefined variables as compiler generated, so they leak through. Exclude them in VariableDeclarationEntryIdentifier using a name-independent structural signal: they are `static` local variables with no definition (their only declaration entry is located at a use site), whereas a genuine `static` local always has an in-source definition. This deliberately avoids hard-coding the names, so a user who really declares such an identifier (on a compiler that does not predefine it) still has a definition and is therefore still flagged. Add a regression test to RULE-5-10-1 covering __func__ and __PRETTY_FUNCTION__ (COMPLIANT). The false positive reproduces in the single-translation-unit test harness: without this fix the test fails with the four spurious findings; with it the test passes. The existing RULE-5-10-1 and Identifiers library tests continue to pass. Fixes #1170 --- ...8-04-rule-5-10-1-pretty-function-regression.md | 2 ++ .../src/codingstandards/cpp/Identifiers.qll | 15 ++++++++++++++- .../RULE-5-10-1/PoorlyFormedIdentifier.expected | 2 ++ cpp/misra/test/rules/RULE-5-10-1/test.cpp | 15 +++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 change_notes/2026-08-04-rule-5-10-1-pretty-function-regression.md diff --git a/change_notes/2026-08-04-rule-5-10-1-pretty-function-regression.md b/change_notes/2026-08-04-rule-5-10-1-pretty-function-regression.md new file mode 100644 index 0000000000..fdfd27c1c7 --- /dev/null +++ b/change_notes/2026-08-04-rule-5-10-1-pretty-function-regression.md @@ -0,0 +1,2 @@ +- `RULE-5-10-1` - `PoorlyFormedIdentifier.ql`: + - Avoid false positives for none user defined identifiers like __PRETTY_FUNCTION__ diff --git a/cpp/common/src/codingstandards/cpp/Identifiers.qll b/cpp/common/src/codingstandards/cpp/Identifiers.qll index b1aaac9620..23751ac264 100644 --- a/cpp/common/src/codingstandards/cpp/Identifiers.qll +++ b/cpp/common/src/codingstandards/cpp/Identifiers.qll @@ -332,7 +332,20 @@ private module IdentifierIntroductionImpl { not variable.isCompilerGenerated() and // Some variables are not correctly marked as compiler generated, such as parameters of lambda // conversion operators. - not variable.(Parameter).getFunction().isCompilerGenerated() + not variable.(Parameter).getFunction().isCompilerGenerated() and + // The compiler-provided predefined function identifiers (`__func__`, and the GCC/Clang + // extensions `__FUNCTION__` and `__PRETTY_FUNCTION__`) are synthesized once per enclosing + // function, but the extractor does not flag them as compiler generated, so they leak through + // the check above. They are not user-defined identifiers and should not be reported. Rather + // than hard-coding these names (which would wrongly suppress a genuine user declaration of + // such an identifier on a compiler that does not predefine it), we identify them + // structurally: they are `static` local variables with no definition (their only declaration + // entry is located at a use site), whereas a real `static` local always has an in-source + // definition. + not ( + variable.(LocalVariable).isStatic() and + not variable.hasDefinition() + ) // Note: Some duplicate and/or unflagged compiler-generated variables seem to exist in tests, // which may be related to constexpr in templates. These redundant variables seem to only be // distinguishable by the fact that their start location is the same as their end location. diff --git a/cpp/misra/test/rules/RULE-5-10-1/PoorlyFormedIdentifier.expected b/cpp/misra/test/rules/RULE-5-10-1/PoorlyFormedIdentifier.expected index 527ed15be9..9ea52373b8 100644 --- a/cpp/misra/test/rules/RULE-5-10-1/PoorlyFormedIdentifier.expected +++ b/cpp/misra/test/rules/RULE-5-10-1/PoorlyFormedIdentifier.expected @@ -49,3 +49,5 @@ | test.cpp:184:7:184:15 | wctrans_t | Identifier 'wctrans_t' is a reserved name. | | test.cpp:185:7:185:14 | wctype_t | Identifier 'wctype_t' is a reserved name. | | test.cpp:186:7:186:12 | wint_t | Identifier 'wint_t' is a reserved name. | +| test.cpp:202:1:202:42 | __PRETTY_FUNCTION__ | Identifier '__PRETTY_FUNCTION__' contains double underscores. | +| test.cpp:202:1:202:42 | __PRETTY_FUNCTION__ | Identifier '__PRETTY_FUNCTION__' starts with underscore. | diff --git a/cpp/misra/test/rules/RULE-5-10-1/test.cpp b/cpp/misra/test/rules/RULE-5-10-1/test.cpp index b09b761fcc..c8600aadfd 100644 --- a/cpp/misra/test/rules/RULE-5-10-1/test.cpp +++ b/cpp/misra/test/rules/RULE-5-10-1/test.cpp @@ -186,6 +186,21 @@ void test_reserved_names() { int wint_t = 20; // NON_COMPLIANT - reserved name } +// Test case for compiler-predefined function identifiers (not user-defined). +// __func__ is standard; __FUNCTION__ and __PRETTY_FUNCTION__ are GCC/Clang +// extensions. They are synthesized per-function by the compiler, so despite +// containing double underscores / leading underscores they must not be flagged. +const char *test_predefined_function_identifiers() { + const char *a = __func__; // COMPLIANT - compiler-predefined, not user-defined + const char *b = __PRETTY_FUNCTION__; // COMPLIANT - compiler-predefined, not user-defined + return a ? a : b; +} + +// Test case for a user-defined macro that reuses a compiler-predefined name. +// Redefining __PRETTY_FUNCTION__ as a macro is a user-defined identifier and +// should be flagged (double underscores + lowercase). +#define __PRETTY_FUNCTION__ "user_defined" // NON_COMPLIANT - user-defined macro + // Test case for valid identifiers void test_valid_identifiers() { int validName = 1; // COMPLIANT