Skip to content

Commit a15b475

Browse files
committed
M16-1-1: Improve perf and detection of nested uses of defined
- Optimize query to improve performance - Improve detection of macros whose body contains the `defined` operator after the start of the macro (e.g. `#define X Y || defined(Z)`). - Enable exclusions to be applied for this rule.
1 parent d74222a commit a15b475

6 files changed

+47
-31
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
* `M16-1-1`
2+
- Optimize query to improve performance
3+
- Improve detection of macros whose body contains the `defined` operator after the start of the macro (e.g. `#define X Y || defined(Z)`).

cpp/autosar/src/rules/M16-1-1/DefinedMacro.qll

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@ import cpp
22
import codingstandards.cpp.autosar
33

44
/**
5-
* A helper class describing macros wrapping defined operator
5+
* A helper class describing macros wrapping the defined operator
66
*/
7-
class DefinedMacro extends Macro {
8-
DefinedMacro() {
9-
this.getBody().regexpMatch("defined\\s*\\(.*")
7+
class MacroUsesDefined extends Macro {
8+
MacroUsesDefined() {
9+
// Uses `defined` directly
10+
exists(this.getBody().regexpFind("\\bdefined\\b", _, _))
1011
or
11-
this.getBody().regexpMatch("defined[\\s]+|defined$")
12+
// Uses a macro that uses `defined` (directly or indirectly)
13+
exists(MacroUsesDefined dm | exists(this.getBody().regexpFind(dm.getRegexForMatch(), _, _)))
1214
}
1315

14-
Macro getAUse() {
15-
result = this or
16-
anyAliasing(result, this)
16+
/**
17+
* Gets a regex for matching uses of this macro.
18+
*/
19+
string getRegexForMatch() {
20+
exists(string arguments |
21+
// If there are arguments
22+
if getHead() = getName() then arguments = "" else arguments = "\\s*\\("
23+
|
24+
// Use word boundary matching to find identifiers that match
25+
result = "\\b" + getName() + "\\b" + arguments
26+
)
1727
}
1828
}
19-
20-
predicate directAlias(Macro alias, Macro aliased) {
21-
not alias.getBody() = alias.getBody().replaceAll(aliased.getHead(), "")
22-
}
23-
24-
predicate anyAliasing(Macro alias, Macro inQ) {
25-
directAlias(alias, inQ)
26-
or
27-
exists(Macro intermediate | anyAliasing(intermediate, inQ) and anyAliasing(alias, intermediate))
28-
}

cpp/autosar/src/rules/M16-1-1/DefinedPreProcessorOperatorGeneratedFromExpansionFound.ql

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,19 @@ import cpp
1616
import codingstandards.cpp.autosar
1717
import DefinedMacro
1818

19-
from DefinedMacro m, PreprocessorBranch e
19+
/**
20+
* An `if` or `elif` preprocessor branch.
21+
*/
22+
class PreprocessorIfOrElif extends PreprocessorBranch {
23+
PreprocessorIfOrElif() {
24+
this instanceof PreprocessorIf or
25+
this instanceof PreprocessorElif
26+
}
27+
}
28+
29+
from PreprocessorIfOrElif e, MacroUsesDefined m
2030
where
21-
(
22-
e instanceof PreprocessorIf or
23-
e instanceof PreprocessorElif
24-
) and
25-
(
26-
e.getHead().regexpMatch(m.getAUse().getHead() + "\\s*\\(.*")
27-
or
28-
e.getHead().regexpMatch(m.getAUse().getHead().replaceAll("(", "\\(").replaceAll(")", "\\)"))
29-
) and
30-
not isExcluded(e)
31+
not isExcluded(e, MacrosPackage::definedPreProcessorOperatorInOneOfTheTwoStandardFormsQuery()) and
32+
// A`#if` or `#elif` which uses a macro which uses `defined`
33+
exists(e.getHead().regexpFind(m.getRegexForMatch(), _, _))
3134
select e, "The macro $@ expands to 'defined'", m, m.getName()
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
| test.cpp:22:1:22:18 | #if DBLWRAPUSES(X) | The macro $@ expands to 'defined' | test.cpp:18:1:18:22 | #define BADDEF defined | BADDEF |
1+
| test.cpp:22:1:22:18 | #if DBLWRAPUSES(X) | The macro $@ expands to 'defined' | test.cpp:21:1:21:24 | #define DBLWRAPUSES USES | DBLWRAPUSES |
22
| test.cpp:26:1:26:16 | #if BADDEFTWO(X) | The macro $@ expands to 'defined' | test.cpp:25:1:25:31 | #define BADDEFTWO(X) defined(X) | BADDEFTWO |
3+
| test.cpp:29:1:29:16 | #if BADDEFTWO(Y) | The macro $@ expands to 'defined' | test.cpp:25:1:25:31 | #define BADDEFTWO(X) defined(X) | BADDEFTWO |
4+
| test.cpp:42:1:42:11 | #if WRAPPER | The macro $@ expands to 'defined' | test.cpp:40:1:40:35 | #define WRAPPER X < Y \|\| defined(z) | WRAPPER |

cpp/autosar/test/rules/M16-1-1/DefinedPreProcessorOperatorInOneOfTheTwoStandardForms.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
| test.cpp:9:1:9:19 | #elif defined X < Y | Use of defined with non-standard form: X < Y. |
33
| test.cpp:13:1:13:18 | #if defined(X > Y) | Use of defined with non-standard form: X > Y. |
44
| test.cpp:14:1:14:20 | #elif defined(X < Y) | Use of defined with non-standard form: X < Y. |
5-
| test.cpp:34:1:34:47 | #if defined(X) \|\| defined _Y_ + X && defined(Y) | Use of defined with non-standard form: _Y_ + X. |
5+
| test.cpp:37:1:37:47 | #if defined(X) \|\| defined _Y_ + X && defined(Y) | Use of defined with non-standard form: _Y_ + X. |

cpp/autosar/test/rules/M16-1-1/test.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,18 @@
2626
#if BADDEFTWO(X) // NON_COMPLIANT
2727
#endif
2828

29+
#if BADDEFTWO(Y) // NON_COMPLIANT
30+
#endif
31+
2932
// clang-format off
3033
#if defined (X) || (defined(_Y_)) // COMPLIANT
3134
// clang-format on
3235
#endif
3336

3437
#if defined(X) || defined _Y_ + X && defined(Y) // NON_COMPLIANT
38+
#endif
39+
40+
#define WRAPPER X < Y || defined(z)
41+
42+
#if WRAPPER // NON_COMPLIANT
3543
#endif

0 commit comments

Comments
 (0)