Skip to content

Commit ff2eb72

Browse files
Update Linkage.qll to clean up implementation and fix linkage bugs.
1 parent 0083f2e commit ff2eb72

File tree

10 files changed

+261
-145
lines changed

10 files changed

+261
-145
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
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.
7+
- New filtering passes begin by filtering out variables that have an existing access (`.getAnAccess()`), instead of performing such a filter step last, with a measured small reduction in overall tuple counts and improved overall query performance.

change_notes/2026-02-12-unused-variable-reorganization.md

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

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/test/Linkage/ExternalLinkage.expected

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
| file://:0:0:0:0 | operator= | Element has external linkage |
55
| test.cpp:1:5:1:6 | g1 | Element has external linkage |
66
| test.cpp:2:12:2:13 | g2 | Element has external linkage |
7+
| test.cpp:4:18:4:19 | g4 | Element has external linkage |
78
| test.cpp:7:11:7:13 | ns1 | Element has external linkage |
89
| test.cpp:8:5:8:6 | l1 | Element has external linkage |
910
| test.cpp:10:6:10:7 | f1 | Element has external linkage |
@@ -18,15 +19,32 @@
1819
| test.cpp:28:8:28:9 | m3 | Element has external linkage |
1920
| test.cpp:30:8:30:9 | e1 | Element has external linkage |
2021
| test.cpp:31:16:31:16 | e2 | Element has external linkage |
22+
| test.cpp:33:9:33:9 | C2 | Element has external linkage |
2123
| test.cpp:33:9:33:9 | operator= | Element has external linkage |
2224
| test.cpp:33:9:33:9 | operator= | Element has external linkage |
2325
| test.cpp:33:9:33:10 | C2 | Element has external linkage |
24-
| test.cpp:34:17:34:17 | operator= | Element has external linkage |
25-
| test.cpp:34:17:34:17 | operator= | Element has external linkage |
26-
| test.cpp:34:17:34:18 | C3 | Element has external linkage |
27-
| test.cpp:38:15:38:15 | (unnamed constructor) | Element has external linkage |
28-
| test.cpp:38:15:38:15 | operator= | Element has external linkage |
29-
| test.cpp:38:15:38:15 | operator= | Element has external linkage |
30-
| test.cpp:38:15:38:16 | C2 | Element has external linkage |
31-
| test.cpp:43:7:43:8 | C3<T> | Element has external linkage |
32-
| test.cpp:86:6:86:6 | g | Element has external linkage |
26+
| test.cpp:35:16:35:17 | m2 | Element has external linkage |
27+
| test.cpp:36:10:36:11 | m3 | Element has external linkage |
28+
| test.cpp:39:17:39:17 | (unnamed constructor) | Element has external linkage |
29+
| test.cpp:39:17:39:17 | operator= | Element has external linkage |
30+
| test.cpp:39:17:39:17 | operator= | Element has external linkage |
31+
| test.cpp:39:17:39:18 | C3 | Element has external linkage |
32+
| test.cpp:42:10:42:11 | m3 | Element has external linkage |
33+
| test.cpp:52:15:52:15 | (unnamed constructor) | Element has external linkage |
34+
| test.cpp:52:15:52:15 | operator= | Element has external linkage |
35+
| test.cpp:52:15:52:15 | operator= | Element has external linkage |
36+
| test.cpp:52:15:52:16 | C2 | Element has external linkage |
37+
| test.cpp:55:8:55:9 | m3 | Element has external linkage |
38+
| test.cpp:57:9:57:9 | C2 | Element has external linkage |
39+
| test.cpp:57:9:57:9 | operator= | Element has external linkage |
40+
| test.cpp:57:9:57:9 | operator= | Element has external linkage |
41+
| test.cpp:57:9:57:10 | C2 | Element has external linkage |
42+
| test.cpp:60:10:60:11 | m3 | Element has external linkage |
43+
| test.cpp:63:17:63:17 | (unnamed constructor) | Element has external linkage |
44+
| test.cpp:63:17:63:17 | operator= | Element has external linkage |
45+
| test.cpp:63:17:63:17 | operator= | Element has external linkage |
46+
| test.cpp:63:17:63:18 | C3 | Element has external linkage |
47+
| test.cpp:66:10:66:11 | m3 | Element has external linkage |
48+
| test.cpp:77:7:77:8 | C3<T> | Element has external linkage |
49+
| test.cpp:160:6:160:6 | g | Element has external linkage |
50+
| test.cpp:169:6:169:16 | block_scope | Element has external linkage |
Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,44 @@
11
| test.cpp:3:11:3:12 | g3 | Element has internal linkage |
2-
| test.cpp:4:18:4:19 | g4 | Element has internal linkage |
32
| test.cpp:5:12:5:13 | g5 | Element has internal linkage |
4-
| test.cpp:48:1:48:9 | (unnamed namespace) | Element has internal linkage |
5-
| test.cpp:49:11:49:13 | (unnamed namespace)::ns2 | Element has internal linkage |
6-
| test.cpp:50:5:50:6 | l1 | Element has internal linkage |
7-
| test.cpp:52:6:52:7 | f1 | Element has internal linkage |
8-
| test.cpp:54:6:54:7 | e1 | Element has internal linkage |
9-
| test.cpp:59:14:59:14 | e2 | Element has internal linkage |
10-
| test.cpp:65:6:65:7 | f2 | Element has internal linkage |
11-
| test.cpp:67:7:67:8 | C1 | Element has internal linkage |
12-
| test.cpp:71:15:71:16 | C2 | Element has internal linkage |
13-
| test.cpp:76:7:76:8 | C3<T> | Element has internal linkage |
14-
| test.cpp:84:13:84:13 | f | Element has internal linkage |
15-
| test.cpp:85:12:85:12 | i | Element has internal linkage |
16-
| test.cpp:87:15:87:15 | f | Element has internal linkage |
3+
| test.cpp:82:1:82:9 | (unnamed namespace) | Element has internal linkage |
4+
| test.cpp:83:11:83:13 | (unnamed namespace)::ns2 | Element has internal linkage |
5+
| test.cpp:84:5:84:6 | l1 | Element has internal linkage |
6+
| test.cpp:86:6:86:7 | f1 | Element has internal linkage |
7+
| test.cpp:88:6:88:7 | e1 | Element has internal linkage |
8+
| test.cpp:93:14:93:14 | e2 | Element has internal linkage |
9+
| test.cpp:99:6:99:7 | f2 | Element has internal linkage |
10+
| test.cpp:101:7:101:7 | C1 | Element has internal linkage |
11+
| test.cpp:101:7:101:7 | operator= | Element has internal linkage |
12+
| test.cpp:101:7:101:7 | operator= | Element has internal linkage |
13+
| test.cpp:101:7:101:8 | C1 | Element has internal linkage |
14+
| test.cpp:103:14:103:15 | m2 | Element has internal linkage |
15+
| test.cpp:104:8:104:9 | m3 | Element has internal linkage |
16+
| test.cpp:106:9:106:9 | C2 | Element has internal linkage |
17+
| test.cpp:106:9:106:9 | operator= | Element has internal linkage |
18+
| test.cpp:106:9:106:9 | operator= | Element has internal linkage |
19+
| test.cpp:106:9:106:10 | C2 | Element has internal linkage |
20+
| test.cpp:108:16:108:17 | m2 | Element has internal linkage |
21+
| test.cpp:109:10:109:11 | m3 | Element has internal linkage |
22+
| test.cpp:112:18:112:18 | operator= | Element has internal linkage |
23+
| test.cpp:112:18:112:18 | operator= | Element has internal linkage |
24+
| test.cpp:112:18:112:19 | C3 | Element has internal linkage |
25+
| test.cpp:115:10:115:11 | m3 | Element has internal linkage |
26+
| test.cpp:125:15:125:15 | (unnamed constructor) | Element has internal linkage |
27+
| test.cpp:125:15:125:15 | operator= | Element has internal linkage |
28+
| test.cpp:125:15:125:15 | operator= | Element has internal linkage |
29+
| test.cpp:125:15:125:16 | C2 | Element has internal linkage |
30+
| test.cpp:128:8:128:9 | m3 | Element has internal linkage |
31+
| test.cpp:130:9:130:9 | C2 | Element has internal linkage |
32+
| test.cpp:130:9:130:9 | operator= | Element has internal linkage |
33+
| test.cpp:130:9:130:9 | operator= | Element has internal linkage |
34+
| test.cpp:130:9:130:10 | C2 | Element has internal linkage |
35+
| test.cpp:133:10:133:11 | m3 | Element has internal linkage |
36+
| test.cpp:136:17:136:17 | (unnamed constructor) | Element has internal linkage |
37+
| test.cpp:136:17:136:17 | operator= | Element has internal linkage |
38+
| test.cpp:136:17:136:17 | operator= | Element has internal linkage |
39+
| test.cpp:136:17:136:18 | C3 | Element has internal linkage |
40+
| test.cpp:139:10:139:11 | m3 | Element has internal linkage |
41+
| test.cpp:150:7:150:8 | C3<T> | Element has internal linkage |
42+
| test.cpp:158:13:158:13 | f | Element has internal linkage |
43+
| test.cpp:159:12:159:12 | i | Element has internal linkage |
44+
| test.cpp:161:15:161:15 | f | Element has internal linkage |

0 commit comments

Comments
 (0)