Skip to content

Commit b5b300d

Browse files
committed
DeadCode: Use HoldsForAllInstances
Eliminate false positives where a line of code is used in some copies (instances) but not others.
1 parent fb43031 commit b5b300d

File tree

1 file changed

+28
-15
lines changed
  • cpp/common/src/codingstandards/cpp/rules/deadcode

1 file changed

+28
-15
lines changed

cpp/common/src/codingstandards/cpp/rules/deadcode/DeadCode.qll

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313

1414
import cpp
15+
import codingstandards.cpp.alertreporting.HoldsForAllInstances
1516
import codingstandards.cpp.Customizations
1617
import codingstandards.cpp.Exclusions
1718
import codingstandards.cpp.deadcode.UselessAssignments
@@ -31,10 +32,6 @@ predicate isDeadOrUnreachableStmt(Stmt s) {
3132
s.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock()
3233
}
3334

34-
/**
35-
* Holds if the `Stmt` `s` is dead, i.e. could be executed, but its removal would not meaningfully
36-
* affect the program.
37-
*/
3835
predicate isDeadStmt(Stmt s) {
3936
// A `DeclStmt` is dead code if:
4037
// - All the declarations are variable declarations
@@ -108,17 +105,33 @@ predicate isDeadStmt(Stmt s) {
108105
exists(TryStmt ts | s = ts and isDeadStmt(ts.getStmt()))
109106
}
110107

111-
query predicate problems(Stmt s, string message) {
112-
not isExcluded(s, getQuery()) and
108+
/**
109+
* Holds if the `Stmt` `s` is dead, i.e. could be executed, but its removal would not meaningfully
110+
* affect the program.
111+
*/
112+
class DeadStmtInstance extends Stmt {
113+
DeadStmtInstance() {
114+
isDeadStmt(this) and
115+
// Exclude compiler generated statements
116+
not this.isCompilerGenerated() and
117+
// Exclude code fully generated by macros, because the code may be "live" in other expansions
118+
not this.isInMacroExpansion() and
119+
// MISRA defines dead code as an "_executed_ statement whose removal would not affect the program
120+
// output". We therefore exclude unreachable statements as they are, by definition, not executed.
121+
not this.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock()
122+
}
123+
}
124+
125+
class DeadStmt = HoldsForAllInstances<DeadStmtInstance>::LogicalResultStmt;
126+
127+
query predicate problems(DeadStmt s, string message) {
128+
not isExcluded(s.getAStmtInstance(), getQuery()) and
113129
message = "This statement is dead code." and
114-
isDeadStmt(s) and
115130
// Report only the highest level dead statement, to avoid over reporting
116-
not isDeadStmt(s.getParentStmt()) and
117-
// MISRA defines dead code as an "_executed_ statement whose removal would not affect the program
118-
// output". We therefore exclude unreachable statements as they are, by definition, not executed.
119-
not s.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock() and
120-
// Exclude code fully generated by macros, because the code may be "live" in other expansions
121-
not s.isInMacroExpansion() and
122-
// Exclude compiler generated statements
123-
not s.isCompilerGenerated()
131+
not exists(DeadStmt parent |
132+
// All instances must share a dead statement parent for us to report the parent instead
133+
forall(Stmt instance | instance = s.getAStmtInstance() |
134+
parent.getAStmtInstance() = instance.getParentStmt()
135+
)
136+
)
124137
}

0 commit comments

Comments
 (0)