Skip to content

Commit eef430c

Browse files
committed
Fixes issue no. 121
1 parent c5bf50b commit eef430c

File tree

3 files changed

+118
-2
lines changed

3 files changed

+118
-2
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Considered use cases mentioned on issue [121](https://github.com/github/codeql-coding-standards/issues/121) while reporting a local function as "unused".

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

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

22+
/** Checks if a function call exists to the function
23+
* passed in the arguments.
24+
*/
25+
predicate isCalled(Function unusedFunction) {
26+
exists (FunctionCall f | unusedFunction.getACallToThisFunction() = f)
27+
}
28+
29+
/** Checks if an overloaded function of
30+
* the function passed in the arguments, is called.
31+
*/
32+
predicate overloadedFunctionIsCalled(Function unusedFunction) {
33+
exists (Function f | f = unusedFunction.getAnOverload*() and isCalled(f))
34+
or
35+
unusedFunction.getNamespace().isAnonymous() and
36+
exists (TopLevelFunction overloadedFunction |
37+
overloadedFunction != unusedFunction and
38+
((overloadedFunction.getName() = unusedFunction.getName()) or
39+
(overloadedFunction.getQualifiedName() =
40+
unusedFunction.getQualifiedName()))
41+
)
42+
}
43+
44+
/** Checks if a Function is part of an unevaluated context. */
45+
predicate partOfUnevalutedContexts(Function unusedFunction) {
46+
exists (Expr e, FunctionCall f | ((e instanceof TypeidOperator or
47+
e instanceof SizeofOperator or
48+
e instanceof NoExceptExpr) and
49+
e.getAChild*() = f and f.getTarget() = unusedFunction
50+
)
51+
)
52+
}
53+
54+
/** Checks if a Function's address was taken. */
55+
predicate addressBeenTaken(Function unusedFunction)
56+
{
57+
exists (FunctionAccess fa | fa.getTarget() = unusedFunction)
58+
}
59+
2260
/** A `Function` nested in an anonymous namespace. */
2361
class AnonymousNamespaceFunction extends Function {
2462
AnonymousNamespaceFunction() { getNamespace().getParentNamespace*().isAnonymous() }
@@ -75,7 +113,22 @@ where
75113
// There exists an instantiation which is called
76114
functionFromInstantiatedTemplate.isConstructedFrom(functionFromUninstantiatedTemplate) and
77115
functionFromInstantiatedTemplate = getTarget(_)
78-
) and
116+
)
117+
and
118+
// A function is defined as "used" if any one of the following holds true:
119+
// - It's an explicitly deleted functions e.g. =delete
120+
// - It's annotated as "[[maybe_unused]]"
121+
// - It's part of an overloaded set and any one of the overloaded instance
122+
// is called.
123+
// - It's an operand of an expression in an unevaluated context.
124+
(
125+
not unusedLocalFunction.isDeleted() and
126+
not unusedLocalFunction.getAnAttribute().getName() = "maybe_unused" and
127+
not overloadedFunctionIsCalled(unusedLocalFunction) and
128+
not addressBeenTaken(unusedLocalFunction) and
129+
not partOfUnevalutedContexts(unusedLocalFunction)
130+
)
131+
and
79132
// Get a printable name
80133
(
81134
if exists(unusedLocalFunction.getQualifiedName())

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

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,66 @@ namespace bar {
8585
void h3() {} // NON_COMPLIANT
8686
} // namespace bar
8787
} // namespace foo
88-
} // namespace
88+
} // namespace
89+
90+
91+
92+
static int unevaluatedContextFn(int x) { x++; return x; } // COMPLIANT - called in an unevaluated context.
93+
#include <typeinfo>
94+
static int unevalContextCaller() // COMPLIANT - address taken
95+
{
96+
97+
typeid(unevaluatedContextFn(0));
98+
sizeof(unevaluatedContextFn(1));
99+
noexcept(unevaluatedContextFn(2));
100+
decltype(unevaluatedContextFn(2)) n = 42;
101+
return 0;
102+
}
103+
int (* ptr_unevalContextCaller)(void) = unevalContextCaller;
104+
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) // COMPLAINT - overload1(int) is called.
120+
{
121+
return c+d;
122+
}
123+
124+
namespace
125+
{
126+
float overload1(int c, float d) // COMPLAINT - overload1(int) is called.
127+
{
128+
return c+d;
129+
}
130+
}
131+
132+
int overload = overload1(5);
133+
134+
class classWithOverloads
135+
{
136+
public:
137+
int caller(int x)
138+
{
139+
return overloadMember(x,0);
140+
}
141+
private:
142+
int overloadMember(int c) // COMPLAINT - overloadMember(int, int) is called.
143+
{
144+
return ++c;
145+
}
146+
int overloadMember(int c, int d) // COMPLAINT - called.
147+
{
148+
return c+d;
149+
}
150+
};

0 commit comments

Comments
 (0)