Skip to content

Commit fabb7e5

Browse files
committed
Finish first draft
1 parent 221b9b2 commit fabb7e5

File tree

3 files changed

+83
-62
lines changed

3 files changed

+83
-62
lines changed

cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql

Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,53 +19,74 @@
1919
import cpp
2020
import codingstandards.cpp.misra
2121
import codingstandards.cpp.SwitchStatement
22+
import codingstandards.cpp.Noreturn
2223

2324
from SwitchStmt switch, string message
2425
where
2526
not isExcluded(switch, StatementsPackage::appropriateStructureOfSwitchStatementQuery()) and
26-
(
27-
// RULE-16-1: Switch not well-formed (has inappropriate statements)
28-
exists(SwitchCase case |
29-
case = switch.getASwitchCase() and
30-
switchCaseNotWellFormed(case) and
31-
message = "has a case that contains inappropriate statements (only expression, compound, selection, iteration or try statements are allowed)"
27+
/* 1. There is a statement that appears as an initializer and is not a declaration statement. */
28+
exists(Stmt initializer | initializer = switch.getInitialization() |
29+
not initializer instanceof DeclStmt
30+
) and
31+
message = "contains a statement that that is not a simple declaration"
32+
or
33+
/* 2. There is a switch case label that does not lead a branch (i.e. a switch case label is nested). */
34+
exists(SwitchCase case | case = switch.getASwitchCase() | case instanceof NestedSwitchCase) and
35+
message = "contains a switch label that is not directly within the switch body"
36+
or
37+
/* 3. There is a non-case label in a label group. */
38+
exists(SwitchCase case | case = switch.getASwitchCase() |
39+
case.getAStmt().getChildStmt*() instanceof LabelStmt
40+
) and
41+
message = "contains a statement label that is not a case label"
42+
or
43+
/* 4. There is a statement before the first case label. */
44+
exists(Stmt switchBody | switchBody = switch.getStmt() |
45+
not switchBody.getChild(0) instanceof SwitchCase
46+
) and
47+
message = "has a statement that is not a case label as its first element"
48+
or
49+
/* 5. There is a switch case whose terminator is not one of the allowed kinds. */
50+
exists(SwitchCase case, Stmt lastStmt |
51+
case = switch.getASwitchCase() and lastStmt = case.getLastStmt()
52+
|
53+
not (
54+
lastStmt instanceof BreakStmt or
55+
lastStmt instanceof ReturnStmt or
56+
lastStmt instanceof GotoStmt or
57+
lastStmt instanceof ContinueStmt or
58+
lastStmt.(ExprStmt).getExpr() instanceof ThrowExpr or
59+
lastStmt.(ExprStmt).getExpr().(Call).getTarget() instanceof NoreturnFunction or
60+
lastStmt.getAnAttribute().getName().matches("%fallthrough") // We'd like to consider compiler variants such as `clang::fallthrough`.
3261
)
33-
or
34-
// RULE-16-2: Nested switch labels
35-
exists(SwitchCase case |
36-
case = switch.getASwitchCase() and
37-
case instanceof NestedSwitchCase and
38-
message = "contains a switch label that is not directly within the switch body"
39-
)
40-
or
41-
// RULE-16-3: Non-empty case doesn't terminate with break
42-
exists(SwitchCase case |
43-
case = switch.getASwitchCase() and
44-
case instanceof CaseDoesNotTerminate and
45-
message = "has a non-empty case that does not terminate with an unconditional break or throw statement"
46-
)
47-
or
48-
// RULE-16-4: Missing default clause
49-
not switch.hasDefaultCase() and
50-
message = "is missing a default clause"
51-
or
52-
// RULE-16-5: Default clause not first or last
53-
exists(SwitchCase defaultCase |
54-
switch.getDefaultCase() = defaultCase and
55-
exists(defaultCase.getPreviousSwitchCase()) and
56-
finalClauseInSwitchNotDefault(switch) and
57-
message = "has a default clause that is not the first or last switch label"
58-
)
59-
or
60-
// RULE-16-6: Less than two case clauses
61-
count(SwitchCase case |
62-
switch.getASwitchCase() = case and
63-
case.getNextSwitchCase() != case.getFollowingStmt()
64-
) + 1 < 2 and
65-
message = "has fewer than two switch-clauses"
66-
or
67-
// RULE-16-7: Boolean switch expression
68-
switch instanceof BooleanSwitchStmt and
69-
message = "has a controlling expression of essentially Boolean type"
70-
)
62+
) and
63+
message = "is missing a terminator that moves the control out of its body"
64+
or
65+
/* 6. The switch statement does not have more than two unique branches. */
66+
count(SwitchCase case |
67+
case = switch.getASwitchCase() and
68+
/*
69+
* If the next switch case is the following statement of this switch case, then the two
70+
* switch cases are consecutive and should be considered as constituting one branch
71+
* together.
72+
*/
73+
74+
not case.getNextSwitchCase() = case.getFollowingStmt()
75+
|
76+
case
77+
) < 2 and
78+
message = "contains less than two branches"
79+
or
80+
/* 7-1. The switch statement is not an enum switch statement and is missing a default case. */
81+
not switch instanceof EnumSwitch and
82+
not switch.hasDefaultCase() and
83+
message = "lacks a default case"
84+
or
85+
/*
86+
* 7-2. The switch statement is an enum switch statement and is missing a branch for a
87+
* variant.
88+
*/
89+
90+
exists(switch.(EnumSwitch).getAMissingCase()) and
91+
message = "lacks a case for one of its variants"
7192
select switch, "Switch statement " + message + "."
Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
| test.cpp:40:3:40:8 | Switch statement has a case that contains inappropriate statements (only expression, compound, selection, iteration or try statements are allowed). |
2-
| test.cpp:86:3:86:8 | Switch statement has a non-empty case that does not terminate with an unconditional break or throw statement. |
3-
| test.cpp:86:3:86:8 | Switch statement has a non-empty case that does not terminate with an unconditional break or throw statement. |
4-
| test.cpp:98:3:98:8 | Switch statement has a non-empty case that does not terminate with an unconditional break or throw statement. |
5-
| test.cpp:123:3:123:8 | Switch statement is missing a default clause. |
6-
| test.cpp:166:3:166:8 | Switch statement has a default clause that is not the first or last switch label. |
7-
| test.cpp:203:3:203:8 | Switch statement has fewer than two switch-clauses. |
8-
| test.cpp:210:3:210:8 | Switch statement has fewer than two switch-clauses. |
9-
| test.cpp:235:3:235:8 | Switch statement has a controlling expression of essentially Boolean type. |
10-
| test.cpp:245:3:245:8 | Switch statement has a controlling expression of essentially Boolean type. |
11-
| test.cpp:266:3:266:8 | Switch statement has a controlling expression of essentially Boolean type. |
12-
| test.cpp:266:3:266:8 | Switch statement is missing a default clause. |
13-
| test.cpp:266:3:266:8 | Switch statement has fewer than two switch-clauses. |
14-
| test.cpp:275:3:275:8 | Switch statement has a non-empty case that does not terminate with an unconditional break or throw statement. |
15-
| test.cpp:275:3:275:8 | Switch statement has a default clause that is not the first or last switch label. |
1+
| test.cpp:28:3:37:3 | switch (...) ... | Switch statement contains a statement that that is not a simple declaration. |
2+
| test.cpp:51:3:60:3 | switch (...) ... | Switch statement contains a switch label that is not directly within the switch body. |
3+
| test.cpp:62:3:71:3 | switch (...) ... | Switch statement contains a switch label that is not directly within the switch body. |
4+
| test.cpp:75:3:85:3 | switch (...) ... | Switch statement contains a statement label that is not a case label. |
5+
| test.cpp:89:3:97:3 | switch (...) ... | Switch statement has a statement that is not a case label as its first element. |
6+
| test.cpp:147:3:154:3 | switch (...) ... | Switch statement is missing a terminator that moves the control out of its body. |
7+
| test.cpp:188:3:192:3 | switch (...) ... | Switch statement contains less than two branches. |
8+
| test.cpp:194:3:200:3 | switch (...) ... | Switch statement contains less than two branches. |
9+
| test.cpp:215:3:219:3 | switch (...) ... | Switch statement contains less than two branches. |
10+
| test.cpp:215:3:219:3 | switch (...) ... | Switch statement lacks a default case. |
11+
| test.cpp:223:3:229:3 | switch (...) ... | Switch statement lacks a case for one of its variants. |
12+
| test.cpp:231:3:239:3 | switch (...) ... | Switch statement lacks a case for one of its variants. |

cpp/misra/test/rules/RULE-9-4-2/test.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <cstdlib>
2+
13
int i = 0;
24

35
/**
@@ -77,16 +79,16 @@ void testOtherLabelsInBranch(int expr) {
7779
someLabel:
7880
i++;
7981
break;
82+
}
8083
default:
8184
break;
8285
}
83-
}
8486
}
8587

8688
void testLeadingNonCaseStatement(int expr) {
8789
switch (expr) { // NON_COMPLIANT: Non-case statement is the first statement in
8890
// the switch body
89-
91+
int x = 1;
9092
case 1:
9193
i++;
9294
break;
@@ -95,7 +97,7 @@ void testLeadingNonCaseStatement(int expr) {
9597
}
9698
}
9799

98-
[[noreturn]] void f() {}
100+
[[noreturn]] void f() { exit(0); }
99101
void g() {}
100102

101103
void testSwitchBranchTerminator(int expr) {
@@ -166,6 +168,7 @@ void testSwitchBranchTerminator(int expr) {
166168
[[fallthrough]];
167169
default:
168170
i++;
171+
break;
169172
}
170173

171174
error:

0 commit comments

Comments
 (0)