mirror of
https://github.com/github/codeql.git
synced 2025-12-20 02:44:30 +01:00
166 lines
5.9 KiB
Plaintext
Executable File
166 lines
5.9 KiB
Plaintext
Executable File
/**
|
|
* 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 = this.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) {
|
|
this.getType().getAnnotationElement(name).getType() instanceof Array and
|
|
exists(Expr value | value = this.getValue(name) |
|
|
if value instanceof ArrayInit then result = value.(ArrayInit).getAnInit() else result = value
|
|
)
|
|
}
|
|
|
|
override string getAPrimaryQlClass() { result = "Annotation" }
|
|
}
|
|
|
|
/** 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 = this.getAnAnnotation().getType() |
|
|
at.nestedName() = name and at.getPackage().getName() = package
|
|
)
|
|
}
|
|
|
|
/** Gets an annotation that applies to this element. */
|
|
cached
|
|
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) {
|
|
category = this.getAnAnnotation().(SuppressWarningsAnnotation).getASuppressedWarning()
|
|
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, _, _) }
|
|
|
|
/** Gets the Kotlin type of this annotation element. */
|
|
KotlinType getKotlinType() { methodsKotlinType(this, result) }
|
|
}
|