Skip to content

Commit 7241613

Browse files
Merge pull request #1044 from github/michaelrfairhurst/implement-deadcode-10-rule-0-2-4
Implement Rule 0.2.4, unused functions with limited visibility.
2 parents f64a352 + d3815ad commit 7241613

File tree

16 files changed

+240
-97
lines changed

16 files changed

+240
-97
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- `A0-1-3` - `UnusedLocalFunction.ql`:
2+
- Query now reports unused public members of classes in anonymous namespaces, which have internal linkage.
3+
- Alert message no longer contains the fully qualified name of the function, since the given function is already linked.

cpp/autosar/src/rules/A0-1-3/UnusedLocalFunction.ql

Lines changed: 4 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -16,95 +16,10 @@
1616

1717
import cpp
1818
import codingstandards.cpp.autosar
19-
import codingstandards.cpp.DynamicCallGraph
20-
import codingstandards.cpp.deadcode.UnusedFunctions
19+
import codingstandards.cpp.rules.unusedlocalfunction.UnusedLocalFunction
2120

22-
/**
23-
* Checks if an overloaded function of
24-
* the function passed in the arguments, is called.
25-
*/
26-
predicate overloadedFunctionIsCalled(Function unusedFunction) {
27-
exists(Function f | f = unusedFunction.getAnOverload() and f = getTarget(_))
28-
}
29-
30-
/** Checks if a Function's address was taken. */
31-
predicate addressBeenTaken(Function unusedFunction) {
32-
exists(FunctionAccess fa | fa.getTarget() = unusedFunction)
33-
}
34-
35-
/** A `Function` nested in an anonymous namespace. */
36-
class AnonymousNamespaceFunction extends Function {
37-
AnonymousNamespaceFunction() { getNamespace().getParentNamespace*().isAnonymous() }
38-
}
39-
40-
/**
41-
* A function which is "local" to a particular scope or translation unit.
42-
*/
43-
class LocalFunction extends UnusedFunctions::UsableFunction {
44-
string localFunctionType;
45-
46-
LocalFunction() {
47-
this.(MemberFunction).isPrivate() and
48-
localFunctionType = "Private member"
49-
or
50-
// A function in an anonymous namespace (which is deduced to have internal linkage)
51-
this instanceof AnonymousNamespaceFunction and
52-
// Not member functions, which don't have internal linkage
53-
not this instanceof MemberFunction and
54-
localFunctionType = "Anonymous namespace"
55-
or
56-
// Static functions with internal linkage
57-
this.isStatic() and
58-
// Member functions never have internal linkage
59-
not this instanceof MemberFunction and
60-
// Functions in anonymous namespaces automatically have the "static" specifier added by the
61-
// extractor. We therefore excluded them from this case, and instead report them in the
62-
// anonymous namespace, as we don't know whether the "static" specifier was explicitly
63-
// provided by the user.
64-
not this instanceof AnonymousNamespaceFunction and
65-
localFunctionType = "Static"
66-
}
67-
68-
/** Gets the type of local function. */
69-
string getLocalFunctionType() { result = localFunctionType }
21+
module UnusedLocalFunctionConfig implements UnusedLocalFunctionConfigSig {
22+
Query getQuery() { result = DeadCodePackage::unusedLocalFunctionQuery() }
7023
}
7124

72-
from LocalFunction unusedLocalFunction, string name
73-
where
74-
not isExcluded(unusedLocalFunction, DeadCodePackage::unusedLocalFunctionQuery()) and
75-
// No static or dynamic call target for this function
76-
not unusedLocalFunction = getTarget(_) and
77-
// If this is a TemplateFunction or an instantiation of a template, then only report it as unused
78-
// if all other instantiations of the template are unused
79-
not exists(
80-
Function functionFromUninstantiatedTemplate, Function functionFromInstantiatedTemplate
81-
|
82-
// `unusedLocalFunction` is a template instantiation from `functionFromUninstantiatedTemplate`
83-
unusedLocalFunction.isConstructedFrom(functionFromUninstantiatedTemplate)
84-
or
85-
// `unusedLocalFunction` is from an uninstantiated template
86-
unusedLocalFunction = functionFromUninstantiatedTemplate
87-
|
88-
// There exists an instantiation which is called
89-
functionFromInstantiatedTemplate.isConstructedFrom(functionFromUninstantiatedTemplate) and
90-
functionFromInstantiatedTemplate = getTarget(_)
91-
) and
92-
// A function is defined as "used" if any one of the following holds true:
93-
// - It's an explicitly deleted functions e.g. =delete
94-
// - It's annotated as "[[maybe_unused]]"
95-
// - It's part of an overloaded set and any one of the overloaded instance
96-
// is called.
97-
// - It's an operand of an expression in an unevaluated context.
98-
not unusedLocalFunction.isDeleted() and
99-
not unusedLocalFunction.getAnAttribute().getName() = "maybe_unused" and
100-
not overloadedFunctionIsCalled(unusedLocalFunction) and
101-
not addressBeenTaken(unusedLocalFunction) and
102-
// Get a printable name
103-
(
104-
if exists(unusedLocalFunction.getQualifiedName())
105-
then name = unusedLocalFunction.getQualifiedName()
106-
else name = unusedLocalFunction.getName()
107-
)
108-
select unusedLocalFunction,
109-
unusedLocalFunction.getLocalFunctionType() + " function " + name +
110-
" is not statically called, or is in an unused template."
25+
import UnusedLocalFunction<UnusedLocalFunctionConfig>

cpp/autosar/test/rules/A0-1-3/UnusedLocalFunction.expected

Lines changed: 0 additions & 6 deletions
This file was deleted.

cpp/autosar/test/rules/A0-1-3/UnusedLocalFunction.qlref

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cpp/common/test/rules/unusedlocalfunction/UnusedLocalFunction.ql
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
2+
import cpp
3+
import RuleMetadata
4+
import codingstandards.cpp.exclusions.RuleMetadata
5+
6+
newtype DeadCode10Query = TUnusedLimitedVisibilityFunctionQuery()
7+
8+
predicate isDeadCode10QueryMetadata(Query query, string queryId, string ruleId, string category) {
9+
query =
10+
// `Query` instance for the `unusedLimitedVisibilityFunction` query
11+
DeadCode10Package::unusedLimitedVisibilityFunctionQuery() and
12+
queryId =
13+
// `@id` for the `unusedLimitedVisibilityFunction` query
14+
"cpp/misra/unused-limited-visibility-function" and
15+
ruleId = "RULE-0-2-4" and
16+
category = "advisory"
17+
}
18+
19+
module DeadCode10Package {
20+
Query unusedLimitedVisibilityFunctionQuery() {
21+
//autogenerate `Query` type
22+
result =
23+
// `Query` type for `unusedLimitedVisibilityFunction` query
24+
TQueryCPP(TDeadCode10PackageQuery(TUnusedLimitedVisibilityFunctionQuery()))
25+
}
26+
}

cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import Const
1919
import Conversions
2020
import Conversions2
2121
import DeadCode
22+
import DeadCode10
2223
import DeadCode11
2324
import DeadCode3
2425
import DeadCode4
@@ -111,6 +112,7 @@ newtype TCPPQuery =
111112
TConversionsPackageQuery(ConversionsQuery q) or
112113
TConversions2PackageQuery(Conversions2Query q) or
113114
TDeadCodePackageQuery(DeadCodeQuery q) or
115+
TDeadCode10PackageQuery(DeadCode10Query q) or
114116
TDeadCode11PackageQuery(DeadCode11Query q) or
115117
TDeadCode3PackageQuery(DeadCode3Query q) or
116118
TDeadCode4PackageQuery(DeadCode4Query q) or
@@ -203,6 +205,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
203205
isConversionsQueryMetadata(query, queryId, ruleId, category) or
204206
isConversions2QueryMetadata(query, queryId, ruleId, category) or
205207
isDeadCodeQueryMetadata(query, queryId, ruleId, category) or
208+
isDeadCode10QueryMetadata(query, queryId, ruleId, category) or
206209
isDeadCode11QueryMetadata(query, queryId, ruleId, category) or
207210
isDeadCode3QueryMetadata(query, queryId, ruleId, category) or
208211
isDeadCode4QueryMetadata(query, queryId, ruleId, category) or
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* Provides a configurable module UnusedLocalFunction with a `problems` predicate
3+
* for the following issue:
4+
* Unused functions may indicate a coding error or require maintenance; functions that
5+
* are unused with certain visibility have no effect on the program and should be
6+
* removed.
7+
*/
8+
9+
import cpp
10+
import codingstandards.cpp.Customizations
11+
import codingstandards.cpp.Exclusions
12+
import codingstandards.cpp.DynamicCallGraph
13+
import codingstandards.cpp.deadcode.UnusedFunctions
14+
15+
/**
16+
* Checks if an overloaded function of
17+
* the function passed in the arguments, is called.
18+
*/
19+
predicate overloadedFunctionIsCalled(Function unusedFunction) {
20+
exists(Function f | f = unusedFunction.getAnOverload() and f = getTarget(_))
21+
}
22+
23+
/** Checks if a Function's address was taken. */
24+
predicate addressBeenTaken(Function unusedFunction) {
25+
exists(FunctionAccess fa | fa.getTarget() = unusedFunction)
26+
}
27+
28+
/** A `Function` nested in an anonymous namespace. */
29+
class AnonymousNamespaceFunction extends Function {
30+
AnonymousNamespaceFunction() { getNamespace().getParentNamespace*().isAnonymous() }
31+
}
32+
33+
/**
34+
* A function which is "local" to a particular scope or translation unit.
35+
*/
36+
class LocalFunction extends UnusedFunctions::UsableFunction {
37+
string localFunctionType;
38+
39+
LocalFunction() {
40+
this.(MemberFunction).isPrivate() and
41+
localFunctionType = "Private member"
42+
or
43+
// A function in an anonymous namespace (which is deduced to have internal linkage)
44+
this instanceof AnonymousNamespaceFunction and
45+
not this instanceof MemberFunction and
46+
localFunctionType = "Anonymous namespace"
47+
or
48+
// Class members in anonymous namespaces also have internal linkage.
49+
this instanceof AnonymousNamespaceFunction and
50+
this instanceof MemberFunction and
51+
localFunctionType = "Anonymous namespace class member"
52+
or
53+
// Static functions with internal linkage
54+
this.isStatic() and
55+
// Member functions never have internal linkage
56+
not this instanceof MemberFunction and
57+
// Functions in anonymous namespaces automatically have the "static" specifier added by the
58+
// extractor. We therefore excluded them from this case, and instead report them in the
59+
// anonymous namespace, as we don't know whether the "static" specifier was explicitly
60+
// provided by the user.
61+
not this instanceof AnonymousNamespaceFunction and
62+
localFunctionType = "Static"
63+
}
64+
65+
/** Gets the type of local function. */
66+
string getLocalFunctionType() { result = localFunctionType }
67+
}
68+
69+
signature module UnusedLocalFunctionConfigSig {
70+
Query getQuery();
71+
}
72+
73+
module UnusedLocalFunction<UnusedLocalFunctionConfigSig Config> {
74+
query predicate problems(LocalFunction unusedLocalFunction, string message) {
75+
not isExcluded(unusedLocalFunction, Config::getQuery()) and
76+
// No static or dynamic call target for this function
77+
not unusedLocalFunction = getTarget(_) and
78+
// If this is a TemplateFunction or an instantiation of a template, then only report it as unused
79+
// if all other instantiations of the template are unused
80+
not exists(
81+
Function functionFromUninstantiatedTemplate, Function functionFromInstantiatedTemplate
82+
|
83+
// `unusedLocalFunction` is a template instantiation from `functionFromUninstantiatedTemplate`
84+
unusedLocalFunction.isConstructedFrom(functionFromUninstantiatedTemplate)
85+
or
86+
// `unusedLocalFunction` is from an uninstantiated template
87+
unusedLocalFunction = functionFromUninstantiatedTemplate
88+
|
89+
// There exists an instantiation which is called
90+
functionFromInstantiatedTemplate.isConstructedFrom(functionFromUninstantiatedTemplate) and
91+
functionFromInstantiatedTemplate = getTarget(_)
92+
) and
93+
// A function is defined as "used" if any one of the following holds true:
94+
// - It's an explicitly deleted functions e.g. =delete
95+
// - It's annotated as "[[maybe_unused]]"
96+
// - It's part of an overloaded set and any one of the overloaded instance
97+
// is called.
98+
// - It's an operand of an expression in an unevaluated context.
99+
not unusedLocalFunction.isDeleted() and
100+
not unusedLocalFunction.getAnAttribute().getName() = "maybe_unused" and
101+
not overloadedFunctionIsCalled(unusedLocalFunction) and
102+
not addressBeenTaken(unusedLocalFunction) and
103+
message =
104+
unusedLocalFunction.getLocalFunctionType() + " function " + unusedLocalFunction.getName() +
105+
" is not statically called, or is in an unused template."
106+
}
107+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| test.cpp:3:13:3:14 | f1 | Static function f1 is not statically called, or is in an unused template. |
2+
| test.cpp:21:29:21:33 | getAT | Static function getAT is not statically called, or is in an unused template. |
3+
| test.cpp:45:8:45:9 | g2 | Private member function g2 is not statically called, or is in an unused template. |
4+
| test.cpp:60:5:60:9 | getAT | Private member function getAT is not statically called, or is in an unused template. |
5+
| test.cpp:81:6:81:7 | h2 | Anonymous namespace function h2 is not statically called, or is in an unused template. |
6+
| test.cpp:85:6:85:7 | h3 | Anonymous namespace function h3 is not statically called, or is in an unused template. |
7+
| test.cpp:144:8:144:8 | f | Anonymous namespace class member function f is not statically called, or is in an unused template. |
8+
| test.cpp:150:8:150:8 | f | Anonymous namespace class member function f is not statically called, or is in an unused template. |
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// GENERATED FILE - DO NOT MODIFY
2+
import codingstandards.cpp.rules.unusedlocalfunction.UnusedLocalFunction
3+
4+
module TestFileConfig implements UnusedLocalFunctionConfigSig {
5+
Query getQuery() { result instanceof TestQuery }
6+
}
7+
8+
import UnusedLocalFunction<TestFileConfig>

0 commit comments

Comments
 (0)