-
Notifications
You must be signed in to change notification settings - Fork 77
Expand file tree
/
Copy pathUnreachableStatement.ql
More file actions
74 lines (71 loc) · 2.69 KB
/
UnreachableStatement.ql
File metadata and controls
74 lines (71 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
* @id cpp/misra/unreachable-statement
* @name RULE-0-0-1: A function shall not contain unreachable statements
* @description Dead code can indicate a logic error, potentially introduced during code edits, or
* it may be unnecessary code that can be deleted.
* @kind problem
* @precision very-high
* @problem.severity error
* @tags external/misra/id/rule-0-0-1
* maintainability
* scope/single-translation-unit
* external/misra/enforcement/decidable
* external/misra/obligation/required
*/
import cpp
import codingstandards.cpp.misra
import codingstandards.cpp.deadcode.UnreachableCode
import codingstandards.cpp.exceptions.ExceptionFlow
import codingstandards.cpp.exceptions.ExceptionSpecifications
import codingstandards.cpp.exceptions.Shadowing
/**
* MISRA C++ defines its own notion of unreachable statements, which is similar to, but distinct
* from, the general concept of unreachable code.
*
* This is not a superset of `BasicBlock.isReachable()`, because that includes all catch blocks.
* However, it is a superset of the transitive closure of blocks reachable from function entry via
* `getASuccessor`.
*
* The superset relationship can be read below, with extra reachable cases added for `&&`, `||`,
* `?:`, and `constexpr if`, and catch blocks that aren't shadowed by prior catch blocks.
*/
predicate isReachable(BasicBlock bb) {
bb = any(Function f).getEntryPoint()
or
isReachable(bb.getAPredecessor())
or
exists(BinaryLogicalOperation op |
isReachable(op.getBasicBlock()) and
bb = op.getAnOperand().getBasicBlock()
)
or
exists(ConditionalExpr cond |
isReachable(cond.getBasicBlock()) and
bb = [cond.getThen(), cond.getElse()].getBasicBlock()
)
or
exists(FunctionCall call, TryStmt try, CatchBlock cb |
isReachable(call.getBasicBlock()) and
not isNoExceptTrue(call.getTarget()) and
try = getNearestTry(call.getEnclosingStmt()) and
cb = try.getACatchClause() and
not cb instanceof ShadowedCatchBlock and
bb = cb.getBasicBlock()
)
or
exists(ConstexprIfStmt ifStmt |
isReachable(ifStmt.getBasicBlock()) and
bb = [ifStmt.getThen(), ifStmt.getElse()].getBasicBlock()
)
}
from BasicBlock bb
where
not isExcluded(bb, DeadCode3Package::unreachableStatementQuery()) and
not isReachable(bb) and
not isCompilerGenerated(bb) and
not affectedByMacro(bb)
// Note that the location of a BasicBlock will in some cases have an incorrect end location, often
// preceding the end and including live code. We cast the block to an `Element` to get locations
// that are not broken.
select bb.(Element), "Unreachable statement in function '$@'.", bb.getEnclosingFunction(),
bb.getEnclosingFunction().getName()