Skip to content

Commit 02c8fe9

Browse files
Marcono1234smowton
authored andcommitted
Java: Add convenience predicates for AnnotationType
1 parent f69b6ee commit 02c8fe9

File tree

2 files changed

+38
-8
lines changed

2 files changed

+38
-8
lines changed

java/ql/lib/semmle/code/java/Annotation.qll

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,43 @@ class AnnotationType extends Interface {
227227

228228
/** Holds if this annotation type is annotated with the meta-annotation `@Inherited`. */
229229
predicate isInherited() {
230-
exists(Annotation ann |
231-
ann.getAnnotatedElement() = this and
232-
ann.getType().hasQualifiedName("java.lang.annotation", "Inherited")
233-
)
230+
getADeclaredAnnotation().getType().hasQualifiedName("java.lang.annotation", "Inherited")
231+
}
232+
233+
/** Holds if this annotation type is annotated with the meta-annotation `@Documented`. */
234+
predicate isDocumented() {
235+
getADeclaredAnnotation().getType().hasQualifiedName("java.lang.annotation", "Documented")
236+
}
237+
238+
/**
239+
* Gets the retention policy of this annotation type, that is, the name of one of the
240+
* enum constants of `java.lang.annotation.RetentionPolicy`. If no explicit retention
241+
* policy is specified the result is `CLASS`.
242+
*/
243+
string getRetentionPolicy() {
244+
if getADeclaredAnnotation() instanceof RetentionAnnotation
245+
then result = getADeclaredAnnotation().(RetentionAnnotation).getRetentionPolicy()
246+
else
247+
// If not explicitly specified retention is CLASS
248+
result = "CLASS"
249+
}
250+
251+
/**
252+
* Holds if the element type is a possible target for this annotation type.
253+
* The `elementType` is the name of one of the `java.lang.annotation.ElementType`
254+
* enum constants. If no explicit target is specified for this annotation type
255+
* it is considered to be applicable to all elements.
256+
*/
257+
// Note: Cannot use a predicate with string as result because annotation type without
258+
// explicit @Target can be applied to all targets, requiring to hardcode element types here
259+
bindingset[elementType]
260+
predicate isATargetType(string elementType) {
261+
if getADeclaredAnnotation() instanceof TargetAnnotation
262+
then elementType = getADeclaredAnnotation().(TargetAnnotation).getATargetElementType()
263+
else
264+
// No Target annotation means "applicable to all contexts" since JDK 14, see https://bugs.openjdk.java.net/browse/JDK-8231435
265+
// The compiler does not completely implement that, but pretend it did
266+
any()
234267
}
235268
}
236269

java/ql/src/Likely Bugs/Reflection/AnnotationPresentCheck.ql

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,5 @@ where
1919
m.getNumberOfParameters() = 1 and
2020
c.getArgument(0).getType() = p and
2121
p.getATypeArgument() = t and
22-
not exists(RetentionAnnotation a |
23-
t.getAnAnnotation() = a and
24-
a.getAValue().(VarAccess).getVariable().hasName("RUNTIME")
25-
)
22+
t.getRetentionPolicy() != "RUNTIME"
2623
select c, "Call to isAnnotationPresent where no annotation has the RUNTIME retention policy."

0 commit comments

Comments
 (0)