Skip to content

Commit 515d56d

Browse files
authored
Merge branch 'main' into michaelrfairhurst/deadcode-5-rule-0-1-1
2 parents 0de9092 + 4e60680 commit 515d56d

26 files changed

+926
-322
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
- All rules using `Linkage.qll`:
2+
- `extern const` global variables are now properly analyzed as having external linkage, rather than internal linkage.
3+
- Linkage analysis has been fixed to properly handle nested classes, including anonymous and typedefs of anonymous classes.
4+
- Linkage for names within classes with internal linkage is now properly inherited as internal, rather than external.
5+
- `M0-1-3`, `RULE-2-8` - `UnusedLocalVariable.ql`, `UnusedMemberVariable.ql`, `UnusedGlobalOrNamespaceVariable.ql`, `UnusedObjectDefinition.ql`, `UnusedObjectDefinitionStrict.ql`:
6+
- The organization of unused variable analysis has been reorganized to be usable in MISRA C++ rule 0.2.1, with no expected noticeable change in results.

cpp/autosar/src/rules/M0-1-3/UnusedGlobalOrNamespaceVariable.ql

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ import cpp
1818
import codingstandards.cpp.autosar
1919
import codingstandards.cpp.deadcode.UnusedVariables
2020

21-
from PotentiallyUnusedGlobalOrNamespaceVariable v
22-
where
23-
not isExcluded(v, DeadCodePackage::unusedGlobalOrNamespaceVariableQuery()) and
24-
// No variable access
25-
not exists(v.getAnAccess()) and
26-
// Exclude members whose value is compile time and is potentially used to inintialize a template
27-
not maybeACompileTimeTemplateArgument(v)
21+
from FullyUnusedGlobalOrNamespaceVariable v
22+
where not isExcluded(v, DeadCodePackage::unusedGlobalOrNamespaceVariableQuery())
2823
select v, "Variable '" + v.getQualifiedName() + "' is unused."

cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -18,58 +18,6 @@ import cpp
1818
import codingstandards.cpp.autosar
1919
import codingstandards.cpp.deadcode.UnusedVariables
2020

21-
// Collect constant values that we should use to exclude otherwise unused constexpr variables.
22-
//
23-
// For constexpr variables used as template arguments or in static_asserts, we don't see accesses
24-
// (just the appropriate literals). We therefore take a conservative approach and do not report
25-
// constexpr variables whose values are used in such contexts.
26-
//
27-
// For performance reasons, these special values should be collected in a single pass.
28-
predicate excludedConstantValue(string value) {
29-
value = any(ClassTemplateInstantiation cti).getTemplateArgument(_).(Expr).getValue()
30-
or
31-
value = any(StaticAssert sa).getCondition().getAChild*().getValue()
32-
}
33-
34-
/**
35-
* Defines the local variables that should be excluded from the unused variable analysis based
36-
* on their constant value.
37-
*
38-
* See `excludedConstantValue` for more details.
39-
*/
40-
predicate excludeVariableByValue(Variable variable) {
41-
variable.isConstexpr() and
42-
excludedConstantValue(getConstExprValue(variable))
43-
}
44-
45-
// TODO: This predicate may be possible to merge with M0-1-4's getUseCount(). These two rules
46-
// diverged to handle `excludeVariableByValue`, but may be possible to merge.
47-
int getUseCountConservatively(Variable v) {
48-
result =
49-
count(VariableAccess access | access = v.getAnAccess()) +
50-
count(UserProvidedConstructorFieldInit cfi | cfi.getTarget() = v) +
51-
// In case an array type uses a constant in the same scope as the constexpr variable,
52-
// consider it as used.
53-
countUsesInLocalArraySize(v)
54-
}
55-
56-
predicate isConservativelyUnused(Variable v) {
57-
getUseCountConservatively(v) = 0 and
58-
not excludeVariableByValue(v)
59-
}
60-
61-
from PotentiallyUnusedLocalVariable v
62-
where
63-
not isExcluded(v, DeadCodePackage::unusedLocalVariableQuery()) and
64-
// Local variable is never accessed
65-
not exists(v.getAnAccess()) and
66-
// Sometimes multiple objects representing the same entities are created in
67-
// the AST. Check if those are not accessed as well. Refer issue #658
68-
not exists(LocalScopeVariable another |
69-
another.getDefinitionLocation() = v.getDefinitionLocation() and
70-
another.hasName(v.getName()) and
71-
exists(another.getAnAccess()) and
72-
another != v
73-
) and
74-
isConservativelyUnused(v)
21+
from FullyUnusedLocalVariable v
22+
where not isExcluded(v, DeadCodePackage::unusedLocalVariableQuery())
7523
select v, "Local variable '" + v.getName() + "' in '" + v.getFunction().getName() + "' is not used."

cpp/autosar/src/rules/M0-1-3/UnusedMemberVariable.ql

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,6 @@ import codingstandards.cpp.autosar
1919
import codingstandards.cpp.FunctionEquivalence
2020
import codingstandards.cpp.deadcode.UnusedVariables
2121

22-
from PotentiallyUnusedMemberVariable v
23-
where
24-
not isExcluded(v, DeadCodePackage::unusedMemberVariableQuery()) and
25-
// No variable access
26-
not exists(v.getAnAccess()) and
27-
// No explicit initialization in a constructor
28-
not exists(UserProvidedConstructorFieldInit cfi | cfi.getTarget() = v) and
29-
// Exclude members whose value is compile time and is potentially used to inintialize a template
30-
not maybeACompileTimeTemplateArgument(v)
22+
from FullyUnusedMemberVariable v
23+
where not isExcluded(v, DeadCodePackage::unusedMemberVariableQuery())
3124
select v, "Member variable '" + v.getName() + "' is unused."

cpp/autosar/src/rules/M0-1-4/SingleUseGlobalOrNamespacePODVariable.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import codingstandards.cpp.autosar
1919
import codingstandards.cpp.deadcode.UnusedVariables
2020
import SingleUsePODVariable
2121

22-
from PotentiallyUnusedGlobalOrNamespaceVariable v
22+
from SecondPass::UnusedGlobalOrNamespaceVariable v
2323
where
2424
not isExcluded(v, DeadCodePackage::singleUseGlobalOrNamespacePODVariableQuery()) and
2525
isSingleUseNonVolatilePODVariable(v)

cpp/autosar/src/rules/M0-1-4/SingleUseLocalPODVariable.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import codingstandards.cpp.autosar
1919
import codingstandards.cpp.deadcode.UnusedVariables
2020
import SingleUsePODVariable
2121

22-
from PotentiallyUnusedLocalVariable v
22+
from SecondPass::UnusedLocalVariable v
2323
where
2424
not isExcluded(v, DeadCodePackage::singleUseLocalPODVariableQuery()) and
2525
isSingleUseNonVolatilePODVariable(v)

cpp/autosar/src/rules/M0-1-4/SingleUseMemberPODVariable.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import codingstandards.cpp.autosar
1919
import codingstandards.cpp.deadcode.UnusedVariables
2020
import SingleUsePODVariable
2121

22-
from PotentiallyUnusedMemberVariable v
22+
from SecondPass::UnusedMemberVariable v
2323
where
2424
not isExcluded(v, DeadCodePackage::singleUseMemberPODVariableQuery()) and
2525
isSingleUseNonVolatilePODVariable(v)

cpp/common/src/codingstandards/cpp/Linkage.qll

Lines changed: 90 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,35 @@
55
import cpp
66
import codingstandards.cpp.Scope
77

8+
/**
9+
* [basic]/6 uses a specific definition of "variable" that excludes non-static data members.
10+
*/
11+
private predicate isSpecificationVariable(Variable v) {
12+
v.(MemberVariable).isStatic()
13+
or
14+
not v instanceof MemberVariable
15+
}
16+
817
/** Holds if `elem` has internal linkage. */
918
predicate hasInternalLinkage(Element elem) {
19+
// An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage
20+
directlyOrIndirectlyUnnnamedNamespace(elem)
21+
or
1022
exists(Declaration decl | decl = elem |
1123
// A name having namespace scope has internal linkage if it is the name of
1224
hasNamespaceScope(decl) and
1325
(
1426
// a variable, function or function template
1527
(
16-
decl instanceof Variable
28+
isSpecificationVariable(decl)
1729
or
1830
decl instanceof Function // TemplateFunction is a subclass of Function so this captures both.
1931
) and
2032
// that is explicitly declared static; or,
2133
decl.isStatic()
2234
or
2335
// a non-volatile variable
24-
decl instanceof Variable and
36+
isSpecificationVariable(decl) and
2537
not decl.(Variable).isVolatile() and
2638
// that is explicitly declared const or constexpr and
2739
(decl.(Variable).isConst() or decl.(Variable).isConstexpr()) and
@@ -32,131 +44,93 @@ predicate hasInternalLinkage(Element elem) {
3244
exists(Union u | hasNamespaceScope(u) and u.isAnonymous() |
3345
decl = u.getACanonicalMemberVariable()
3446
)
35-
or
36-
// A name having namespace scope that has not been given internal linkage above has the same linkage as the enclosing namespace if it is the name of
37-
hasInternalLinkage(decl.getNamespace()) and
38-
(
39-
// a variable;
40-
decl instanceof Variable
41-
or
42-
// a function
43-
decl instanceof Function
44-
or
45-
// a named class, or an unnamed class defined in a typedef declartion in which the class has the typedef name for linkage purposes
46-
exists(Class klass | decl = klass |
47-
not klass.isAnonymous()
48-
or
49-
klass.isAnonymous() and exists(TypedefType typedef | typedef.getADeclaration() = klass)
50-
)
51-
or
52-
// a named enumeration, or an unnamed enumeration defined in a typedef declaration in which the enumeration has the typedef name for linkage purposes
53-
exists(Enum enum | enum = decl |
54-
not enum.isAnonymous()
55-
or
56-
enum.isAnonymous() and exists(TypedefType typedef | typedef.getADeclaration() = enum)
57-
)
58-
or
59-
// an enumerator beloning to an enumeration with linkage
60-
exists(Enum enum | enum.getADeclaration() = decl | hasInternalLinkage(enum))
61-
or
62-
// a template
63-
decl instanceof TemplateClass
64-
or
65-
decl instanceof TemplateFunction
66-
)
6747
)
6848
or
69-
decl instanceof GlobalVariable and
70-
(
71-
decl.(GlobalVariable).isStatic() or
72-
decl.(GlobalVariable).isConst()
73-
) and
74-
not decl.(GlobalVariable).hasSpecifier("external")
75-
)
76-
or
77-
// An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage
78-
exists(Namespace ns | ns = elem |
79-
ns.isAnonymous()
49+
directlyOrIndirectlyUnnnamedNamespace(decl.getNamespace()) and
50+
inheritsLinkageOfNamespace(decl.getNamespace(), decl)
8051
or
81-
not ns.isAnonymous() and
82-
exists(Namespace parent | parent.isAnonymous() and parent.getAChildNamespace+() = ns)
52+
exists(Class klass |
53+
hasInternalLinkage(klass) and
54+
inheritsLinkageOfClass(klass, decl)
55+
)
8356
)
84-
or
85-
elem instanceof TopLevelFunction and
86-
elem.(Function).isStatic()
8757
}
8858

8959
/** Holds if `elem` has external linkage. */
9060
predicate hasExternalLinkage(Element elem) {
61+
elem instanceof Namespace and
62+
not directlyOrIndirectlyUnnnamedNamespace(elem)
63+
or
9164
not hasInternalLinkage(elem) and
92-
(
93-
exists(Declaration decl | decl = elem |
94-
hasNamespaceScope(decl) and
95-
// A name having namespace scope that has not been given internal linkage above has the same linkage as the enclosing namespace if it is the name of
96-
not hasInternalLinkage(decl.getNamespace()) and
97-
(
98-
// a variable;
99-
decl instanceof Variable
100-
or
101-
// a function
102-
decl instanceof Function
103-
or
104-
// a named class, or an unnamed class defined in a typedef declaration in which the class has the typedef name for linkage purposes
105-
exists(Class klass | decl = klass |
106-
not klass.isAnonymous()
107-
or
108-
klass.isAnonymous() and exists(TypedefType typedef | typedef.getADeclaration() = klass)
109-
)
110-
or
111-
// a named enumeration, or an unnamed enumeration defined in a typedef declaration in which the enumeration has the typedef name for linkage purposes
112-
exists(Enum enum | enum = decl |
113-
not enum.isAnonymous()
114-
or
115-
enum.isAnonymous() and exists(TypedefType typedef | typedef.getADeclaration() = enum)
116-
)
117-
or
118-
// an enumerator beloning to an enumeration with linkage
119-
exists(Enum enum | enum.getADeclaration() = decl | hasInternalLinkage(enum))
120-
or
121-
// a template
122-
decl instanceof TemplateClass
123-
or
124-
decl instanceof TemplateFunction
125-
)
126-
or
127-
// In addition,
128-
hasClassScope(decl) and
129-
(
130-
// a member function,
131-
decl instanceof MemberFunction
132-
or
133-
// static data member
134-
decl instanceof MemberVariable and decl.(MemberVariable).isStatic()
135-
or
136-
// a named class, or an unnamed class defined in a typedef declartion in which the class has the typedef name for linkage purposes
137-
exists(Class klass | decl = klass |
138-
not klass.isAnonymous()
139-
or
140-
klass.isAnonymous() and exists(TypedefType typedef | typedef.getADeclaration() = klass)
141-
)
142-
or
143-
// a named enumeration, or an unnamed enumeration defined in a typedef declaration in which the enumeration has the typedef name for linkage purposes
144-
exists(Enum enum | enum = decl |
145-
not enum.isAnonymous()
146-
or
147-
enum.isAnonymous() and exists(TypedefType typedef | typedef.getADeclaration() = enum)
148-
)
149-
) and
150-
// has external linkage if the name of the class has external linkage
151-
hasExternalLinkage(decl.getDeclaringType())
152-
or
153-
decl instanceof GlobalVariable and
154-
not decl.(GlobalVariable).isStatic() and
155-
not decl.(GlobalVariable).isConst()
65+
exists(Declaration decl | decl = elem |
66+
// A name having namespace scope that has not been given internal linkage above has the same linkage as the enclosing namespace if it is the name of
67+
not directlyOrIndirectlyUnnnamedNamespace(decl.getNamespace()) and
68+
inheritsLinkageOfNamespace(decl.getNamespace(), decl)
69+
or
70+
exists(Class klass |
71+
hasExternalLinkage(klass) and
72+
inheritsLinkageOfClass(klass, decl)
15673
)
74+
)
75+
}
76+
77+
private predicate directlyOrIndirectlyUnnnamedNamespace(Namespace ns) {
78+
exists(Namespace anonymous |
79+
anonymous.isAnonymous() and
80+
ns = anonymous.getAChildNamespace*()
81+
)
82+
}
83+
84+
private predicate hasLinkageOfTypedef(TypedefType typedef, Element decl) {
85+
// an unnamed class defined in a typedef declartion in which the class has the typedef name for linkage purposes
86+
decl.(Class).isAnonymous() and typedef.getADeclaration() = decl
87+
or
88+
// an unnamed enumeration defined in a typedef declaration in which the enumeration has the typedef name for linkage purposes
89+
decl.(Enum).isAnonymous() and typedef.getADeclaration() = decl
90+
}
91+
92+
private predicate inheritsLinkageOfNamespace(Namespace ns, Declaration decl) {
93+
hasNamespaceScope(decl) and
94+
ns = decl.getNamespace() and
95+
(
96+
// A name having namespace scope that has not been given internal linkage above has the same linkage as the enclosing namespace if it is the name of
97+
// a variable;
98+
isSpecificationVariable(decl)
99+
or
100+
// a function
101+
decl instanceof Function
102+
or
103+
decl instanceof Class and not decl.(Class).isAnonymous() // a named class
104+
or
105+
decl instanceof Enum and not decl.(Enum).isAnonymous() // a named enumeration
106+
or
107+
// a template
108+
decl instanceof TemplateClass
109+
or
110+
decl instanceof TemplateFunction
111+
or
112+
decl instanceof TemplateVariable
113+
)
114+
or
115+
hasNamespaceScope(decl) and
116+
exists(TypedefType typedef | hasLinkageOfTypedef(typedef, decl) and ns = typedef.getNamespace())
117+
}
118+
119+
private predicate inheritsLinkageOfClass(Class klass, Element decl) {
120+
hasClassScope(decl) and
121+
(
122+
// a member function,
123+
decl.(MemberFunction).getDeclaringType() = klass
124+
or
125+
// static data member
126+
decl.(MemberVariable).isStatic() and decl.(MemberVariable).getDeclaringType() = klass
157127
or
158-
elem instanceof Namespace
128+
decl.(Class).getDeclaringType() = klass and not decl.(Class).isAnonymous()
159129
or
160-
elem instanceof TopLevelFunction
130+
decl.(Enum).getDeclaringType() = klass and not decl.(Enum).isAnonymous()
131+
or
132+
exists(TypedefType typedef |
133+
hasLinkageOfTypedef(typedef, decl) and klass = typedef.getDeclaringType()
134+
)
161135
)
162136
}

cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,16 @@ import codingstandards.cpp.alertreporting.DeduplicateMacroResults
1717
class UnusedObjectDefinition extends VariableDeclarationEntry {
1818
UnusedObjectDefinition() {
1919
(
20-
getVariable() instanceof BasePotentiallyUnusedLocalVariable
20+
getVariable() instanceof FirstPass::UnusedLocalVariable
2121
or
22-
getVariable() instanceof BasePotentiallyUnusedGlobalOrNamespaceVariable
22+
getVariable() instanceof FirstPass::UnusedGlobalOrNamespaceVariable
2323
) and
24-
not exists(VariableAccess access | access.getTarget() = getVariable()) and
25-
getVariable().getDefinition() = this
24+
getVariable().getDefinition() = this and
25+
not exists(getVariable().getAnAccess())
2626
}
2727

2828
/* Dead objects with these attributes are reported in the "strict" queries. */
29-
predicate hasAttrUnused() {
30-
getVariable().getAnAttribute().hasName(["unused", "used", "maybe_unused", "cleanup"])
31-
}
29+
predicate hasAttrUnused() { hasAttrUnused(getVariable()) }
3230
}
3331

3432
/* Configuration to use the `DedupMacroResults` module to reduce alert noise */

0 commit comments

Comments
 (0)