|
1 | 1 | /** |
2 | 2 | * @id c/misra/goto-label-block-condition |
3 | | - * @name RULE-15-3: The goto statement and any of its label shall be declared or enclosed in the same block. |
| 3 | + * @name RULE-15-3: The goto statement and any of its label shall be declared or enclosed in the same block. |
4 | 4 | * @description Any label referenced by a goto statement shall be declared in the same block, or in |
5 | 5 | * any block enclosing the goto statement |
6 | 6 | * @kind problem |
|
15 | 15 | import cpp |
16 | 16 | import codingstandards.c.misra |
17 | 17 |
|
| 18 | +predicate isPartOfSwitch(Stmt goto) { |
| 19 | + exists(SwitchStmt switch | switch.getStmt() = goto.getParent()) |
| 20 | +} |
| 21 | + |
| 22 | +Stmt getNextStmt(ControlFlowNode node) { |
| 23 | + node.getASuccessor() = result |
| 24 | + or |
| 25 | + exists(ControlFlowNode other | |
| 26 | + node.getASuccessor() = other and other != result and result = getNextStmt(other) |
| 27 | + ) |
| 28 | +} |
| 29 | + |
| 30 | +Stmt getPreviousStmt(Stmt s) { s = getNextStmt(result) } |
| 31 | + |
| 32 | +SwitchCase getSwitchCase(Stmt stmt) { |
| 33 | + exists(int index, SwitchStmt switch | |
| 34 | + getStmtInSwitch(switch, stmt, index) and getStmtInSwitch(switch, result, index - 1) |
| 35 | + ) |
| 36 | + or |
| 37 | + exists(int index, SwitchStmt switch, Stmt other | |
| 38 | + getStmtInSwitch(switch, stmt, index) and |
| 39 | + getStmtInSwitch(switch, other, index - 1) and |
| 40 | + not other instanceof SwitchCase and |
| 41 | + result = getSwitchCase(other) |
| 42 | + ) |
| 43 | +} |
| 44 | + |
| 45 | +predicate getStmtInSwitch(SwitchStmt switch, Stmt s, int index) { |
| 46 | + switch.getStmt().(BlockStmt).getStmt(index) = s |
| 47 | +} |
| 48 | + |
18 | 49 | int statementDepth(Stmt statement) { |
19 | 50 | statement.getParent() = statement.getEnclosingFunction().getBlock() and result = 1 |
20 | 51 | or |
21 | 52 | statementDepth(statement.getParent()) + 1 = result |
22 | 53 | } |
23 | 54 |
|
24 | 55 | predicate test(GotoStmt goto, Stmt target, int m, int n) { |
25 | | - statementDepth(goto) = m and target = goto.getTarget() and statementDepth(target) = n |
| 56 | + statementDepth(goto) = m and |
| 57 | + target = goto.getTarget() and |
| 58 | + statementDepth(target) = n and |
| 59 | + isPartOfSwitch(goto) and |
| 60 | + getSwitchCase(goto) = getSwitchCase(target) and |
| 61 | + m = n |
26 | 62 | } |
27 | 63 |
|
28 | | -from GotoStmt goto |
| 64 | +from GotoStmt goto, Stmt target, int gotoDepth, int targetDepth |
29 | 65 | where |
30 | 66 | not isExcluded(goto, Statements2Package::gotoLabelBlockConditionQuery()) and |
31 | | - not goto.getEnclosingBlock+() = goto.getTarget().getEnclosingBlock() |
32 | | - or |
33 | | - exists(SwitchStmt switch, int caseLocation, int nextCaseLocation | |
34 | | - switch.getAChild*() = goto and |
35 | | - switch.getASwitchCase().getLocation().getStartLine() = caseLocation and |
36 | | - switch.getASwitchCase().getNextSwitchCase().getLocation().getStartLine() = nextCaseLocation and |
37 | | - goto.getLocation().getStartLine() > caseLocation and |
38 | | - goto.getLocation().getStartLine() < nextCaseLocation and |
| 67 | + goto.getTarget() = target and |
| 68 | + gotoDepth = statementDepth(goto) and |
| 69 | + targetDepth = statementDepth(target) and |
| 70 | + targetDepth >= gotoDepth and |
| 71 | + ( |
| 72 | + targetDepth = gotoDepth |
| 73 | + implies |
39 | 74 | ( |
40 | | - goto.getTarget().getLocation().getStartLine() < caseLocation |
| 75 | + not isPartOfSwitch(goto) and not goto.getParent() = target.getParent() |
41 | 76 | or |
42 | | - goto.getTarget().getLocation().getStartLine() > nextCaseLocation |
43 | | - ) and |
44 | | - goto.getTarget().getLocation().getStartLine() > switch.getLocation().getStartLine() |
| 77 | + isPartOfSwitch(goto) and not getSwitchCase(goto) = getSwitchCase(target) |
| 78 | + ) |
45 | 79 | ) |
46 | 80 | select goto, "The $@ statement and its $@ are not declared or enclosed in the same block. test", |
47 | | - goto, "goto", goto.getTarget(), "label" |
| 81 | + goto, "goto", target, "label" |
0 commit comments