Skip to content

Commit e47e0ae

Browse files
authored
Merge pull request github#347 from rak3-sh/rp/a0-1-3-improvements
Consider additional use-cases to conclude a function as "used"
2 parents e43fbbc + 9396451 commit e47e0ae

File tree

4 files changed

+89
-3
lines changed

4 files changed

+89
-3
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
- `A0-1-3` - Considered the following additional use cases while reporting a local function as "unused".
2+
- The address of a function is taken
3+
- The operand of an expression in an unevaluated context
4+
- Functions marked with [[maybe_unused]]
5+
- Explicitly deleted functions e.g. =delete
6+
- Use of any overload of a function in an overload set constitute a use of all members of the set. An overload set is a set of functions with the same name that differ in the number, type and/or qualifiers of their parameters, and, for the purpose of this query, are limited to functions which are declared in the same scope (namespace or class).

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

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ import codingstandards.cpp.autosar
1919
import codingstandards.cpp.DynamicCallGraph
2020
import codingstandards.cpp.deadcode.UnusedFunctions
2121

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+
{
33+
exists (FunctionAccess fa | fa.getTarget() = unusedFunction)
34+
}
35+
2236
/** A `Function` nested in an anonymous namespace. */
2337
class AnonymousNamespaceFunction extends Function {
2438
AnonymousNamespaceFunction() { getNamespace().getParentNamespace*().isAnonymous() }
@@ -75,7 +89,19 @@ where
7589
// There exists an instantiation which is called
7690
functionFromInstantiatedTemplate.isConstructedFrom(functionFromUninstantiatedTemplate) and
7791
functionFromInstantiatedTemplate = getTarget(_)
78-
) and
92+
)
93+
and
94+
// A function is defined as "used" if any one of the following holds true:
95+
// - It's an explicitly deleted functions e.g. =delete
96+
// - It's annotated as "[[maybe_unused]]"
97+
// - It's part of an overloaded set and any one of the overloaded instance
98+
// is called.
99+
// - It's an operand of an expression in an unevaluated context.
100+
not unusedLocalFunction.isDeleted() and
101+
not unusedLocalFunction.getAnAttribute().getName() = "maybe_unused" and
102+
not overloadedFunctionIsCalled(unusedLocalFunction) and
103+
not addressBeenTaken(unusedLocalFunction)
104+
and
79105
// Get a printable name
80106
(
81107
if exists(unusedLocalFunction.getQualifiedName())

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

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,55 @@ namespace bar {
8585
void h3() {} // NON_COMPLIANT
8686
} // namespace bar
8787
} // namespace foo
88-
} // namespace
88+
} // namespace
89+
90+
static int unevaluatedContextFn(int x) {
91+
x++;
92+
return x;
93+
} // COMPLIANT - called in an unevaluated context.
94+
#include <typeinfo>
95+
static int unevalContextCaller() // COMPLIANT - address taken
96+
{
97+
98+
typeid(unevaluatedContextFn(0));
99+
sizeof(unevaluatedContextFn(1));
100+
noexcept(unevaluatedContextFn(2));
101+
decltype(unevaluatedContextFn(2)) n = 42;
102+
return 0;
103+
}
104+
int (*ptr_unevalContextCaller)(void) = unevalContextCaller;
105+
106+
class X {
107+
private:
108+
[[maybe_unused]] void maybeUnused();
109+
void deleted() = delete; // COMPLIANT - Deleted Function
110+
};
111+
112+
void X::maybeUnused() {} // COMPLIANT - [[maybe_unused]]
113+
114+
static int overload1(int c) // COMPLIANT - called
115+
{
116+
return ++c;
117+
}
118+
119+
static int overload1(int c, int d) // COMPLIANT - overload1(int) is called.
120+
{
121+
return c + d;
122+
}
123+
124+
int overload = overload1(5);
125+
126+
class classWithOverloads {
127+
public:
128+
int caller(int x) { return overloadMember(x, 0); }
129+
130+
private:
131+
int overloadMember(int c) // COMPLIANT - overloadMember(int, int) is called.
132+
{
133+
return ++c;
134+
}
135+
int overloadMember(int c, int d) // COMPLIANT - called.
136+
{
137+
return c + d;
138+
}
139+
};

rule_packages/cpp/DeadCode.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@
6767
"tags": [
6868
"readability",
6969
"maintainability"
70-
]
70+
],
71+
"implementation_scope": {
72+
"description": "Use of any overload of a function in an overload set constitute a use of all members of the set. An overload set is a set of functions with the same name that differ in the number, type and/or qualifiers of their parameters, and, for the purpose of this query, are limited to functions which are declared in the same scope (namespace or class). Functions defined in anonymous (unnamed) namespaces and global namespaces are therefore not currently considered to be part of the same overload set."
73+
}
7174
}
7275
],
7376
"title": "Every function defined in an anonymous namespace, or static function with internal linkage, or private member function shall be used."

0 commit comments

Comments
 (0)