|
16 | 16 |
|
17 | 17 | import cpp |
18 | 18 | import codingstandards.cpp.autosar |
19 | | -import codingstandards.cpp.deadcode.UselessAssignments |
20 | | -import codingstandards.cpp.deadcode.UnreachableCode |
| 19 | +import codingstandards.cpp.rules.deadcode.DeadCode |
21 | 20 |
|
22 | | -/* |
23 | | - * This query finds the following kinds of dead code statement: |
24 | | - * - A declaration of a non-static stack variable whose initializing expression is pure and that is never subsequently accessed in live code. |
25 | | - * - A block that contain only dead statements. |
26 | | - * - A do loop whose condition is pure, and whose body contains only dead statements. |
27 | | - * - An if statement whose condition is pure, and whose then and else clauses (where they exist) only contain dead statements. |
28 | | - * - A label statement to which the code never jumps. |
29 | | - * - A while loop whose condition is pure, and whose body contains only dead statements. |
30 | | - * - Expression statements whose expressions are pure. |
31 | | - * - Writes to a non-static stack variable that is never subsequently read in live code. |
32 | | - */ |
33 | | - |
34 | | -/** |
35 | | - * Holds if the `Stmt` `s` is either dead or unreachable. |
36 | | - */ |
37 | | -predicate isDeadOrUnreachableStmt(Stmt s) { |
38 | | - isDeadStmt(s) |
39 | | - or |
40 | | - s.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock() |
| 21 | +class MisraCppDeadCodeQuery extends DeadCodeSharedQuery { |
| 22 | + MisraCppDeadCodeQuery() { this = DeadCodePackage::deadCodeQuery() } |
41 | 23 | } |
42 | | - |
43 | | -/** |
44 | | - * Holds if the `Stmt` `s` is dead, i.e. could be executed, but its removal would not meaningfully |
45 | | - * affect the program. |
46 | | - */ |
47 | | -predicate isDeadStmt(Stmt s) { |
48 | | - // A `DeclStmt` is dead code if: |
49 | | - // - All the declarations are variable declarations |
50 | | - // - None of those variables are ever accessed in non-dead code |
51 | | - // - The initializers for each of the variables are pure |
52 | | - exists(DeclStmt ds | |
53 | | - ds = s and |
54 | | - // Use forex so that we don't flag "fake" generated `DeclStmt`s (e.g. those generated by the |
55 | | - // extractor for static_asserts) with no actual declarations |
56 | | - forex(Declaration d | d = ds.getADeclaration() | |
57 | | - exists(LocalScopeVariable v | |
58 | | - d = v and |
59 | | - v.getInitializer().getExpr().isPure() and |
60 | | - not exists(VariableAccess va | |
61 | | - va.getTarget() = v and |
62 | | - not isDeadOrUnreachableStmt(va.getEnclosingStmt()) |
63 | | - ) |
64 | | - ) |
65 | | - ) |
66 | | - ) |
67 | | - or |
68 | | - // A block that only contains dead statements. |
69 | | - exists(BlockStmt b | |
70 | | - b = s and |
71 | | - forall(Stmt child | child = b.getAStmt() | isDeadStmt(child)) and |
72 | | - // If this is a catch block, we should only report it as dead if it is the last catch block. |
73 | | - not exists(TryStmt ts, int i | |
74 | | - ts.getCatchClause(i) = b and |
75 | | - i < (ts.getNumberOfCatchClauses() - 1) |
76 | | - ) |
77 | | - ) |
78 | | - or |
79 | | - // A do statement whose condition is pure, and whose body contains only dead statements. |
80 | | - exists(DoStmt ds | |
81 | | - ds = s and |
82 | | - ds.getCondition().isPure() and |
83 | | - isDeadOrUnreachableStmt(ds.getStmt()) |
84 | | - ) |
85 | | - or |
86 | | - // An if statement whose condition is pure, and whose then and else clauses (where they exist) are dead or unreachable |
87 | | - exists(IfStmt is | |
88 | | - is = s and |
89 | | - is.getCondition().isPure() and |
90 | | - // Then part is either dead or unreachable |
91 | | - isDeadOrUnreachableStmt(is.getThen()) and |
92 | | - (exists(is.getElse()) implies isDeadOrUnreachableStmt(is.getElse())) |
93 | | - ) |
94 | | - or |
95 | | - // A while statement whose condition is pure, and whose body is a dead or unreachable statement |
96 | | - exists(WhileStmt ws | |
97 | | - ws = s and |
98 | | - ws.getCondition().isPure() and |
99 | | - isDeadOrUnreachableStmt(ws.getStmt()) |
100 | | - ) |
101 | | - or |
102 | | - // An expression statement which is pure |
103 | | - s.(ExprStmt).getExpr().isPure() |
104 | | - or |
105 | | - exists(SsaDefinition sd, LocalScopeVariable v | |
106 | | - // A useless definition |
107 | | - isUselessSsaDefinition(sd, v) and |
108 | | - s.(ExprStmt).getExpr() = sd.getDefinition() and |
109 | | - // The defining value is pure |
110 | | - sd.getDefiningValue(v).isPure() |
111 | | - ) |
112 | | - or |
113 | | - // Any TryStmt with a dead body is dead. We ignore the catch blocks, because if the body is dead, |
114 | | - // no exception can be thrown, and so the catch blocks are unreachable |
115 | | - exists(TryStmt ts | s = ts and isDeadStmt(ts.getStmt())) |
116 | | -} |
117 | | - |
118 | | -from Stmt s |
119 | | -where |
120 | | - not isExcluded(s, DeadCodePackage::deadCodeQuery()) and |
121 | | - isDeadStmt(s) and |
122 | | - // Report only the highest level dead statement, to avoid over reporting |
123 | | - not isDeadStmt(s.getParentStmt()) and |
124 | | - // MISRA defines dead code as an "_executed_ statement whose removal would not affect the program |
125 | | - // output". We therefore exclude unreachable statements as they are, by definition, not executed. |
126 | | - not s.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock() and |
127 | | - // Exclude code generated by macros, because the code may be "live" in other instantiations |
128 | | - not s.isAffectedByMacro() and |
129 | | - // Exclude compiler generated statements |
130 | | - not s.isCompilerGenerated() |
131 | | -select s, "This statement is dead code." |
0 commit comments