forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDeadField.qll
More file actions
171 lines (158 loc) · 5.47 KB
/
DeadField.qll
File metadata and controls
171 lines (158 loc) · 5.47 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
import java
import semmle.code.java.deadcode.DeadCode
import semmle.code.java.frameworks.javaee.Persistence
import semmle.code.java.frameworks.JAXB
import semmle.code.java.frameworks.jackson.JacksonSerializability
/**
* A field that is from a source file.
*
* This defines the set of fields for which we will determine liveness.
*/
library class SourceField extends Field {
SourceField() { fromSource() }
}
/**
* A field is dead if it is never read by a live callable and it is neither reflectively accessed,
* nor whitelisted.
*/
class DeadField extends SourceField {
DeadField() { not this instanceof LiveField }
/**
* Holds if this dead field is already within the scope of a dead class, or reported by a dead
* enum constant.
*/
predicate isInDeadScope() {
// `EnumConstant`s, and fields in dead classes, are reported in other queries.
getDeclaringType() instanceof DeadClass or
this instanceof EnumConstant
}
}
/**
* A field is live if it is read by a live callable, accessed by an annotation on a live element,
* reflectively read, or whitelisted as read.
*/
class LiveField extends SourceField {
LiveField() {
exists(FieldRead access | access = getAnAccess() |
isLive(access.getEnclosingCallable())
or
exists(Annotation a |
// This is an access used in an annotation, either directly, or within the expression.
a.getValue(_) = access.getParent*()
|
// The annotated element is a live callable.
isLive(a.getAnnotatedElement())
or
// The annotated element is in a live callable.
isLive(a.getAnnotatedElement().(LocalVariableDecl).getEnclosingCallable())
or
// The annotated element is a live field.
a.getAnnotatedElement() instanceof LiveField
or
// The annotated element is a live source class or interface.
// Note: We ignore annotation values on library classes, because they should only refer to
// fields in library classes, not `fromSource()` fields.
a.getAnnotatedElement() instanceof LiveClass
)
)
or
this instanceof ReflectivelyReadField
or
this instanceof WhitelistedLiveField
}
}
/**
* A field that may be read reflectively.
*/
abstract class ReflectivelyReadField extends Field { }
/**
* A field which is dead, but should be considered as live.
*
* This should be used for cases where the field is dead, but should not be removed - for example,
* because it may be useful in the future. If the field is live, but is not marked as a such, then
* either a new `EntryPoint` should be added, or, if the field is accessed reflectively, this should
* be identified by extending `ReflectivelyReadField` instead.
*
* Whitelisting a field will automatically cause the containing class to be considered as live.
*/
abstract class WhitelistedLiveField extends Field { }
/**
* A static, final, long field named `serialVersionUID` in a class that extends `Serializable` acts as
* a version number for the serialization framework.
*/
class SerialVersionUIDField extends ReflectivelyReadField {
SerialVersionUIDField() {
hasName("serialVersionUID") and
isStatic() and
isFinal() and
getType().hasName("long") and
getDeclaringType().getASupertype*() instanceof TypeSerializable
}
}
/**
* A field is read by the JAXB during serialization if it is a JAXB bound field, and if the
* containing class is considered "live".
*/
class LiveJaxbBoundField extends ReflectivelyReadField, JaxbBoundField {
LiveJaxbBoundField() {
// If the class is considered live, it must have at least one live constructor.
exists(Constructor c | c = getDeclaringType().getAConstructor() | isLive(c))
}
}
/**
* A field with an annotation which implies that it will be read by `JUnit` when running tests
* within this class.
*/
class JUnitAnnotatedField extends ReflectivelyReadField {
JUnitAnnotatedField() {
hasAnnotation("org.junit.experimental.theories", "DataPoint") or
hasAnnotation("org.junit.experimental.theories", "DataPoints") or
hasAnnotation("org.junit.runners", "Parameterized$Parameter") or
hasAnnotation("org.junit", "Rule") or
hasAnnotation("org.junit", "ClassRule")
}
}
/**
* A field that is reflectively read via a call to `Class.getField(...)`.
*/
class ClassReflectivelyReadField extends ReflectivelyReadField {
ClassReflectivelyReadField() {
exists(ReflectiveFieldAccess fieldAccess | this = fieldAccess.inferAccessedField())
}
}
/**
* Consider all `JacksonSerializableField`s as reflectively read.
*/
class JacksonSerializableReflectivelyReadField extends ReflectivelyReadField,
JacksonSerializableField { }
/**
* A field that is used when applying Jackson mixins.
*/
class JacksonMixinReflextivelyReadField extends ReflectivelyReadField {
JacksonMixinReflextivelyReadField() {
exists(JacksonMixinType mixinType, JacksonAddMixinCall mixinCall |
this = mixinType.getAMixedInField() and
mixinType = mixinCall.getAMixedInType()
|
isLive(mixinCall.getEnclosingCallable())
)
}
}
/**
* A field which is read by a JPA compatible Java persistence framework.
*/
class JPAReadField extends ReflectivelyReadField {
JPAReadField() {
exists(PersistentEntity entity |
this = entity.getAField() and
(
entity.getAccessType() = "field" or
this.hasAnnotation("javax.persistence", "Access")
)
|
not this.hasAnnotation("javax.persistence", "Transient") and
not isStatic() and
not isFinal()
)
}
}