forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMember.qll
More file actions
executable file
·624 lines (534 loc) · 20.5 KB
/
Member.qll
File metadata and controls
executable file
·624 lines (534 loc) · 20.5 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
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
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
/**
* Provides classes and predicates for working with members of Java classes and interfaces,
* that is, methods, constructors, fields and nested types.
*/
import Element
import Type
import Annotation
import Exception
import metrics.MetricField
private import dispatch.VirtualDispatch
/**
* A common abstraction for type member declarations,
* including methods, constructors, fields, and nested types.
*/
class Member extends Element, Annotatable, Modifiable, @member {
Member() { declaresMember(_, this) }
/** Gets the type in which this member is declared. */
RefType getDeclaringType() { declaresMember(result, this) }
/** Gets the qualified name of this member. */
string getQualifiedName() { result = getDeclaringType().getName() + "." + getName() }
/** Holds if this member is package protected, that is, neither public nor private nor protected. */
predicate isPackageProtected() {
not isPrivate() and
not isProtected() and
not isPublic()
}
/**
* Gets the immediately enclosing callable, if this member is declared in
* an anonymous or local class.
*/
Callable getEnclosingCallable() {
exists(NestedClass nc | this.getDeclaringType() = nc |
nc.(AnonymousClass).getClassInstanceExpr().getEnclosingCallable() = result or
nc.(LocalClass).getLocalClassDeclStmt().getEnclosingCallable() = result
)
}
}
/** A callable is a method or constructor. */
class Callable extends StmtParent, Member, @callable {
/**
* Gets the declared return type of this callable (`void` for
* constructors).
*/
Type getReturnType() {
constrs(this, _, _, result, _, _) or
methods(this, _, _, result, _, _)
}
/**
* Gets a callee that may be called from this callable.
*/
Callable getACallee() { this.calls(result) }
/** Gets the call site of a call from this callable to a callee. */
Call getACallSite(Callable callee) {
result.getCaller() = this and
result.getCallee() = callee
}
/**
* Gets the bytecode method descriptor, encoding parameter and return types,
* but not the name of the callable.
*/
string getMethodDescriptor() {
exists(string return | return = this.getReturnType().getTypeDescriptor() |
result = "(" + descriptorUpTo(this.getNumberOfParameters()) + ")" + return
)
}
private string descriptorUpTo(int n) {
n = 0 and result = ""
or
exists(Parameter p | p = this.getParameter(n - 1) |
result = descriptorUpTo(n - 1) + p.getType().getTypeDescriptor()
)
}
/** Holds if this callable calls `target`. */
predicate calls(Callable target) { exists(getACallSite(target)) }
/**
* Holds if this callable calls `target`
* using a `super(...)` constructor call.
*/
predicate callsSuperConstructor(Constructor target) {
getACallSite(target) instanceof SuperConstructorInvocationStmt
}
/**
* Holds if this callable calls `target`
* using a `this(...)` constructor call.
*/
predicate callsThis(Constructor target) {
getACallSite(target) instanceof ThisConstructorInvocationStmt
}
/**
* Holds if this callable calls `target`
* using a `super` method call.
*/
predicate callsSuper(Method target) { getACallSite(target) instanceof SuperMethodAccess }
/**
* Holds if this callable calls `c` using
* either a `super(...)` constructor call
* or a `this(...)` constructor call.
*/
predicate callsConstructor(Constructor c) { this.callsSuperConstructor(c) or this.callsThis(c) }
/**
* Holds if this callable may call the specified callable,
* taking virtual dispatch into account.
*
* This includes both static call targets and dynamic dispatch targets.
*/
predicate polyCalls(Callable m) { this.calls(m) or this.callsImpl(m) }
/**
* Holds if `c` is a viable implementation of a callable called by this
* callable, taking virtual dispatch resolution into account.
*/
predicate callsImpl(Callable c) {
exists(Call call |
call.getCaller() = this and
viableCallable(call) = c
)
}
/**
* Holds if field `f` may be assigned a value
* within the body of this callable.
*/
predicate writes(Field f) { f.getAnAccess().(LValue).getEnclosingCallable() = this }
/**
* Holds if field `f` may be read
* within the body of this callable.
*/
predicate reads(Field f) { f.getAnAccess().(RValue).getEnclosingCallable() = this }
/**
* Holds if field `f` may be either read or written
* within the body of this callable.
*/
predicate accesses(Field f) { this.writes(f) or this.reads(f) }
/**
* Gets a field accessed in this callable.
*/
Field getAnAccessedField() { this.accesses(result) }
/** Gets the type of a formal parameter of this callable. */
Type getAParamType() { result = getParameterType(_) }
/** Holds if this callable does not have any formal parameters. */
predicate hasNoParameters() { not exists(getAParameter()) }
/** Gets the number of formal parameters of this callable. */
int getNumberOfParameters() { result = count(getAParameter()) }
/** Gets a formal parameter of this callable. */
Parameter getAParameter() { result.getCallable() = this }
/** Gets the formal parameter at the specified (zero-based) position. */
Parameter getParameter(int n) { params(result, _, n, this, _) }
/** Gets the type of the formal parameter at the specified (zero-based) position. */
Type getParameterType(int n) { params(_, result, n, this, _) }
/**
* Gets the signature of this callable, including its name and the types of all its parameters,
* identified by their simple (unqualified) names.
*
* Use `getSignature` to obtain a signature including fully qualified type names.
*/
string getStringSignature() { result = this.getName() + this.paramsString() }
/** Gets a parenthesized string containing all parameter types of this callable, separated by a comma. */
pragma[nomagic]
string paramsString() {
exists(int n | n = getNumberOfParameters() |
n = 0 and result = "()"
or
n > 0 and result = "(" + this.paramUpTo(n - 1) + ")"
)
}
/**
* Gets a string containing the parameter types of this callable
* from left to right, up to (and including) the `n`-th parameter.
*/
private string paramUpTo(int n) {
n = 0 and result = getParameterType(0).toString()
or
n > 0 and result = paramUpTo(n - 1) + ", " + getParameterType(n)
}
/** Holds if this callable has the specified string signature. */
predicate hasStringSignature(string sig) { sig = this.getStringSignature() }
/** Gets an exception that occurs in the `throws` clause of this callable. */
Exception getAnException() { exceptions(result, _, this) }
/** Gets an exception type that occurs in the `throws` clause of this callable. */
RefType getAThrownExceptionType() { result = getAnException().getType() }
/** Gets a call site that references this callable. */
Call getAReference() { result.getCallee() = this }
/** Gets the body of this callable, if any. */
Block getBody() { result.getParent() = this }
/**
* Gets the source declaration of this callable.
*
* For parameterized instances of generic methods, the
* source declaration is the corresponding generic method.
*
* For non-parameterized callables declared inside a parameterized
* instance of a generic type, the source declaration is the
* corresponding callable in the generic type.
*
* For all other callables, the source declaration is the callable itself.
*/
Callable getSourceDeclaration() { result = this }
/** Holds if this callable is the same as its source declaration. */
predicate isSourceDeclaration() { this.getSourceDeclaration() = this }
/** Cast this callable to a class that provides access to metrics information. */
MetricCallable getMetrics() { result = this }
/** Holds if the last parameter of this callable is a varargs (variable arity) parameter. */
predicate isVarargs() { this.getAParameter().isVarargs() }
/**
* Gets the signature of this callable, where all types in the signature have a fully-qualified name.
*
* For example, method `void m(String s)` has the signature `m(java.lang.String)`.
*/
string getSignature() {
constrs(this, _, result, _, _, _) or
methods(this, _, result, _, _, _)
}
}
/** Holds if method `m1` overrides method `m2`. */
private predicate overrides(Method m1, Method m2) {
exists(RefType t1, RefType t2 | overridesIgnoringAccess(m1, t1, m2, t2) |
m2.isPublic()
or
m2.isProtected()
or
m2.isPackageProtected() and t1.getPackage() = t2.getPackage()
)
}
/**
* Auxiliary predicate: whether method `m1` overrides method `m2`,
* ignoring any access modifiers. Additionally, this predicate binds
* `t1` to the type declaring `m1` and `t2` to the type declaring `m2`.
*/
pragma[noopt]
predicate overridesIgnoringAccess(Method m1, RefType t1, Method m2, RefType t2) {
exists(string sig |
virtualMethodWithSignature(sig, t1, m1) and
t1.extendsOrImplements+(t2) and
virtualMethodWithSignature(sig, t2, m2)
)
}
private predicate virtualMethodWithSignature(string sig, RefType t, Method m) {
methods(m, _, _, _, t, _) and
sig = m.getSignature() and
m.isVirtual()
}
private predicate potentialInterfaceImplementationWithSignature(string sig, RefType t, Method impl) {
t.hasMethod(impl, _) and
sig = impl.getSignature() and
impl.isVirtual() and
impl.isPublic() and
not t instanceof Interface and
not t.isAbstract()
}
pragma[nomagic]
private predicate implementsInterfaceMethod(SrcMethod impl, SrcMethod m) {
exists(RefType t, Interface i, Method minst, Method implinst |
m = minst.getSourceDeclaration() and
i = minst.getDeclaringType() and
t.extendsOrImplements+(i) and
t.isSourceDeclaration() and
potentialInterfaceImplementationWithSignature(minst.getSignature(), t, implinst) and
impl = implinst.getSourceDeclaration()
)
}
/** A method is a particular kind of callable. */
class Method extends Callable, @method {
/** Holds if this method (directly) overrides the specified callable. */
predicate overrides(Method m) { overrides(this, m) }
/**
* Holds if this method either overrides `m`, or `m` is the
* source declaration of this method (and not equal to it).
*/
predicate overridesOrInstantiates(Method m) {
this.overrides(m)
or
this.getSourceDeclaration() = m and this != m
}
/** Gets a method (directly or transitively) overridden by this method. */
Method getAnOverride() { this.overrides+(result) }
/** Gets the source declaration of a method overridden by this method. */
SrcMethod getASourceOverriddenMethod() {
exists(Method m | this.overrides(m) and result = m.getSourceDeclaration())
}
override string getSignature() { methods(this, _, result, _, _, _) }
/**
* Holds if this method and method `m` are declared in the same type
* and have the same parameter types.
*/
predicate sameParamTypes(Method m) {
// `this` and `m` are different methods,
this != m and
// `this` and `m` are declared in the same type,
this.getDeclaringType() = m.getDeclaringType() and
// `this` and `m` are of the same arity, and
this.getNumberOfParameters() = m.getNumberOfParameters() and
// there does not exist a pair of parameters whose types differ.
not exists(int n | this.getParameterType(n) != m.getParameterType(n))
}
override SrcMethod getSourceDeclaration() { methods(this, _, _, _, _, result) }
/**
* All the methods that could possibly be called when this method
* is called. For class methods this includes the method itself and all its
* overriding methods (if any), and for interface methods this includes
* matching methods defined on or inherited by implementing classes.
*
* Only includes method implementations, not abstract or non-default interface methods.
* Native methods are included, since they have an implementation (just not in Java).
*/
SrcMethod getAPossibleImplementation() {
this.getSourceDeclaration().getAPossibleImplementationOfSrcMethod() = result
}
override MethodAccess getAReference() { result = Callable.super.getAReference() }
override predicate isPublic() {
Callable.super.isPublic()
or
// JLS 9.4: Every method declaration in the body of an interface without an
// access modifier is implicitly public.
getDeclaringType() instanceof Interface and
not this.isPrivate()
or
exists(FunctionalExpr func | func.asMethod() = this)
}
override predicate isAbstract() {
Callable.super.isAbstract()
or
// JLS 9.4: An interface method lacking a `private`, `default`, or `static` modifier
// is implicitly abstract.
this.getDeclaringType() instanceof Interface and
not this.isPrivate() and
not this.isDefault() and
not this.isStatic()
}
override predicate isStrictfp() {
Callable.super.isStrictfp()
or
// JLS 8.1.1.3, JLS 9.1.1.2
getDeclaringType().isStrictfp()
}
/**
* Holds if this method is neither private nor a static interface method
* nor an initializer method, and hence could be inherited.
*/
predicate isInheritable() {
not isPrivate() and
not (isStatic() and getDeclaringType() instanceof Interface) and
not this instanceof InitializerMethod
}
/**
* Holds if this method is neither private nor static, and hence
* uses dynamic dispatch.
*/
predicate isVirtual() { not isPrivate() and not isStatic() }
/** Holds if this method can be overridden. */
predicate isOverridable() {
isVirtual() and
not isFinal() and
not getDeclaringType().isFinal()
}
}
/** A method that is the same as its source declaration. */
class SrcMethod extends Method {
SrcMethod() { methods(_, _, _, _, _, this) }
/**
* All the methods that could possibly be called when this method
* is called. For class methods this includes the method itself and all its
* overriding methods (if any), and for interface methods this includes
* matching methods defined on or inherited by implementing classes.
*
* Only includes method implementations, not abstract or non-default interface methods.
* Native methods are included, since they have an implementation (just not in Java).
*/
SrcMethod getAPossibleImplementationOfSrcMethod() {
(
if this.getDeclaringType() instanceof Interface and this.isVirtual()
then implementsInterfaceMethod(result, this)
else result.getASourceOverriddenMethod*() = this
) and
(exists(result.getBody()) or result.hasModifier("native"))
}
}
/**
* A _setter_ method is a method with the following properties:
*
* - it has exactly one parameter,
* - its body contains exactly one statement
* that assigns the value of the method parameter to a field
* declared in the same type as the method.
*/
class SetterMethod extends Method {
SetterMethod() {
this.getNumberOfParameters() = 1 and
exists(ExprStmt s, Assignment a |
s = this.getBody().(SingletonBlock).getStmt() and a = s.getExpr()
|
exists(Field f | f.getDeclaringType() = this.getDeclaringType() |
a.getDest() = f.getAnAccess() and
a.getSource() = this.getAParameter().getAnAccess()
)
)
}
/** Gets the field assigned by this setter method. */
Field getField() {
exists(Assignment a | a.getEnclosingCallable() = this | a.getDest() = result.getAnAccess())
}
}
/**
* A _getter_ method is a method with the following properties:
*
* - it has no parameters,
* - its body contains exactly one statement
* that returns the value of a field.
*/
class GetterMethod extends Method {
GetterMethod() {
this.hasNoParameters() and
exists(ReturnStmt s, Field f | s = this.getBody().(SingletonBlock).getStmt() |
s.getResult() = f.getAnAccess()
)
}
/** Gets the field whose value is returned by this getter method. */
Field getField() {
exists(ReturnStmt r | r.getEnclosingCallable() = this | r.getResult() = result.getAnAccess())
}
}
/**
* A finalizer method, with name `finalize`,
* return type `void` and no parameters.
*/
class FinalizeMethod extends Method {
FinalizeMethod() {
this.hasName("finalize") and
this.getReturnType().hasName("void") and
this.hasNoParameters()
}
}
/** A constructor is a particular kind of callable. */
class Constructor extends Callable, @constructor {
/** Holds if this is a default constructor, not explicitly declared in source code. */
predicate isDefaultConstructor() { isDefConstr(this) }
override Constructor getSourceDeclaration() { constrs(this, _, _, _, _, result) }
override string getSignature() { constrs(this, _, result, _, _, _) }
}
/**
* A compiler-generated initializer method (could be static or
* non-static), which is used to hold (static or non-static) field
* initializers, as well as explicit initializer blocks.
*/
abstract class InitializerMethod extends Method { }
/**
* A static initializer is a method that contains all static
* field initializations and static initializer blocks.
*/
class StaticInitializer extends InitializerMethod {
StaticInitializer() { hasName("<clinit>") }
}
/**
* An instance initializer is a method that contains field initializations
* and explicit instance initializer blocks.
*/
class InstanceInitializer extends InitializerMethod {
InstanceInitializer() { this.hasName("<obinit>") }
}
/** A field declaration that declares one or more class or instance fields. */
class FieldDeclaration extends ExprParent, @fielddecl, Annotatable {
/** Gets the access to the type of the field(s) in this declaration. */
Expr getTypeAccess() { result.getParent() = this }
/** Gets a field declared in this declaration. */
Field getAField() { fieldDeclaredIn(result, this, _) }
/** Gets the field declared at the specified (zero-based) position in this declaration */
Field getField(int idx) { fieldDeclaredIn(result, this, idx) }
/** Gets the number of fields declared in this declaration. */
int getNumField() { result = max(int idx | fieldDeclaredIn(_, this, idx) | idx) + 1 }
override string toString() {
if this.getNumField() = 0
then result = this.getTypeAccess() + " " + this.getField(0) + ";"
else result = this.getTypeAccess() + " " + this.getField(0) + ", ...;"
}
}
/** A class or instance field. */
class Field extends Member, ExprParent, @field, Variable {
/** Gets the declared type of this field. */
override Type getType() { fields(this, _, result, _, _) }
/** Gets the type in which this field is declared. */
override RefType getDeclaringType() { fields(this, _, _, result, _) }
/**
* Gets the field declaration in which this field is declared.
*
* Note that this declaration is only available if the field occurs in source code.
*/
FieldDeclaration getDeclaration() { result.getAField() = this }
/** Gets the initializer expression of this field, if any. */
override Expr getInitializer() {
exists(AssignExpr e, InitializerMethod im |
e.getDest() = this.getAnAccess() and
e.getSource() = result and
result.getEnclosingCallable() = im and
// This rules out updates in explicit initializer blocks as they are nested inside the compiler generated initializer blocks.
e.getEnclosingStmt().getParent() = im.getBody()
)
}
/**
* Gets the source declaration of this field.
*
* For fields that are members of a parameterized
* instance of a generic type, the source declaration is the
* corresponding field in the generic type.
*
* For all other fields, the source declaration is the field itself.
*/
Field getSourceDeclaration() { fields(this, _, _, _, result) }
/** Holds if this field is the same as its source declaration. */
predicate isSourceDeclaration() { this.getSourceDeclaration() = this }
override predicate isPublic() {
Member.super.isPublic()
or
// JLS 9.3: Every field declaration in the body of an interface is
// implicitly public, static, and final
getDeclaringType() instanceof Interface
}
override predicate isStatic() {
Member.super.isStatic()
or
// JLS 9.3: Every field declaration in the body of an interface is
// implicitly public, static, and final
this.getDeclaringType() instanceof Interface
}
override predicate isFinal() {
Member.super.isFinal()
or
// JLS 9.3: Every field declaration in the body of an interface is
// implicitly public, static, and final
this.getDeclaringType() instanceof Interface
}
/** Cast this field to a class that provides access to metrics information. */
MetricField getMetrics() { result = this }
}
/** An instance field. */
class InstanceField extends Field {
InstanceField() { not this.isStatic() }
}