Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 225d24e

Browse filesBrowse files
committed
DeadCode: Create shared implementations for the cpp queries
Create shared implementations in preparation for the C queries.
1 parent 4acb620 commit 225d24e
Copy full SHA for 225d24e
Expand file treeCollapse file tree

29 files changed

+247
-170
lines changed

‎cpp/autosar/src/rules/A0-1-4/UnusedParameter.ql

Copy file name to clipboardExpand all lines: cpp/autosar/src/rules/A0-1-4/UnusedParameter.ql
+4-7Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,8 @@
1616
import cpp
1717
import codingstandards.cpp.autosar
1818
import codingstandards.cpp.deadcode.UnusedParameters
19+
import codingstandards.cpp.rules.unusedparameter.UnusedParameter
1920

20-
from Function f, UnusedParameter p
21-
where
22-
not isExcluded(p, DeadCodePackage::unusedParameterQuery()) and
23-
f = p.getFunction() and
24-
// Virtual functions are covered by a different rule
25-
not f.isVirtual()
26-
select p, "Unused parameter '" + p.getName() + "' for function $@.", f, f.getQualifiedName()
21+
class UnusedParameterQuery extends UnusedParameterSharedQuery {
22+
UnusedParameterQuery() { this = DeadCodePackage::unusedParameterQuery() }
23+
}

‎cpp/autosar/src/rules/A0-1-6/UnusedTypeDeclarations.ql

Copy file name to clipboardExpand all lines: cpp/autosar/src/rules/A0-1-6/UnusedTypeDeclarations.ql
+4-9Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,8 @@
1616

1717
import cpp
1818
import codingstandards.cpp.autosar
19-
import codingstandards.cpp.TypeUses
19+
import codingstandards.cpp.rules.unusedtypedeclarations.UnusedTypeDeclarations
2020

21-
from UserType ut
22-
where
23-
not isExcluded(ut, DeadCodePackage::unusedTypeDeclarationsQuery()) and
24-
not ut instanceof TemplateParameter and
25-
not ut instanceof ProxyClass and
26-
not exists(getATypeUse(ut)) and
27-
not ut.isFromUninstantiatedTemplate(_)
28-
select ut, "Type declaration " + ut.getName() + " is not used."
21+
class UnusedTypeDeclarationsQuery extends UnusedTypeDeclarationsSharedQuery {
22+
UnusedTypeDeclarationsQuery() { this = DeadCodePackage::unusedTypeDeclarationsQuery() }
23+
}

‎cpp/autosar/src/rules/M0-1-1/UnreachableCode.ql

Copy file name to clipboardExpand all lines: cpp/autosar/src/rules/M0-1-1/UnreachableCode.ql
+4-35Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,39 +17,8 @@
1717
import cpp
1818
import codingstandards.cpp.autosar
1919
import codingstandards.cpp.deadcode.UnreachableCode
20+
import codingstandards.cpp.rules.unreachablecode.UnreachableCode
2021

21-
/*
22-
* This query identifies unreachable code at the level of `BasicBlock`. We use `BasicBlock`s for
23-
* this because they represent sequences of statements which, according to the CFG, are either
24-
* all unreachable or all reachable, because control flow cannot escape from the middle of the
25-
* basic block.
26-
*
27-
* We use the `BasicBlock.isUnreachable()` predicate to identify `BasicBlock`s which are unreachable
28-
* according to our calculated control flow graph. In practice, this can resolve expressions used in
29-
* conditions which are constant, accesses of constant values (even across function boundaries), and
30-
* operations, recursively, on such expressions. There is no attempt made to resolve conditional
31-
* expressions which are not statically constant or derived directly from statically constant variables.
32-
*
33-
* One potential problem with using `BasicBlock`s is that for template functions the `BasicBlock` is
34-
* duplicated across multiple `Function` instances, one for uninstantiated templates, and one for
35-
* each instantiation. Rather than considering each template instantiation independently, we instead
36-
* only report a `BasicBlock` in a template as unreachable, if it is unreachable in all template
37-
* instantiations (and in the uninstantiated template). This helps avoid flagging examples such as
38-
* `return 1` as dead code in this example, where `T::isVal()` is statically deducible in some
39-
* template instantiations:
40-
* ```
41-
* template <class T> int f() {
42-
* if (T::isVal()) return 1;
43-
* return 2;
44-
* }
45-
* ```
46-
*/
47-
48-
from UnreachableBasicBlock b
49-
where
50-
// None of the basic blocks are excluded
51-
not isExcluded(b.getABasicBlock(), DeadCodePackage::unreachableCodeQuery()) and
52-
// Exclude results where at least one of the basic blocks appears in a macro expansion, as
53-
// macros can easily result in unreachable blocks through no fault of the user of the macro
54-
not inMacroExpansion(b.getABasicBlock())
55-
select b, "This statement in function $@ is unreachable.", b.getPrimaryFunction() as f, f.getName()
22+
class UnreachableCodeQuery extends UnreachableCodeSharedQuery {
23+
UnreachableCodeQuery() { this = DeadCodePackage::unreachableCodeQuery() }
24+
}

‎cpp/autosar/src/rules/M0-1-9/DeadCode.ql

Copy file name to clipboardExpand all lines: cpp/autosar/src/rules/M0-1-9/DeadCode.ql
+3-111Lines changed: 3 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -16,116 +16,8 @@
1616

1717
import cpp
1818
import codingstandards.cpp.autosar
19-
import codingstandards.cpp.deadcode.UselessAssignments
20-
import codingstandards.cpp.deadcode.UnreachableCode
19+
import codingstandards.cpp.rules.deadcode.DeadCode
2120

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() }
4123
}
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."

‎cpp/autosar/test/rules/A0-1-4/UnusedParameter.qlref

Copy file name to clipboardExpand all lines: cpp/autosar/test/rules/A0-1-4/UnusedParameter.qlref
-1Lines changed: 0 additions & 1 deletion
This file was deleted.
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cpp/common/test/rules/unusedparameter/UnusedParameter.ql

‎cpp/autosar/test/rules/A0-1-6/UnusedTypeDeclarations.qlref

Copy file name to clipboardExpand all lines: cpp/autosar/test/rules/A0-1-6/UnusedTypeDeclarations.qlref
-1Lines changed: 0 additions & 1 deletion
This file was deleted.
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cpp/common/test/rules/unusedtypedeclarations/UnusedTypeDeclarations.ql

‎cpp/autosar/test/rules/M0-1-1/UnreachableCode.qlref

Copy file name to clipboardExpand all lines: cpp/autosar/test/rules/M0-1-1/UnreachableCode.qlref
-1Lines changed: 0 additions & 1 deletion
This file was deleted.
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cpp/common/test/rules/unreachablecode/UnreachableCode.ql

‎cpp/autosar/test/rules/M0-1-9/DeadCode.qlref

Copy file name to clipboardExpand all lines: cpp/autosar/test/rules/M0-1-9/DeadCode.qlref
-1Lines changed: 0 additions & 1 deletion
This file was deleted.
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cpp/common/test/rules/deadcode/DeadCode.ql
+122Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/**
2+
* Provides a library which includes a `problems` predicate for reporting DeadCode.
3+
*
4+
* This problems predicate finds the following kinds of dead code statement:
5+
* - A declaration of a non-static stack variable whose initializing expression is pure and that is never subsequently accessed in live code.
6+
* - A block that contain only dead statements.
7+
* - A do loop whose condition is pure, and whose body contains only dead statements.
8+
* - An if statement whose condition is pure, and whose then and else clauses (where they exist) only contain dead statements.
9+
* - A label statement to which the code never jumps.
10+
* - A while loop whose condition is pure, and whose body contains only dead statements.
11+
* - Expression statements whose expressions are pure.
12+
* - Writes to a non-static stack variable that is never subsequently read in live code.
13+
*/
14+
15+
import cpp
16+
import codingstandards.cpp.Customizations
17+
import codingstandards.cpp.Exclusions
18+
import codingstandards.cpp.deadcode.UselessAssignments
19+
import codingstandards.cpp.deadcode.UnreachableCode
20+
21+
abstract class DeadCodeSharedQuery extends Query { }
22+
23+
Query getQuery() { result instanceof DeadCodeSharedQuery }
24+
25+
/**
26+
* Holds if the `Stmt` `s` is either dead or unreachable.
27+
*/
28+
predicate isDeadOrUnreachableStmt(Stmt s) {
29+
isDeadStmt(s)
30+
or
31+
s.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock()
32+
}
33+
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+
*/
38+
predicate isDeadStmt(Stmt s) {
39+
// A `DeclStmt` is dead code if:
40+
// - All the declarations are variable declarations
41+
// - None of those variables are ever accessed in non-dead code
42+
// - The initializers for each of the variables are pure
43+
exists(DeclStmt ds |
44+
ds = s and
45+
// Use forex so that we don't flag "fake" generated `DeclStmt`s (e.g. those generated by the
46+
// extractor for static_asserts) with no actual declarations
47+
forex(Declaration d | d = ds.getADeclaration() |
48+
exists(LocalScopeVariable v |
49+
d = v and
50+
v.getInitializer().getExpr().isPure() and
51+
not exists(VariableAccess va |
52+
va.getTarget() = v and
53+
not isDeadOrUnreachableStmt(va.getEnclosingStmt())
54+
)
55+
)
56+
)
57+
)
58+
or
59+
// A block that only contains dead statements.
60+
exists(BlockStmt b |
61+
b = s and
62+
forall(Stmt child | child = b.getAStmt() | isDeadStmt(child)) and
63+
// If this is a catch block, we should only report it as dead if it is the last catch block.
64+
not exists(TryStmt ts, int i |
65+
ts.getCatchClause(i) = b and
66+
i < (ts.getNumberOfCatchClauses() - 1)
67+
)
68+
)
69+
or
70+
// A do statement whose condition is pure, and whose body contains only dead statements.
71+
exists(DoStmt ds |
72+
ds = s and
73+
ds.getCondition().isPure() and
74+
isDeadOrUnreachableStmt(ds.getStmt())
75+
)
76+
or
77+
// An if statement whose condition is pure, and whose then and else clauses (where they exist) are dead or unreachable
78+
exists(IfStmt is |
79+
is = s and
80+
is.getCondition().isPure() and
81+
// Then part is either dead or unreachable
82+
isDeadOrUnreachableStmt(is.getThen()) and
83+
(exists(is.getElse()) implies isDeadOrUnreachableStmt(is.getElse()))
84+
)
85+
or
86+
// A while statement whose condition is pure, and whose body is a dead or unreachable statement
87+
exists(WhileStmt ws |
88+
ws = s and
89+
ws.getCondition().isPure() and
90+
isDeadOrUnreachableStmt(ws.getStmt())
91+
)
92+
or
93+
// An expression statement which is pure
94+
s.(ExprStmt).getExpr().isPure()
95+
or
96+
exists(SsaDefinition sd, LocalScopeVariable v |
97+
// A useless definition
98+
isUselessSsaDefinition(sd, v) and
99+
s.(ExprStmt).getExpr() = sd.getDefinition() and
100+
// The defining value is pure
101+
sd.getDefiningValue(v).isPure()
102+
)
103+
or
104+
// Any TryStmt with a dead body is dead. We ignore the catch blocks, because if the body is dead,
105+
// no exception can be thrown, and so the catch blocks are unreachable
106+
exists(TryStmt ts | s = ts and isDeadStmt(ts.getStmt()))
107+
}
108+
109+
query predicate problems(Stmt s, string message) {
110+
not isExcluded(s, getQuery()) and
111+
message = "This statement is dead code." and
112+
isDeadStmt(s) and
113+
// Report only the highest level dead statement, to avoid over reporting
114+
not isDeadStmt(s.getParentStmt()) and
115+
// MISRA defines dead code as an "_executed_ statement whose removal would not affect the program
116+
// output". We therefore exclude unreachable statements as they are, by definition, not executed.
117+
not s.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock() and
118+
// Exclude code generated by macros, because the code may be "live" in other instantiations
119+
not s.isAffectedByMacro() and
120+
// Exclude compiler generated statements
121+
not s.isCompilerGenerated()
122+
}
+48Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* Provides a library which includes a `problems` predicate for reporting unreachable code.
3+
*
4+
* This problems predicate identifies unreachable code at the level of `BasicBlock`. We use
5+
* `BasicBlock`s for this because they represent sequences of statements which, according to the CFG,
6+
* are either all unreachable or all reachable, because control flow cannot escape from the middle
7+
* of the basic block.
8+
*
9+
* We use the `BasicBlock.isUnreachable()` predicate to identify `BasicBlock`s which are unreachable
10+
* according to our calculated control flow graph. In practice, this can resolve expressions used in
11+
* conditions which are constant, accesses of constant values (even across function boundaries), and
12+
* operations, recursively, on such expressions. There is no attempt made to resolve conditional
13+
* expressions which are not statically constant or derived directly from statically constant variables.
14+
*
15+
* One potential problem with using `BasicBlock`s is that for template functions the `BasicBlock` is
16+
* duplicated across multiple `Function` instances, one for uninstantiated templates, and one for
17+
* each instantiation. Rather than considering each template instantiation independently, we instead
18+
* only report a `BasicBlock` in a template as unreachable, if it is unreachable in all template
19+
* instantiations (and in the uninstantiated template). This helps avoid flagging examples such as
20+
* `return 1` as dead code in this example, where `T::isVal()` is statically deducible in some
21+
* template instantiations:
22+
* ```
23+
* template <class T> int f() {
24+
* if (T::isVal()) return 1;
25+
* return 2;
26+
* }
27+
* ```
28+
*/
29+
30+
import cpp
31+
import codingstandards.cpp.Customizations
32+
import codingstandards.cpp.Exclusions
33+
import codingstandards.cpp.deadcode.UnreachableCode
34+
35+
abstract class UnreachableCodeSharedQuery extends Query { }
36+
37+
Query getQuery() { result instanceof UnreachableCodeSharedQuery }
38+
39+
query predicate problems(UnreachableBasicBlock b, string message, Function f, string functionName) {
40+
// None of the basic blocks are excluded
41+
not isExcluded(b.getABasicBlock(), getQuery()) and
42+
message = "This statement in function $@ is unreachable." and
43+
// Exclude results where at least one of the basic blocks appears in a macro expansion, as
44+
// macros can easily result in unreachable blocks through no fault of the user of the macro
45+
not inMacroExpansion(b.getABasicBlock()) and
46+
f = b.getPrimaryFunction() and
47+
functionName = f.getName()
48+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.