-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathMemberFunction.qll
485 lines (433 loc) · 14.9 KB
/
MemberFunction.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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
/**
* Provides classes for working with C++ member functions, constructors, destructors,
* and user-defined operators.
*/
import cpp
/**
* A C++ function declared as a member of a class [N4140 9.3]. This includes
* static member functions. For example the functions `MyStaticMemberFunction`
* and `MyMemberFunction` in:
* ```
* class MyClass {
* public:
* void MyMemberFunction() {
* DoSomething();
* }
*
* static void MyStaticMemberFunction() {
* DoSomething();
* }
* };
* ```
*/
class MemberFunction extends Function {
MemberFunction() { this.isMember() }
override string getAPrimaryQlClass() {
not this instanceof CopyAssignmentOperator and
not this instanceof MoveAssignmentOperator and
result = "MemberFunction"
}
/**
* Gets the number of parameters of this function, including any implicit
* `this` parameter.
*/
override int getEffectiveNumberOfParameters() {
if this.isStatic()
then result = this.getNumberOfParameters()
else result = this.getNumberOfParameters() + 1
}
/** Holds if this member is private. */
predicate isPrivate() { this.hasSpecifier("private") }
/** Holds if this member is protected. */
predicate isProtected() { this.hasSpecifier("protected") }
/** Holds if this member is public. */
predicate isPublic() { this.hasSpecifier("public") }
/** Holds if this declaration has the lvalue ref-qualifier */
predicate isLValueRefQualified() { this.hasSpecifier("&") }
/** Holds if this declaration has the rvalue ref-qualifier */
predicate isRValueRefQualified() { this.hasSpecifier("&&") }
/** Holds if this declaration has a ref-qualifier */
predicate isRefQualified() { this.isLValueRefQualified() or this.isRValueRefQualified() }
/** Holds if this function overrides that function. */
predicate overrides(MemberFunction that) {
overrides(underlyingElement(this), unresolveElement(that))
}
/** Gets a directly overridden function. */
MemberFunction getAnOverriddenFunction() { this.overrides(result) }
/** Gets a directly overriding function. */
MemberFunction getAnOverridingFunction() { result.overrides(this) }
/**
* Gets the declaration entry for this member function that is within the
* class body.
*/
FunctionDeclarationEntry getClassBodyDeclarationEntry() {
if strictcount(this.getADeclarationEntry()) = 1
then result = this.getDefinition()
else (
result = this.getADeclarationEntry() and result != this.getDefinition()
)
}
/**
* Gets the type of the `this` parameter associated with this member function, if any. The type
* may have `const` and/or `volatile` qualifiers, matching the function declaration.
*/
PointerType getTypeOfThis() {
member_function_this_type(underlyingElement(this), unresolveElement(result))
}
}
/**
* A C++ virtual function. For example the two functions called
* `myVirtualFunction` in the following code are each a
* `VirtualFunction`:
* ```
* class A {
* public:
* virtual void myVirtualFunction() = 0;
* };
*
* class B: public A {
* public:
* virtual void myVirtualFunction() {
* doSomething();
* }
* };
* ```
*/
class VirtualFunction extends MemberFunction {
VirtualFunction() { this.hasSpecifier("virtual") or purefunctions(underlyingElement(this)) }
override string getAPrimaryQlClass() { result = "VirtualFunction" }
/** Holds if this virtual function is pure. */
predicate isPure() { this instanceof PureVirtualFunction }
/**
* Holds if this function was declared with the `override` specifier
* [N4140 10.3].
*/
predicate isOverrideExplicit() { this.hasSpecifier("override") }
}
/**
* A C++ pure virtual function [N4140 10.4]. For example the first function
* called `myVirtualFunction` in the following code:
* ```
* class A {
* public:
* virtual void myVirtualFunction() = 0;
* };
*
* class B: public A {
* public:
* virtual void myVirtualFunction() {
* doSomething();
* }
* };
* ```
*/
class PureVirtualFunction extends VirtualFunction {
PureVirtualFunction() { purefunctions(underlyingElement(this)) }
override string getAPrimaryQlClass() { result = "PureVirtualFunction" }
}
/**
* A const C++ member function [N4140 9.3.1/4]. A const function has the
* `const` specifier and does not modify the state of its class. For example
* the member function `day` in the following code:
* ```
* class MyClass {
* ...
*
* int day() const {
* return d;
* }
*
* ...
* };
* ```
*/
class ConstMemberFunction extends MemberFunction {
ConstMemberFunction() { this.hasSpecifier("const") }
override string getAPrimaryQlClass() { result = "ConstMemberFunction" }
}
/**
* A C++ constructor [N4140 12.1]. For example the function `MyClass` in the
* following code is a constructor:
* ```
* class MyClass {
* public:
* MyClass() {
* ...
* }
* };
* ```
*/
class Constructor extends MemberFunction {
Constructor() { functions(underlyingElement(this), _, 2) }
override string getAPrimaryQlClass() { result = "Constructor" }
/**
* Holds if this constructor serves as a default constructor.
*
* This holds for constructors with zero formal parameters. It also holds
* for constructors which have a non-zero number of formal parameters,
* provided that every parameter has a default value.
*/
predicate isDefault() { forall(Parameter p | p = this.getAParameter() | p.hasInitializer()) }
/**
* Gets an entry in the constructor's initializer list, or a
* compiler-generated action which initializes a base class or member
* variable.
*/
ConstructorInit getAnInitializer() { result = this.getInitializer(_) }
/**
* Gets an entry in the constructor's initializer list, or a
* compiler-generated action which initializes a base class or member
* variable. The index specifies the order in which the initializer is
* to be evaluated.
*/
ConstructorInit getInitializer(int i) {
exprparents(unresolveElement(result), i, underlyingElement(this))
}
}
/**
* A function that defines an implicit conversion.
*/
class ImplicitConversionFunction extends MemberFunction {
ImplicitConversionFunction() {
// ConversionOperator
functions(underlyingElement(this), _, 4)
or
// ConversionConstructor (deprecated)
strictcount(Parameter p | p = this.getAParameter() and not p.hasInitializer()) = 1 and
not this.hasSpecifier("explicit")
}
/** Gets the type this `ImplicitConversionFunction` takes as input. */
Type getSourceType() { none() } // overridden in subclasses
/** Gets the type this `ImplicitConversionFunction` converts to. */
Type getDestType() { none() } // overridden in subclasses
}
private predicate hasCopySignature(MemberFunction f) {
f.getParameter(0).getUnspecifiedType().(LValueReferenceType).getBaseType() = f.getDeclaringType()
}
private predicate hasMoveSignature(MemberFunction f) {
f.getParameter(0).getUnspecifiedType().(RValueReferenceType).getBaseType() = f.getDeclaringType()
}
/**
* A C++ copy constructor [N4140 12.8]. For example the function `MyClass` in
* the following code is a `CopyConstructor`:
* ```
* class MyClass {
* public:
* MyClass(const MyClass &from) {
* ...
* }
* };
* ```
*
* As per the standard, a copy constructor of class `T` is a non-template
* constructor whose first parameter has type `T&`, `const T&`, `volatile
* T&`, or `const volatile T&`, and either there are no other parameters,
* or the rest of the parameters all have default values.
*
* For template classes, it can generally not be determined until instantiation
* whether a constructor is a copy constructor. For such classes, `CopyConstructor`
* over-approximates the set of copy constructors; if an under-approximation is
* desired instead, see the member predicate
* `mayNotBeCopyConstructorInInstantiation`.
*/
class CopyConstructor extends Constructor {
CopyConstructor() {
hasCopySignature(this) and
(
// The rest of the parameters all have default values
forall(int i | i > 0 and exists(this.getParameter(i)) | this.getParameter(i).hasInitializer())
or
// or this is a template class, in which case the default values have
// not been extracted even if they exist. In that case, we assume that
// there are default values present since that is the most common case
// in real-world code.
this.getDeclaringType() instanceof TemplateClass
) and
not exists(this.getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "CopyConstructor" }
/**
* Holds if we cannot determine that this constructor will become a copy
* constructor in all instantiations. Depending on template parameters of the
* enclosing class, this may become an ordinary constructor or a copy
* constructor.
*/
predicate mayNotBeCopyConstructorInInstantiation() {
// In general, default arguments of template classes can only be
// type-checked for each template instantiation; if an argument in an
// instantiation fails to type-check then the corresponding parameter has
// no default argument in the instantiation.
this.getDeclaringType() instanceof TemplateClass and
this.getNumberOfParameters() > 1
}
}
/**
* A C++ move constructor [N4140 12.8]. For example the function `MyClass` in
* the following code is a `MoveConstructor`:
* ```
* class MyClass {
* public:
* MyClass(MyClass &&from) {
* ...
* }
* };
* ```
*
* As per the standard, a move constructor of class `T` is a non-template
* constructor whose first parameter is `T&&`, `const T&&`, `volatile T&&`,
* or `const volatile T&&`, and either there are no other parameters, or
* the rest of the parameters all have default values.
*
* For template classes, it can generally not be determined until instantiation
* whether a constructor is a move constructor. For such classes, `MoveConstructor`
* over-approximates the set of move constructors; if an under-approximation is
* desired instead, see the member predicate
* `mayNotBeMoveConstructorInInstantiation`.
*/
class MoveConstructor extends Constructor {
MoveConstructor() {
hasMoveSignature(this) and
(
// The rest of the parameters all have default values
forall(int i | i > 0 and exists(this.getParameter(i)) | this.getParameter(i).hasInitializer())
or
// or this is a template class, in which case the default values have
// not been extracted even if they exist. In that case, we assume that
// there are default values present since that is the most common case
// in real-world code.
this.getDeclaringType() instanceof TemplateClass
) and
not exists(this.getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "MoveConstructor" }
/**
* Holds if we cannot determine that this constructor will become a move
* constructor in all instantiations. Depending on template parameters of the
* enclosing class, this may become an ordinary constructor or a move
* constructor.
*/
predicate mayNotBeMoveConstructorInInstantiation() {
// In general, default arguments of template classes can only be
// type-checked for each template instantiation; if an argument in an
// instantiation fails to type-check then the corresponding parameter has
// no default argument in the instantiation.
this.getDeclaringType() instanceof TemplateClass and
this.getNumberOfParameters() > 1
}
}
/**
* A C++ constructor that takes no arguments ('default' constructor). This
* is the constructor that is invoked when no initializer is given. For
* example the function `MyClass` in the following code is a
* `NoArgConstructor`:
* ```
* class MyClass {
* public:
* MyClass() {
* ...
* }
* };
* ```
*/
class NoArgConstructor extends Constructor {
NoArgConstructor() { this.getNumberOfParameters() = 0 }
}
/**
* A C++ destructor [N4140 12.4]. For example the function `~MyClass` in the
* following code is a destructor:
* ```
* class MyClass {
* public:
* ~MyClass() {
* ...
* }
* };
* ```
*/
class Destructor extends MemberFunction {
Destructor() { functions(underlyingElement(this), _, 3) }
override string getAPrimaryQlClass() { result = "Destructor" }
/**
* Gets a compiler-generated action which destructs a base class or member
* variable.
*/
DestructorDestruction getADestruction() { result = this.getDestruction(_) }
/**
* Gets a compiler-generated action which destructs a base class or member
* variable. The index specifies the order in which the destruction should
* be evaluated.
*/
DestructorDestruction getDestruction(int i) {
exprparents(unresolveElement(result), i, underlyingElement(this))
}
}
/**
* A C++ conversion operator [N4140 12.3.2]. For example the function
* `operator int` in the following code is a `ConversionOperator`:
* ```
* class MyClass {
* public:
* operator int();
* };
* ```
*/
class ConversionOperator extends MemberFunction, ImplicitConversionFunction {
ConversionOperator() { functions(underlyingElement(this), _, 4) }
override string getAPrimaryQlClass() { result = "ConversionOperator" }
override Type getSourceType() { result = this.getDeclaringType() }
override Type getDestType() { result = this.getType() }
}
/**
* A C++ copy assignment operator [N4140 12.8]. For example the function
* `operator=` in the following code is a `CopyAssignmentOperator`:
* ```
* class MyClass {
* public:
* MyClass &operator=(const MyClass &other);
* };
* ```
*
* As per the standard, a copy assignment operator of class `T` is a
* non-template non-static member function with the name `operator=` that
* takes exactly one parameter of type `T`, `T&`, `const T&`, `volatile
* T&`, or `const volatile T&`.
*/
class CopyAssignmentOperator extends Operator {
CopyAssignmentOperator() {
this.hasName("operator=") and
(
hasCopySignature(this)
or
// Unlike CopyConstructor, this member allows a non-reference
// parameter.
this.getParameter(0).getUnspecifiedType() = this.getDeclaringType()
) and
not exists(this.getParameter(1)) and
not exists(this.getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "CopyAssignmentOperator" }
}
/**
* A C++ move assignment operator [N4140 12.8]. For example the function
* `operator=` in the following code is a `MoveAssignmentOperator`:
* ```
* class MyClass {
* public:
* MyClass &operator=(MyClass &&other);
* };
* ```
*
* As per the standard, a move assignment operator of class `T` is a
* non-template non-static member function with the name `operator=` that
* takes exactly one parameter of type `T&&`, `const T&&`, `volatile T&&`,
* or `const volatile T&&`.
*/
class MoveAssignmentOperator extends Operator {
MoveAssignmentOperator() {
this.hasName("operator=") and
hasMoveSignature(this) and
not exists(this.getParameter(1)) and
not exists(this.getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "MoveAssignmentOperator" }
}