forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAnnotation.qll
More file actions
executable file
·163 lines (137 loc) · 5.79 KB
/
Annotation.qll
File metadata and controls
executable file
·163 lines (137 loc) · 5.79 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
/**
* Provides classes and predicates for working with Java annotations.
*
* Annotations are used to add meta-information to language elements in a
* uniform fashion. They can be seen as typed modifiers that can take
* parameters.
*
* Each annotation type has zero or more annotation elements that contain a
* name and possibly a value.
*/
import Element
import Expr
import Type
import Member
import JDKAnnotations
/** Any annotation used to annotate language elements with meta-information. */
class Annotation extends @annotation, Expr {
/** Holds if this annotation applies to a declaration. */
predicate isDeclAnnotation() { this instanceof DeclAnnotation }
/** Holds if this annotation applies to a type. */
predicate isTypeAnnotation() { this instanceof TypeAnnotation }
/** Gets the element being annotated. */
Element getAnnotatedElement() {
exists(Element e | e = this.getParent() |
if e.(Field).getCompilationUnit().fromSource()
then
exists(FieldDeclaration decl |
decl.getField(0) = e and
result = decl.getAField()
)
else result = e
)
}
/** Gets the annotation type declaration for this annotation. */
override AnnotationType getType() { result = Expr.super.getType() }
/** Gets the annotation element with the specified `name`. */
AnnotationElement getAnnotationElement(string name) {
result = this.getType().getAnnotationElement(name)
}
/** Gets a value of an annotation element. */
Expr getAValue() { filteredAnnotValue(this, _, result) }
/** Gets the value of the annotation element with the specified `name`. */
Expr getValue(string name) { filteredAnnotValue(this, this.getAnnotationElement(name), result) }
/** Gets the element being annotated. */
Element getTarget() { result = getAnnotatedElement() }
override string toString() { result = this.getType().getName() }
/** This expression's Halstead ID (used to compute Halstead metrics). */
override string getHalsteadID() { result = "Annotation" }
/**
* Gets a value of the annotation element with the specified `name`, which must be declared as an array
* type.
*
* If the annotation element is defined with an array initializer, then the returned value will
* be one of the elements of that array. Otherwise, the returned value will be the single
* expression defined for the value.
*/
Expr getAValue(string name) {
getType().getAnnotationElement(name).getType() instanceof Array and
exists(Expr value | value = getValue(name) |
if value instanceof ArrayInit then result = value.(ArrayInit).getAnInit() else result = value
)
}
}
/** An `Annotation` that applies to a declaration. */
class DeclAnnotation extends @declannotation, Annotation { }
/** An `Annotation` that applies to a type. */
class TypeAnnotation extends @typeannotation, Annotation { }
/**
* There may be duplicate entries in annotValue(...) - one entry for
* information populated from bytecode, and one for information populated
* from source. This removes the duplication.
*/
private predicate filteredAnnotValue(Annotation a, Method m, Expr val) {
annotValue(a, m, val) and
(sourceAnnotValue(a, m, val) or not sourceAnnotValue(a, m, _))
}
private predicate sourceAnnotValue(Annotation a, Method m, Expr val) {
annotValue(a, m, val) and
val.getFile().getExtension() = "java"
}
/** An abstract representation of language elements that can be annotated. */
class Annotatable extends Element {
/** Holds if this element has an annotation. */
predicate hasAnnotation() { exists(Annotation a | a.getAnnotatedElement() = this) }
/** Holds if this element has the specified annotation. */
predicate hasAnnotation(string package, string name) {
exists(AnnotationType at | at = getAnAnnotation().getType() |
at.nestedName() = name and at.getPackage().getName() = package
)
}
/** Gets an annotation that applies to this element. */
Annotation getAnAnnotation() { result.getAnnotatedElement() = this }
/**
* Holds if this or any enclosing `Annotatable` has a `@SuppressWarnings("<category>")`
* annotation attached to it for the specified `category`.
*/
predicate suppressesWarningsAbout(string category) {
exists(string withQuotes |
withQuotes = getAnAnnotation().(SuppressWarningsAnnotation).getASuppressedWarning()
|
category = withQuotes.substring(1, withQuotes.length() - 1)
)
or
this.(Member).getDeclaringType().suppressesWarningsAbout(category)
or
this.(Expr).getEnclosingCallable().suppressesWarningsAbout(category)
or
this.(Stmt).getEnclosingCallable().suppressesWarningsAbout(category)
or
this.(NestedClass).getEnclosingType().suppressesWarningsAbout(category)
or
this.(LocalVariableDecl).getCallable().suppressesWarningsAbout(category)
}
}
/** An annotation type is a special kind of interface type declaration. */
class AnnotationType extends Interface {
AnnotationType() { isAnnotType(this) }
/** Gets the annotation element with the specified `name`. */
AnnotationElement getAnnotationElement(string name) {
methods(result, _, _, _, this, _) and result.hasName(name)
}
/** Gets an annotation element that is a member of this annotation type. */
AnnotationElement getAnAnnotationElement() { methods(result, _, _, _, this, _) }
/** Holds if this annotation type is annotated with the meta-annotation `@Inherited`. */
predicate isInherited() {
exists(Annotation ann |
ann.getAnnotatedElement() = this and
ann.getType().hasQualifiedName("java.lang.annotation", "Inherited")
)
}
}
/** An annotation element is a member declared in an annotation type. */
class AnnotationElement extends Member {
AnnotationElement() { isAnnotElem(this) }
/** Gets the type of this annotation element. */
Type getType() { methods(this, _, _, result, _, _) }
}