-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathNameQualifiers.qll
166 lines (152 loc) · 4.67 KB
/
NameQualifiers.qll
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/**
* Provides classes for working with name qualifiers such as the `N::` in
* `N::f()`.
*/
import cpp
/**
* A C++ name qualifier, for example `N::` in the following code:
* ```
* namespace N {
* int f() {
* ...
* }
* }
*
* int g() {
* return N::f();
* }
* ```
*/
class NameQualifier extends NameQualifiableElement, @namequalifier {
/**
* Gets the expression ultimately qualified by the chain of name
* qualifiers. For example, `f()` in `N1::N2::f()`.
*/
Expr getExpr() { result = this.getQualifiedElement+() }
/** Gets a location for this name qualifier. */
override Location getLocation() { namequalifiers(underlyingElement(this), _, _, result) }
/**
* Gets the name qualifier that qualifies this name qualifier, if any.
* This is used for name qualifier chains, for example the name qualifier
* `N2::` has a name qualifier `N1::` in the chain `N1::N2::f()`.
*/
override NameQualifier getNameQualifier() {
namequalifiers(unresolveElement(result), underlyingElement(this), _, _)
}
/**
* Gets the element qualified by this name qualifier. For example, `f()`
* in `N::f()`.
*/
NameQualifiableElement getQualifiedElement() {
namequalifiers(underlyingElement(this), unresolveElement(result), _, _)
}
/**
* Gets the qualifying element of this name qualifier. For example, `N`
* in `N::f()`.
*/
NameQualifyingElement getQualifyingElement() {
exists(NameQualifyingElement nqe |
namequalifiers(underlyingElement(this), _, unresolveElement(nqe), _) and
if nqe instanceof SpecialNameQualifyingElement
then
exists(Access a |
a = this.getQualifiedElement() and
result = a.getTarget().getDeclaringType()
)
or
exists(FunctionCall c |
c = this.getQualifiedElement() and
result = c.getTarget().getDeclaringType()
)
else result = nqe
)
}
override string toString() {
exists(NameQualifyingElement nqe |
namequalifiers(underlyingElement(this), _, unresolveElement(nqe), _) and
result = nqe.getName() + "::"
)
}
}
/**
* A C++ element that can be qualified with a name. This is in practice
* either an expression or a name qualifier. For example, there are two
* name-qualifiable elements in the following code, the expression `f()`
* (which is qualified by `N::`), and the qualifier `N::` (which is not
* itself qualified in this example):
* ```
* namespace N {
* int f() {
* ...
* }
* }
*
* int g() {
* return N::f();
* }
* ```
*/
class NameQualifiableElement extends Element, @namequalifiableelement {
/**
* Gets the name qualifier associated with this element. For example, the
* name qualifier of `N::f()` is `N`.
*/
NameQualifier getNameQualifier() {
namequalifiers(unresolveElement(result), underlyingElement(this), _, _)
}
/**
* Holds if this element has a globally qualified name. For example,
* `::x` is globally qualified. It is used to refer to `x` in the global
* namespace.
*/
predicate hasGlobalQualifiedName() {
this.getNameQualifier*().getQualifyingElement() instanceof GlobalNamespace
}
/**
* Holds if this element has a `__super`-qualified name. For example:
* `__super::get()`. Note: `__super` is non-standard C++ extension, only
* supported by some C++ compilers.
*/
predicate hasSuperQualifiedName() {
exists(NameQualifier nq, SpecialNameQualifyingElement snqe |
nq = this.getNameQualifier*() and
namequalifiers(unresolveElement(nq), _, unresolveElement(snqe), _) and
snqe.getName() = "__super"
)
}
}
/**
* A C++ element that can qualify a name. For example, the namespaces `A` and
* `A::B` and the class `A::C` in the following code:
* ```
* namespace A {
* namespace B {
* ...
* }
*
* class C {
* ...
* };
* }
* ```
*/
class NameQualifyingElement extends Element, @namequalifyingelement {
/**
* Gets a name qualifier for which this is the qualifying namespace or
* user-defined type. For example: class `X` is the
* `NameQualifyingElement` and `X::` is the `NameQualifier`.
*/
NameQualifier getANameQualifier() {
namequalifiers(unresolveElement(result), _, underlyingElement(this), _)
}
/** Gets the name of this namespace or user-defined type. */
string getName() { none() }
}
/**
* A special name-qualifying element. For example: `__super`.
*/
class SpecialNameQualifyingElement extends NameQualifyingElement, @specialnamequalifyingelement {
/** Gets the name of this special qualifying element. */
override string getName() { specialnamequalifyingelements(underlyingElement(this), result) }
override string toString() { result = this.getName() }
}