-
Notifications
You must be signed in to change notification settings - Fork 75
Expand file tree
/
Copy pathLinkage.qll
More file actions
136 lines (128 loc) · 4.64 KB
/
Linkage.qll
File metadata and controls
136 lines (128 loc) · 4.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/**
* A module to reason about the linkage of objects and functions.
*/
import cpp
import codingstandards.cpp.Scope
/**
* [basic]/6 uses a specific definition of "variable" that excludes non-static data members.
*/
private predicate isSpecificationVariable(Variable v) {
v.(MemberVariable).isStatic()
or
not v instanceof MemberVariable
}
/** Holds if `elem` has internal linkage. */
predicate hasInternalLinkage(Element elem) {
// An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage
elem instanceof WithinAnonymousNamespace
or
exists(Declaration decl | decl = elem |
// A name having namespace scope has internal linkage if it is the name of
hasNamespaceScope(decl) and
(
// a variable, function or function template
(
isSpecificationVariable(decl)
or
decl instanceof Function // TemplateFunction is a subclass of Function so this captures both.
) and
// that is explicitly declared static; or,
decl.isStatic()
or
// a non-volatile variable
isSpecificationVariable(decl) and
not decl.(Variable).isVolatile() and
// that is explicitly declared const or constexpr and
(decl.(Variable).isConst() or decl.(Variable).isConstexpr()) and
// neither explicitly declared external nor previously declared to have external linkage; or
not exists(DeclarationEntry e | e = decl.getADeclarationEntry() | e.hasSpecifier("extern"))
or
// a data member of an anonymous union.
exists(Union u | hasNamespaceScope(u) and u.isAnonymous() |
decl = u.getACanonicalMemberVariable()
)
)
or
decl.getNamespace() instanceof WithinAnonymousNamespace and
inheritsLinkageOfNamespace(decl.getNamespace(), decl)
or
exists(Class klass |
hasInternalLinkage(klass) and
inheritsLinkageOfClass(klass, decl)
)
)
}
/** Holds if `elem` has external linkage. */
predicate hasExternalLinkage(Element elem) {
elem instanceof Namespace and
not elem instanceof WithinAnonymousNamespace
or
not hasInternalLinkage(elem) and
exists(Declaration decl | decl = elem |
// 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
not decl.getNamespace() instanceof WithinAnonymousNamespace and
inheritsLinkageOfNamespace(decl.getNamespace(), decl)
or
exists(Class klass |
hasExternalLinkage(klass) and
inheritsLinkageOfClass(klass, decl)
)
)
}
/**
* A `Namespace` that is anonymous or indirectly contained within an unnamed namespace.
*/
class WithinAnonymousNamespace extends Namespace {
WithinAnonymousNamespace() { getParentNamespace*().isAnonymous() }
}
private predicate hasLinkageOfTypedef(TypedefType typedef, Element decl) {
// an unnamed class defined in a typedef declartion in which the class has the typedef name for linkage purposes
decl.(Class).isAnonymous() and typedef.getADeclaration() = decl
or
// an unnamed enumeration defined in a typedef declaration in which the enumeration has the typedef name for linkage purposes
decl.(Enum).isAnonymous() and typedef.getADeclaration() = decl
}
private predicate inheritsLinkageOfNamespace(Namespace ns, Declaration decl) {
hasNamespaceScope(decl) and
ns = decl.getNamespace() and
(
// 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
// a variable;
isSpecificationVariable(decl)
or
// a function
decl instanceof Function
or
decl instanceof Class and not decl.(Class).isAnonymous() // a named class
or
decl instanceof Enum and not decl.(Enum).isAnonymous() // a named enumeration
or
// a template
decl instanceof TemplateClass
or
decl instanceof TemplateFunction
or
decl instanceof TemplateVariable
)
or
hasNamespaceScope(decl) and
exists(TypedefType typedef | hasLinkageOfTypedef(typedef, decl) and ns = typedef.getNamespace())
}
private predicate inheritsLinkageOfClass(Class klass, Element decl) {
hasClassScope(decl) and
(
// a member function,
decl.(MemberFunction).getDeclaringType() = klass
or
// static data member
decl.(MemberVariable).isStatic() and decl.(MemberVariable).getDeclaringType() = klass
or
decl.(Class).getDeclaringType() = klass and not decl.(Class).isAnonymous()
or
decl.(Enum).getDeclaringType() = klass and not decl.(Enum).isAnonymous()
or
exists(TypedefType typedef |
hasLinkageOfTypedef(typedef, decl) and klass = typedef.getDeclaringType()
)
)
}