mirror of
https://github.com/github/codeql.git
synced 2026-02-28 21:03:50 +01:00
Java: Autoformat most of semmle.code.java.
This commit is contained in:
@@ -38,14 +38,10 @@ class Annotation extends @annotation, Expr {
|
||||
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)
|
||||
}
|
||||
Expr getValue(string name) { filteredAnnotValue(this, this.getAnnotationElement(name), result) }
|
||||
|
||||
/** Gets the element being annotated. */
|
||||
Element getTarget() {
|
||||
exprs(this, _, _, result, _)
|
||||
}
|
||||
Element getTarget() { exprs(this, _, _, result, _) }
|
||||
|
||||
override string toString() { result = this.getType().getName() }
|
||||
|
||||
@@ -63,35 +59,28 @@ class Annotation extends @annotation, Expr {
|
||||
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
|
||||
if value instanceof ArrayInit then result = value.(ArrayInit).getAnInit() else result = value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** An `Annotation` that applies to a declaration. */
|
||||
class DeclAnnotation extends @declannotation, Annotation {
|
||||
}
|
||||
class DeclAnnotation extends @declannotation, Annotation { }
|
||||
|
||||
/** An `Annotation` that applies to a type. */
|
||||
class TypeAnnotation extends @typeannotation, Annotation {
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
private predicate sourceAnnotValue(Annotation a, Method m, Expr val) {
|
||||
annotValue(a, m, val) and
|
||||
val.getFile().getExtension() = "java"
|
||||
}
|
||||
@@ -103,7 +92,9 @@ class Annotatable extends Element {
|
||||
|
||||
/** 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)
|
||||
exists(AnnotationType at | at = getAnAnnotation().getType() |
|
||||
at.nestedName() = name and at.getPackage().getName() = package
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets an annotation that applies to this element. */
|
||||
@@ -114,14 +105,20 @@ class Annotatable extends Element {
|
||||
* annotation attached to it for the specified `category`.
|
||||
*/
|
||||
predicate suppressesWarningsAbout(string category) {
|
||||
exists(string withQuotes
|
||||
| withQuotes = ((SuppressWarningsAnnotation) getAnAnnotation()).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
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -132,13 +129,11 @@ class AnnotationType extends Interface {
|
||||
|
||||
/** Gets the annotation element with the specified `name`. */
|
||||
AnnotationElement getAnnotationElement(string name) {
|
||||
methods(result,_,_,_,this,_) and result.hasName(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,_)
|
||||
}
|
||||
AnnotationElement getAnAnnotationElement() { methods(result, _, _, _, this, _) }
|
||||
|
||||
/** Holds if this annotation type is annotated with the meta-annotation `@Inherited`. */
|
||||
predicate isInherited() {
|
||||
@@ -154,5 +149,5 @@ class AnnotationElement extends Member {
|
||||
AnnotationElement() { isAnnotElem(this) }
|
||||
|
||||
/** Gets the type of this annotation element. */
|
||||
Type getType() { methods(this,_,_,result,_,_) }
|
||||
Type getType() { methods(this, _, _, result, _, _) }
|
||||
}
|
||||
|
||||
@@ -9,9 +9,11 @@ import java
|
||||
* `List<T>`, instantiating the type parameter to `Object`.
|
||||
*/
|
||||
predicate instantiates(RefType t, GenericType g, int i, RefType arg) {
|
||||
t = g.getAParameterizedType() and exists(g.getTypeParameter(i)) and
|
||||
t = g.getAParameterizedType() and
|
||||
exists(g.getTypeParameter(i)) and
|
||||
(
|
||||
arg = t.(ParameterizedType).getTypeArgument(i) or
|
||||
arg = t.(ParameterizedType).getTypeArgument(i)
|
||||
or
|
||||
t instanceof RawType and arg instanceof TypeObject
|
||||
)
|
||||
}
|
||||
@@ -40,7 +42,7 @@ predicate indirectlyInstantiates(RefType t, GenericType g, int i, RefType arg) {
|
||||
(extendsReftype(tsrc, sup) or implInterface(tsrc, sup)) and
|
||||
// check whether the subtype instantiates `g`
|
||||
indirectlyInstantiates(sup, g, i, suparg)
|
||||
|
|
||||
|
|
||||
// if `t` is itself an instantiation of `tsrc` and `sup` instantiates
|
||||
// `g` to one of the type parameters of `tsrc`, we return the corresponding
|
||||
// instantiation in `t`
|
||||
@@ -63,7 +65,7 @@ class CollectionType extends RefType {
|
||||
CollectionType() {
|
||||
exists(ParameterizedInterface coll |
|
||||
coll.getSourceDeclaration().hasQualifiedName("java.util", "Collection")
|
||||
|
|
||||
|
|
||||
this.hasSupertype*(coll)
|
||||
)
|
||||
}
|
||||
@@ -78,9 +80,7 @@ class CollectionType extends RefType {
|
||||
|
||||
/** A method declared in a collection type. */
|
||||
class CollectionMethod extends Method {
|
||||
CollectionMethod() {
|
||||
this.getDeclaringType() instanceof CollectionType
|
||||
}
|
||||
CollectionMethod() { this.getDeclaringType() instanceof CollectionType }
|
||||
|
||||
/** Gets the type of elements of the collection to which this method belongs. */
|
||||
RefType getReceiverElementType() {
|
||||
@@ -90,34 +90,24 @@ class CollectionMethod extends Method {
|
||||
|
||||
/** The `size` method on `java.util.Collection`. */
|
||||
class CollectionSizeMethod extends CollectionMethod {
|
||||
CollectionSizeMethod() {
|
||||
this.hasName("size") and this.hasNoParameters()
|
||||
}
|
||||
CollectionSizeMethod() { this.hasName("size") and this.hasNoParameters() }
|
||||
}
|
||||
|
||||
/** A method that mutates the collection it belongs to. */
|
||||
class CollectionMutator extends CollectionMethod {
|
||||
CollectionMutator() {
|
||||
this.getName().regexpMatch("add.*|remove.*|push|pop|clear")
|
||||
}
|
||||
CollectionMutator() { this.getName().regexpMatch("add.*|remove.*|push|pop|clear") }
|
||||
}
|
||||
|
||||
/** A method call that mutates a collection. */
|
||||
class CollectionMutation extends MethodAccess {
|
||||
CollectionMutation() {
|
||||
this.getMethod() instanceof CollectionMutator
|
||||
}
|
||||
CollectionMutation() { this.getMethod() instanceof CollectionMutator }
|
||||
|
||||
predicate resultIsChecked() {
|
||||
not this.getParent() instanceof ExprStmt
|
||||
}
|
||||
predicate resultIsChecked() { not this.getParent() instanceof ExprStmt }
|
||||
}
|
||||
|
||||
/** A method that queries the contents of a collection without mutating it. */
|
||||
class CollectionQueryMethod extends CollectionMethod {
|
||||
CollectionQueryMethod() {
|
||||
this.getName().regexpMatch("contains|containsAll|get|size|peek")
|
||||
}
|
||||
CollectionQueryMethod() { this.getName().regexpMatch("contains|containsAll|get|size|peek") }
|
||||
}
|
||||
|
||||
/** A `new` expression that allocates a fresh, empty collection. */
|
||||
|
||||
@@ -10,29 +10,21 @@ import semmle.code.FileSystem
|
||||
* A compilation unit is a `.java` or `.class` file.
|
||||
*/
|
||||
class CompilationUnit extends Element, File {
|
||||
CompilationUnit() {
|
||||
cupackage(this,_)
|
||||
}
|
||||
CompilationUnit() { cupackage(this, _) }
|
||||
|
||||
/** Gets the name of the compilation unit (not including its extension). */
|
||||
override string getName() {
|
||||
result = Element.super.getName()
|
||||
}
|
||||
override string getName() { result = Element.super.getName() }
|
||||
|
||||
/**
|
||||
* Holds if this compilation unit has the specified `name`,
|
||||
* which must not include the file extension.
|
||||
*/
|
||||
override predicate hasName(string name) {
|
||||
Element.super.hasName(name)
|
||||
}
|
||||
override predicate hasName(string name) { Element.super.hasName(name) }
|
||||
|
||||
override string toString() {
|
||||
result = Element.super.toString()
|
||||
}
|
||||
override string toString() { result = Element.super.toString() }
|
||||
|
||||
/** Gets the declared package of this compilation unit. */
|
||||
Package getPackage() { cupackage(this,result) }
|
||||
Package getPackage() { cupackage(this, result) }
|
||||
|
||||
/**
|
||||
* Gets the module associated with this compilation unit, if any.
|
||||
|
||||
@@ -24,12 +24,12 @@ import java
|
||||
*/
|
||||
newtype Label = MkLabel(string l) { exists(LabeledStmt lbl | l = lbl.getLabel()) }
|
||||
|
||||
|
||||
/**
|
||||
* Either a `Label` or nothing.
|
||||
*/
|
||||
newtype MaybeLabel = JustLabel(Label l) or NoLabel()
|
||||
|
||||
newtype MaybeLabel =
|
||||
JustLabel(Label l) or
|
||||
NoLabel()
|
||||
|
||||
/**
|
||||
* A completion of a statement or an expression.
|
||||
@@ -48,7 +48,8 @@ newtype Completion =
|
||||
* flow node having value `innerValue`.
|
||||
*/
|
||||
BooleanCompletion(boolean outerValue, boolean innerValue) {
|
||||
(outerValue = true or outerValue = false) and (innerValue = true or innerValue = false)
|
||||
(outerValue = true or outerValue = false) and
|
||||
(innerValue = true or innerValue = false)
|
||||
} or
|
||||
/**
|
||||
* The expression or statement completes via a `break` statement.
|
||||
@@ -63,25 +64,13 @@ newtype Completion =
|
||||
*/
|
||||
ThrowCompletion(ThrowableType tt)
|
||||
|
||||
ContinueCompletion anonymousContinueCompletion() { result = ContinueCompletion(NoLabel()) }
|
||||
|
||||
ContinueCompletion anonymousContinueCompletion() {
|
||||
result = ContinueCompletion(NoLabel())
|
||||
}
|
||||
ContinueCompletion labelledContinueCompletion(Label l) { result = ContinueCompletion(JustLabel(l)) }
|
||||
|
||||
ContinueCompletion labelledContinueCompletion(Label l) {
|
||||
result = ContinueCompletion(JustLabel(l))
|
||||
}
|
||||
BreakCompletion anonymousBreakCompletion() { result = BreakCompletion(NoLabel()) }
|
||||
|
||||
BreakCompletion anonymousBreakCompletion() {
|
||||
result = BreakCompletion(NoLabel())
|
||||
}
|
||||
|
||||
BreakCompletion labelledBreakCompletion(Label l) {
|
||||
result = BreakCompletion(JustLabel(l))
|
||||
}
|
||||
BreakCompletion labelledBreakCompletion(Label l) { result = BreakCompletion(JustLabel(l)) }
|
||||
|
||||
/** Gets the completion `booleanCompletion(value, value)`. */
|
||||
Completion basicBooleanCompletion(boolean value) {
|
||||
result = BooleanCompletion(value, value)
|
||||
}
|
||||
|
||||
Completion basicBooleanCompletion(boolean value) { result = BooleanCompletion(value, value) }
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import java
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@
|
||||
*
|
||||
* See the Java Language Specification, Section 5, for details.
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.arithmetic.Overflow
|
||||
|
||||
@@ -21,23 +22,17 @@ abstract class ConversionSite extends Expr {
|
||||
/**
|
||||
* Gets the type that is converted from.
|
||||
*/
|
||||
Type getConversionSource() {
|
||||
result = this.getType()
|
||||
}
|
||||
Type getConversionSource() { result = this.getType() }
|
||||
|
||||
/**
|
||||
* Whether this conversion site actually induces a conversion.
|
||||
*/
|
||||
predicate isTrivial() {
|
||||
getConversionTarget() = getConversionSource()
|
||||
}
|
||||
predicate isTrivial() { getConversionTarget() = getConversionSource() }
|
||||
|
||||
/**
|
||||
* Whether this conversion is implicit.
|
||||
*/
|
||||
predicate isImplicit() {
|
||||
any()
|
||||
}
|
||||
predicate isImplicit() { any() }
|
||||
|
||||
abstract string kind();
|
||||
}
|
||||
@@ -50,18 +45,16 @@ abstract class ConversionSite extends Expr {
|
||||
*/
|
||||
class AssignmentConversionContext extends ConversionSite {
|
||||
Variable v;
|
||||
|
||||
AssignmentConversionContext() {
|
||||
this = v.getAnAssignedValue() or
|
||||
this = v.getAnAssignedValue()
|
||||
or
|
||||
exists(Assignment a | a.getDest().getProperExpr() = v.getAnAccess() and this = a.getSource())
|
||||
}
|
||||
|
||||
override Type getConversionTarget() {
|
||||
result = v.getType()
|
||||
}
|
||||
override Type getConversionTarget() { result = v.getType() }
|
||||
|
||||
override string kind() {
|
||||
result = "assignment context"
|
||||
}
|
||||
override string kind() { result = "assignment context" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,16 +66,12 @@ class AssignmentConversionContext extends ConversionSite {
|
||||
*/
|
||||
class ReturnConversionSite extends ConversionSite {
|
||||
ReturnStmt r;
|
||||
ReturnConversionSite() {
|
||||
this = r.getResult()
|
||||
}
|
||||
|
||||
override Type getConversionTarget() {
|
||||
result = r.getEnclosingCallable().getReturnType()
|
||||
}
|
||||
override string kind() {
|
||||
result = "return context"
|
||||
}
|
||||
ReturnConversionSite() { this = r.getResult() }
|
||||
|
||||
override Type getConversionTarget() { result = r.getEnclosingCallable().getReturnType() }
|
||||
|
||||
override string kind() { result = "return context" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,18 +82,14 @@ class ReturnConversionSite extends ConversionSite {
|
||||
*/
|
||||
class InvocationConversionContext extends ConversionSite {
|
||||
Call c;
|
||||
|
||||
int index;
|
||||
InvocationConversionContext() {
|
||||
this = c.getArgument(index)
|
||||
}
|
||||
|
||||
override Type getConversionTarget() {
|
||||
result = c.getCallee().getParameter(index).getType()
|
||||
}
|
||||
InvocationConversionContext() { this = c.getArgument(index) }
|
||||
|
||||
override string kind() {
|
||||
result = "invocation context"
|
||||
}
|
||||
override Type getConversionTarget() { result = c.getCallee().getParameter(index).getType() }
|
||||
|
||||
override string kind() { result = "invocation context" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,38 +100,28 @@ class InvocationConversionContext extends ConversionSite {
|
||||
*/
|
||||
class StringConversionContext extends ConversionSite {
|
||||
AddExpr a;
|
||||
|
||||
StringConversionContext() {
|
||||
a.getAnOperand() = this and
|
||||
not this.getType() instanceof TypeString and
|
||||
a.getAnOperand().getType() instanceof TypeString
|
||||
}
|
||||
|
||||
override Type getConversionTarget() {
|
||||
result instanceof TypeString
|
||||
}
|
||||
override Type getConversionTarget() { result instanceof TypeString }
|
||||
|
||||
override string kind() {
|
||||
result = "string context"
|
||||
}
|
||||
override string kind() { result = "string context" }
|
||||
}
|
||||
|
||||
class CastConversionContext extends ConversionSite {
|
||||
CastExpr c;
|
||||
CastConversionContext() {
|
||||
this = c.getExpr()
|
||||
}
|
||||
|
||||
override Type getConversionTarget() {
|
||||
result = c.getType()
|
||||
}
|
||||
CastConversionContext() { this = c.getExpr() }
|
||||
|
||||
override predicate isImplicit() {
|
||||
none()
|
||||
}
|
||||
override Type getConversionTarget() { result = c.getType() }
|
||||
|
||||
override string kind() {
|
||||
result = "cast context"
|
||||
}
|
||||
override predicate isImplicit() { none() }
|
||||
|
||||
override string kind() { result = "cast context" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,16 +132,10 @@ class CastConversionContext extends ConversionSite {
|
||||
*/
|
||||
class NumericConversionContext extends ConversionSite {
|
||||
ArithExpr e;
|
||||
NumericConversionContext() {
|
||||
this = e.getAnOperand()
|
||||
}
|
||||
|
||||
override Type getConversionTarget() {
|
||||
result = e.getType()
|
||||
}
|
||||
NumericConversionContext() { this = e.getAnOperand() }
|
||||
|
||||
override string kind() {
|
||||
result = "numeric context"
|
||||
}
|
||||
override Type getConversionTarget() { result = e.getType() }
|
||||
|
||||
override string kind() { result = "numeric context" }
|
||||
}
|
||||
|
||||
@@ -34,57 +34,48 @@ predicate depends(RefType t, RefType dep) {
|
||||
usesType(t.(NestedType).getEnclosingType(), dep)
|
||||
or
|
||||
// the type of any field declared in `t`,
|
||||
exists(Field f | f.getDeclaringType() = t |
|
||||
usesType(f.getType(), dep)
|
||||
) or
|
||||
exists(Field f | f.getDeclaringType() = t | usesType(f.getType(), dep))
|
||||
or
|
||||
// the return type of any method declared in `t`,
|
||||
exists(Method m | m.getDeclaringType() = t |
|
||||
usesType(m.getReturnType(), dep)
|
||||
) or
|
||||
exists(Method m | m.getDeclaringType() = t | usesType(m.getReturnType(), dep))
|
||||
or
|
||||
// the type of any parameter of a callable in `t`,
|
||||
exists(Callable c | c.getDeclaringType() = t |
|
||||
usesType(c.getAParamType(), dep)
|
||||
) or
|
||||
exists(Callable c | c.getDeclaringType() = t | usesType(c.getAParamType(), dep))
|
||||
or
|
||||
// the type of any exception in the `throws` clause of a callable declared in `t`,
|
||||
exists(Exception e | e.getCallable().getDeclaringType() = t |
|
||||
usesType(e.getType(), dep)
|
||||
) or
|
||||
exists(Exception e | e.getCallable().getDeclaringType() = t | usesType(e.getType(), dep))
|
||||
or
|
||||
// the declaring type of a callable accessed in `t`,
|
||||
exists(Callable c |
|
||||
c.getAReference().getEnclosingCallable().getDeclaringType() = t
|
||||
|
|
||||
exists(Callable c | c.getAReference().getEnclosingCallable().getDeclaringType() = t |
|
||||
usesType(c.getSourceDeclaration().getDeclaringType(), dep)
|
||||
) or
|
||||
)
|
||||
or
|
||||
// the declaring type of a field accessed in `t`,
|
||||
exists(Field f |
|
||||
f.getAnAccess().getEnclosingCallable().getDeclaringType() = t
|
||||
|
|
||||
exists(Field f | f.getAnAccess().getEnclosingCallable().getDeclaringType() = t |
|
||||
usesType(f.getSourceDeclaration().getDeclaringType(), dep)
|
||||
) or
|
||||
)
|
||||
or
|
||||
// the type of a local variable declared in `t`,
|
||||
exists(LocalVariableDeclExpr decl |
|
||||
decl.getEnclosingCallable().getDeclaringType() = t
|
||||
|
|
||||
exists(LocalVariableDeclExpr decl | decl.getEnclosingCallable().getDeclaringType() = t |
|
||||
usesType(decl.getType(), dep)
|
||||
) or
|
||||
)
|
||||
or
|
||||
// the type of a type literal accessed in `t`,
|
||||
exists(TypeLiteral l |
|
||||
l.getEnclosingCallable().getDeclaringType() = t
|
||||
|
|
||||
exists(TypeLiteral l | l.getEnclosingCallable().getDeclaringType() = t |
|
||||
usesType(l.getTypeName().getType(), dep)
|
||||
) or
|
||||
)
|
||||
or
|
||||
// the type of an annotation (or one of its element values) that annotates `t` or one of its members,
|
||||
exists(Annotation a |
|
||||
a.getAnnotatedElement() = t or
|
||||
a.getAnnotatedElement().(Member).getDeclaringType() = t
|
||||
|
|
||||
|
|
||||
usesType(a.getType(), dep) or
|
||||
usesType(a.getAValue().getType(), dep)
|
||||
) or
|
||||
)
|
||||
or
|
||||
// the type accessed in an `instanceof` expression in `t`.
|
||||
exists(InstanceOfExpr ioe |
|
||||
t = ioe.getEnclosingCallable().getDeclaringType()
|
||||
|
|
||||
exists(InstanceOfExpr ioe | t = ioe.getEnclosingCallable().getDeclaringType() |
|
||||
usesType(ioe.getTypeName().getType(), dep)
|
||||
)
|
||||
)
|
||||
@@ -108,8 +99,7 @@ predicate usesType(Type t, RefType dep) {
|
||||
* the element type of an array type, or
|
||||
* a bound of a type variable or wildcard.
|
||||
*/
|
||||
private
|
||||
RefType inside(Type t) {
|
||||
private RefType inside(Type t) {
|
||||
result = t.(TypeVariable).getATypeBound().getType() or
|
||||
result = t.(Wildcard).getATypeBound().getType() or
|
||||
result = t.(ParameterizedType).getATypeArgument() or
|
||||
|
||||
@@ -28,89 +28,98 @@ predicate numDepends(RefType t, RefType dep, int value) {
|
||||
not t = dep and
|
||||
// Type `t` depends on:
|
||||
value = strictcount(Element elem |
|
||||
// its supertypes,
|
||||
exists(RefType s | elem = s and t.hasSupertype(s) |
|
||||
usesType(s, dep)
|
||||
) or
|
||||
// its enclosing types,
|
||||
exists(RefType s | elem = s and t.getEnclosingType() = s |
|
||||
usesType(s, dep)
|
||||
) or
|
||||
// the type of any field declared in `t`,
|
||||
exists(Field f | elem = f and f.getDeclaringType() = t |
|
||||
usesType(f.getType(), dep)
|
||||
) or
|
||||
// the return type of any method declared in `t`,
|
||||
exists(Method m | elem = m and m.getDeclaringType() = t |
|
||||
usesType(m.getReturnType(), dep)
|
||||
) or
|
||||
// the type of any parameter of a callable in `t`,
|
||||
exists(Parameter p | elem = p and p.getCallable().getDeclaringType() = t |
|
||||
usesType(p.getType(), dep)
|
||||
) or
|
||||
// the type of any exception in the `throws` clause of a callable declared in `t`,
|
||||
exists(Exception e | elem = e and e.getCallable().getDeclaringType() = t |
|
||||
usesType(e.getType(), dep)
|
||||
) or
|
||||
// the declaring type of a callable accessed in `t`,
|
||||
exists(Call c | elem = c and
|
||||
c.getEnclosingCallable().getDeclaringType() = t
|
||||
// its supertypes,
|
||||
exists(RefType s | elem = s and t.hasSupertype(s) | usesType(s, dep))
|
||||
or
|
||||
// its enclosing types,
|
||||
exists(RefType s | elem = s and t.getEnclosingType() = s | usesType(s, dep))
|
||||
or
|
||||
// the type of any field declared in `t`,
|
||||
exists(Field f | elem = f and f.getDeclaringType() = t | usesType(f.getType(), dep))
|
||||
or
|
||||
// the return type of any method declared in `t`,
|
||||
exists(Method m | elem = m and m.getDeclaringType() = t | usesType(m.getReturnType(), dep))
|
||||
or
|
||||
// the type of any parameter of a callable in `t`,
|
||||
exists(Parameter p | elem = p and p.getCallable().getDeclaringType() = t |
|
||||
usesType(p.getType(), dep)
|
||||
)
|
||||
or
|
||||
// the type of any exception in the `throws` clause of a callable declared in `t`,
|
||||
exists(Exception e | elem = e and e.getCallable().getDeclaringType() = t |
|
||||
usesType(e.getType(), dep)
|
||||
)
|
||||
or
|
||||
// the declaring type of a callable accessed in `t`,
|
||||
exists(Call c |
|
||||
elem = c and
|
||||
c.getEnclosingCallable().getDeclaringType() = t
|
||||
|
|
||||
usesType(c.getCallee().getSourceDeclaration().getDeclaringType(), dep)
|
||||
) or
|
||||
// the declaring type of a field accessed in `t`,
|
||||
exists(FieldAccess fa | elem = fa and
|
||||
fa.getEnclosingCallable().getDeclaringType() = t
|
||||
usesType(c.getCallee().getSourceDeclaration().getDeclaringType(), dep)
|
||||
)
|
||||
or
|
||||
// the declaring type of a field accessed in `t`,
|
||||
exists(FieldAccess fa |
|
||||
elem = fa and
|
||||
fa.getEnclosingCallable().getDeclaringType() = t
|
||||
|
|
||||
usesType(fa.getField().getSourceDeclaration().getDeclaringType(), dep)
|
||||
) or
|
||||
// the type of a local variable declared in `t`,
|
||||
exists(LocalVariableDeclExpr decl | elem = decl and
|
||||
decl.getEnclosingCallable().getDeclaringType() = t
|
||||
usesType(fa.getField().getSourceDeclaration().getDeclaringType(), dep)
|
||||
)
|
||||
or
|
||||
// the type of a local variable declared in `t`,
|
||||
exists(LocalVariableDeclExpr decl |
|
||||
elem = decl and
|
||||
decl.getEnclosingCallable().getDeclaringType() = t
|
||||
|
|
||||
usesType(decl.getType(), dep)
|
||||
) or
|
||||
// the type of a type literal accessed in `t`,
|
||||
exists(TypeLiteral l | elem = l and
|
||||
l.getEnclosingCallable().getDeclaringType() = t
|
||||
usesType(decl.getType(), dep)
|
||||
)
|
||||
or
|
||||
// the type of a type literal accessed in `t`,
|
||||
exists(TypeLiteral l |
|
||||
elem = l and
|
||||
l.getEnclosingCallable().getDeclaringType() = t
|
||||
|
|
||||
usesType(l.getTypeName().getType(), dep)
|
||||
) or
|
||||
// the type of an annotation (or one of its element values) that annotates `t` or one of its members,
|
||||
exists(Annotation a |
|
||||
a.getAnnotatedElement() = t or
|
||||
a.getAnnotatedElement().(Member).getDeclaringType() = t
|
||||
usesType(l.getTypeName().getType(), dep)
|
||||
)
|
||||
or
|
||||
// the type of an annotation (or one of its element values) that annotates `t` or one of its members,
|
||||
exists(Annotation a |
|
||||
a.getAnnotatedElement() = t or
|
||||
a.getAnnotatedElement().(Member).getDeclaringType() = t
|
||||
|
|
||||
elem = a and usesType(a.getType(), dep) or
|
||||
elem = a.getAValue() and elem.getFile().getExtension() = "java" and usesType(elem.(Expr).getType(), dep)
|
||||
) or
|
||||
// the type accessed in an `instanceof` expression in `t`.
|
||||
exists(InstanceOfExpr ioe | elem = ioe and
|
||||
t = ioe.getEnclosingCallable().getDeclaringType()
|
||||
elem = a and usesType(a.getType(), dep)
|
||||
or
|
||||
elem = a.getAValue() and
|
||||
elem.getFile().getExtension() = "java" and
|
||||
usesType(elem.(Expr).getType(), dep)
|
||||
)
|
||||
or
|
||||
// the type accessed in an `instanceof` expression in `t`.
|
||||
exists(InstanceOfExpr ioe |
|
||||
elem = ioe and
|
||||
t = ioe.getEnclosingCallable().getDeclaringType()
|
||||
|
|
||||
usesType(ioe.getTypeName().getType(), dep)
|
||||
usesType(ioe.getTypeName().getType(), dep)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate filePackageDependencyCount(File sourceFile, int total, string entity) {
|
||||
exists(Package targetPackage |
|
||||
total = strictsum(RefType sourceType, RefType targetType, int num |
|
||||
sourceType.getFile() = sourceFile and
|
||||
sourceType.fromSource() and
|
||||
sourceType.getPackage() != targetPackage and
|
||||
targetType.getPackage() = targetPackage and
|
||||
numDepends(sourceType, targetType, num)
|
||||
sourceType.getFile() = sourceFile and
|
||||
sourceType.fromSource() and
|
||||
sourceType.getPackage() != targetPackage and
|
||||
targetType.getPackage() = targetPackage and
|
||||
numDepends(sourceType, targetType, num)
|
||||
|
|
||||
num)
|
||||
and
|
||||
num
|
||||
) and
|
||||
entity = "/" + sourceFile.getRelativePath() + "<|>" + targetPackage + "<|>N/A"
|
||||
)
|
||||
}
|
||||
|
||||
private string nameVersionRegex() {
|
||||
result = "([_.A-Za-z0-9-]*)-([0-9][A-Za-z0-9.+_-]*)"
|
||||
}
|
||||
private string nameVersionRegex() { result = "([_.A-Za-z0-9-]*)-([0-9][A-Za-z0-9.+_-]*)" }
|
||||
|
||||
/**
|
||||
* Given a JAR filename, try to split it into a name and version.
|
||||
@@ -122,7 +131,8 @@ bindingset[target]
|
||||
predicate hasDashedVersion(string target, string name, string version) {
|
||||
exists(string regex | regex = nameVersionRegex() |
|
||||
name = target.regexpCapture(regex, 1) and
|
||||
version = target.regexpCapture(regex, 2))
|
||||
version = target.regexpCapture(regex, 2)
|
||||
)
|
||||
}
|
||||
|
||||
predicate fileJarDependencyCount(File sourceFile, int total, string entity) {
|
||||
@@ -130,20 +140,22 @@ predicate fileJarDependencyCount(File sourceFile, int total, string entity) {
|
||||
jarStem = targetJar.getStem() and
|
||||
targetJar.(File).getExtension() = "jar" and
|
||||
jarStem != "rt"
|
||||
|
|
||||
|
|
||||
total = strictsum(RefType r, RefType dep, int num |
|
||||
r.getFile() = sourceFile and
|
||||
r.fromSource() and
|
||||
dep.getFile().getParentContainer*() = targetJar and
|
||||
numDepends(r, dep, num)
|
||||
r.getFile() = sourceFile and
|
||||
r.fromSource() and
|
||||
dep.getFile().getParentContainer*() = targetJar and
|
||||
numDepends(r, dep, num)
|
||||
|
|
||||
num) and
|
||||
num
|
||||
) and
|
||||
exists(string name, string version |
|
||||
if hasDashedVersion(jarStem, _, _) then
|
||||
hasDashedVersion(jarStem, name, version)
|
||||
else
|
||||
(name = jarStem and version = "unknown")
|
||||
|
|
||||
if hasDashedVersion(jarStem, _, _)
|
||||
then hasDashedVersion(jarStem, name, version)
|
||||
else (
|
||||
name = jarStem and version = "unknown"
|
||||
)
|
||||
|
|
||||
entity = "/" + sourceFile.getRelativePath() + "<|>" + name + "<|>" + version
|
||||
)
|
||||
)
|
||||
|
||||
@@ -9,7 +9,7 @@ import Javadoc
|
||||
/** A program element that has a name. */
|
||||
class Element extends @element, Top {
|
||||
/** Holds if this element has the specified `name`. */
|
||||
predicate hasName(string name) { hasName(this,name) }
|
||||
predicate hasName(string name) { hasName(this, name) }
|
||||
|
||||
/** Gets the name of this element. */
|
||||
string getName() { this.hasName(result) }
|
||||
@@ -34,9 +34,7 @@ class Element extends @element, Top {
|
||||
* Elements pertaining to source files may include generated elements
|
||||
* not visible in source code, such as implicit default constructors.
|
||||
*/
|
||||
predicate fromSource() {
|
||||
getCompilationUnit().getExtension() = "java"
|
||||
}
|
||||
predicate fromSource() { getCompilationUnit().getExtension() = "java" }
|
||||
|
||||
/** Gets the compilation unit that this element belongs to. */
|
||||
CompilationUnit getCompilationUnit() { result = getFile() }
|
||||
@@ -49,13 +47,27 @@ class Element extends @element, Top {
|
||||
* Holds if element `parent` is immediately above element `e` in the syntax tree.
|
||||
*/
|
||||
private predicate hasChildElement(Element parent, Element e) {
|
||||
cupackage(e,parent) or
|
||||
enclInReftype(e,parent) or
|
||||
(not(enclInReftype(e,_)) and e.(Class).getCompilationUnit() = parent) or
|
||||
(not(enclInReftype(e,_)) and e.(Interface).getCompilationUnit() = parent) or
|
||||
methods(e,_,_,_,parent,_) or
|
||||
constrs(e,_,_,_,parent,_) or
|
||||
params(e,_,_,parent,_) or
|
||||
fields(e,_,_,parent,_) or
|
||||
typeVars(e,_,_,_,parent)
|
||||
cupackage(e, parent)
|
||||
or
|
||||
enclInReftype(e, parent)
|
||||
or
|
||||
(
|
||||
not (enclInReftype(e, _)) and
|
||||
e.(Class).getCompilationUnit() = parent
|
||||
)
|
||||
or
|
||||
(
|
||||
not (enclInReftype(e, _)) and
|
||||
e.(Interface).getCompilationUnit() = parent
|
||||
)
|
||||
or
|
||||
methods(e, _, _, _, parent, _)
|
||||
or
|
||||
constrs(e, _, _, _, parent, _)
|
||||
or
|
||||
params(e, _, _, parent, _)
|
||||
or
|
||||
fields(e, _, _, parent, _)
|
||||
or
|
||||
typeVars(e, _, _, _, parent)
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ import Type
|
||||
*/
|
||||
class Exception extends Element, @exception {
|
||||
/** Gets the type of this exception. */
|
||||
RefType getType() { exceptions(this,result,_) }
|
||||
RefType getType() { exceptions(this, result, _) }
|
||||
|
||||
/** Gets the callable whose `throws` clause contains this exception. */
|
||||
Callable getCallable() { exceptions(this,_,result) }
|
||||
Callable getCallable() { exceptions(this, _, result) }
|
||||
|
||||
/** Gets the name of this exception, that is, the name of its type. */
|
||||
override string getName() { result = this.getType().getName() }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,17 +6,13 @@ import Type
|
||||
private import semmle.code.java.frameworks.JavaxAnnotations
|
||||
|
||||
/** A Java class that is detected as having been generated. */
|
||||
abstract class GeneratedClass extends Class {
|
||||
|
||||
}
|
||||
abstract class GeneratedClass extends Class { }
|
||||
|
||||
/**
|
||||
* A Java class annotated with a `@Generated` annotation.
|
||||
*/
|
||||
class AnnotatedGeneratedClass extends GeneratedClass {
|
||||
AnnotatedGeneratedClass() {
|
||||
this.getAnAnnotation() instanceof GeneratedAnnotation
|
||||
}
|
||||
AnnotatedGeneratedClass() { this.getAnAnnotation() instanceof GeneratedAnnotation }
|
||||
}
|
||||
|
||||
/** A Java class generated by an ANTLR scanner or parser class. */
|
||||
@@ -28,38 +24,36 @@ class AntlrGenerated extends GeneratedClass {
|
||||
t.hasQualifiedName("org.antlr.runtime", "Parser") or
|
||||
t.hasQualifiedName("org.antlr.runtime.tree", "TreeParser") or
|
||||
// ANTLR v2
|
||||
t.hasQualifiedName("antlr","TreeParser") or
|
||||
t.hasQualifiedName("antlr","CharScanner") or
|
||||
t.hasQualifiedName("antlr","LLkParser")
|
||||
t.hasQualifiedName("antlr", "TreeParser") or
|
||||
t.hasQualifiedName("antlr", "CharScanner") or
|
||||
t.hasQualifiedName("antlr", "LLkParser")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A generated callable is a callable declared in a generated class. */
|
||||
class GeneratedCallable extends Callable {
|
||||
GeneratedCallable() {
|
||||
this.getDeclaringType() instanceof GeneratedClass
|
||||
}
|
||||
GeneratedCallable() { this.getDeclaringType() instanceof GeneratedClass }
|
||||
}
|
||||
|
||||
/**
|
||||
* A file that is detected as having been generated.
|
||||
*/
|
||||
abstract class GeneratedFile extends File {
|
||||
}
|
||||
abstract class GeneratedFile extends File { }
|
||||
|
||||
/**
|
||||
* A file detected as generated based on commonly-used marker comments.
|
||||
*/
|
||||
library
|
||||
class MarkerCommentGeneratedFile extends GeneratedFile {
|
||||
library class MarkerCommentGeneratedFile extends GeneratedFile {
|
||||
MarkerCommentGeneratedFile() {
|
||||
exists(JavadocElement t | t.getFile() = this |
|
||||
exists(string msg | msg = t.getText() |
|
||||
msg.regexpMatch("(?i).*\\bGenerated By\\b.*\\bDo not edit\\b.*") or
|
||||
msg.regexpMatch("(?i).*\\bThis (file|class|interface|art[ei]fact) (was|is|(has been)) (?:auto[ -]?)?gener(e?)ated.*") or
|
||||
msg
|
||||
.regexpMatch("(?i).*\\bThis (file|class|interface|art[ei]fact) (was|is|(has been)) (?:auto[ -]?)?gener(e?)ated.*") or
|
||||
msg.regexpMatch("(?i).*\\bAny modifications to this file will be lost\\b.*") or
|
||||
msg.regexpMatch("(?i).*\\bThis (file|class|interface|art[ei]fact) (was|is) (?:mechanically|automatically) generated\\b.*") or
|
||||
msg
|
||||
.regexpMatch("(?i).*\\bThis (file|class|interface|art[ei]fact) (was|is) (?:mechanically|automatically) generated\\b.*") or
|
||||
msg.regexpMatch("(?i).*\\bThe following code was (?:auto[ -]?)?generated (?:by|from)\\b.*") or
|
||||
msg.regexpMatch("(?i).*\\bAutogenerated by Thrift.*") or
|
||||
msg.regexpMatch("(?i).*\\bGenerated By.*JavaCC.*") or
|
||||
|
||||
@@ -39,7 +39,7 @@ import Type
|
||||
* For example, `X` in `class X<T> { }`.
|
||||
*/
|
||||
class GenericType extends RefType {
|
||||
GenericType() { typeVars(_,_,_,_,this) }
|
||||
GenericType() { typeVars(_, _, _, _, this) }
|
||||
|
||||
/**
|
||||
* Gets a parameterization of this generic type, where each use of
|
||||
@@ -78,12 +78,10 @@ class GenericType extends RefType {
|
||||
}
|
||||
|
||||
/** A generic type that is a class. */
|
||||
class GenericClass extends GenericType, Class {
|
||||
}
|
||||
class GenericClass extends GenericType, Class { }
|
||||
|
||||
/** A generic type that is an interface. */
|
||||
class GenericInterface extends GenericType, Interface {
|
||||
}
|
||||
class GenericInterface extends GenericType, Interface { }
|
||||
|
||||
/**
|
||||
* A common super-class for Java types that may have a type bound.
|
||||
@@ -113,7 +111,8 @@ abstract class BoundedType extends RefType, @boundedtype {
|
||||
|
||||
/** Gets a transitive upper bound for this type that is not itself a bounded type. */
|
||||
RefType getAnUltimateUpperBoundType() {
|
||||
result = getUpperBoundType() and not result instanceof BoundedType or
|
||||
result = getUpperBoundType() and not result instanceof BoundedType
|
||||
or
|
||||
result = getUpperBoundType().(BoundedType).getAnUltimateUpperBoundType()
|
||||
}
|
||||
}
|
||||
@@ -126,10 +125,10 @@ abstract class BoundedType extends RefType, @boundedtype {
|
||||
*/
|
||||
class TypeVariable extends BoundedType, @typevariable {
|
||||
/** Gets the generic type that is parameterized by this type parameter, if any. */
|
||||
RefType getGenericType() { typeVars(this,_,_,_,result) }
|
||||
RefType getGenericType() { typeVars(this, _, _, _, result) }
|
||||
|
||||
/** Gets the generic callable that is parameterized by this type parameter, if any. */
|
||||
GenericCallable getGenericCallable() { typeVars(this,_,_,_,result) }
|
||||
GenericCallable getGenericCallable() { typeVars(this, _, _, _, result) }
|
||||
|
||||
/**
|
||||
* Gets an upper bound of this type parameter, or `Object`
|
||||
@@ -137,10 +136,9 @@ class TypeVariable extends BoundedType, @typevariable {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
override RefType getUpperBoundType() {
|
||||
if this.hasTypeBound() then
|
||||
result = this.getATypeBound().getType()
|
||||
else
|
||||
result instanceof TypeObject
|
||||
if this.hasTypeBound()
|
||||
then result = this.getATypeBound().getType()
|
||||
else result instanceof TypeObject
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,10 +147,9 @@ class TypeVariable extends BoundedType, @typevariable {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
override RefType getFirstUpperBoundType() {
|
||||
if this.hasTypeBound() then
|
||||
result = this.getFirstTypeBound().getType()
|
||||
else
|
||||
result instanceof TypeObject
|
||||
if this.hasTypeBound()
|
||||
then result = this.getFirstTypeBound().getType()
|
||||
else result instanceof TypeObject
|
||||
}
|
||||
|
||||
/** Gets the lexically enclosing package of this type parameter, if any. */
|
||||
@@ -167,19 +164,20 @@ class TypeVariable extends BoundedType, @typevariable {
|
||||
exists(GenericType gen, int pos |
|
||||
this = gen.getTypeParameter(pos) and
|
||||
typearg = gen.getAParameterizedType().getTypeArgument(pos)
|
||||
) or
|
||||
)
|
||||
or
|
||||
typearg = any(GenericCall call).getATypeArgument(this)
|
||||
|
|
||||
if typearg.(Wildcard).isUnconstrained() and this.hasTypeBound() then
|
||||
result.(Wildcard).getUpperBound().getType() = this.getUpperBoundType()
|
||||
else
|
||||
result = typearg
|
||||
|
|
||||
if typearg.(Wildcard).isUnconstrained() and this.hasTypeBound()
|
||||
then result.(Wildcard).getUpperBound().getType() = this.getUpperBoundType()
|
||||
else result = typearg
|
||||
)
|
||||
}
|
||||
|
||||
/** Finds a non-typevariable type that was transitively supplied for this parameter. */
|
||||
RefType getAnUltimatelySuppliedType() {
|
||||
result = getASuppliedType() and not result instanceof TypeVariable or
|
||||
result = getASuppliedType() and not result instanceof TypeVariable
|
||||
or
|
||||
result = getASuppliedType().(TypeVariable).getAnUltimatelySuppliedType()
|
||||
}
|
||||
}
|
||||
@@ -197,29 +195,22 @@ class TypeVariable extends BoundedType, @typevariable {
|
||||
*/
|
||||
class Wildcard extends BoundedType, @wildcard {
|
||||
/** Holds if this wildcard has an upper bound. */
|
||||
predicate hasUpperBound() {
|
||||
wildcards(this, _, 1)
|
||||
}
|
||||
predicate hasUpperBound() { wildcards(this, _, 1) }
|
||||
|
||||
/** Holds if this wildcard has a lower bound. */
|
||||
predicate hasLowerBound() {
|
||||
wildcards(this, _, 2)
|
||||
}
|
||||
predicate hasLowerBound() { wildcards(this, _, 2) }
|
||||
|
||||
/** Gets the upper bound for this wildcard, if any. */
|
||||
TypeBound getUpperBound() {
|
||||
this.hasUpperBound() and result = this.getATypeBound()
|
||||
}
|
||||
TypeBound getUpperBound() { this.hasUpperBound() and result = this.getATypeBound() }
|
||||
|
||||
/**
|
||||
* Gets an upper bound type of this wildcard, or `Object`
|
||||
* if no explicit type bound is present.
|
||||
*/
|
||||
override RefType getUpperBoundType() {
|
||||
if this.hasUpperBound() then
|
||||
result = this.getUpperBound().getType()
|
||||
else
|
||||
result instanceof TypeObject
|
||||
if this.hasUpperBound()
|
||||
then result = this.getUpperBound().getType()
|
||||
else result instanceof TypeObject
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,24 +218,19 @@ class Wildcard extends BoundedType, @wildcard {
|
||||
* if no explicit type bound is present.
|
||||
*/
|
||||
override RefType getFirstUpperBoundType() {
|
||||
if this.hasUpperBound() then
|
||||
result = this.getFirstTypeBound().getType()
|
||||
else
|
||||
result instanceof TypeObject
|
||||
if this.hasUpperBound()
|
||||
then result = this.getFirstTypeBound().getType()
|
||||
else result instanceof TypeObject
|
||||
}
|
||||
|
||||
/** Gets the lower bound of this wildcard, if any. */
|
||||
TypeBound getLowerBound() {
|
||||
this.hasLowerBound() and result = this.getATypeBound()
|
||||
}
|
||||
TypeBound getLowerBound() { this.hasLowerBound() and result = this.getATypeBound() }
|
||||
|
||||
/**
|
||||
* Gets the lower bound type for this wildcard,
|
||||
* if an explicit lower bound is present.
|
||||
*/
|
||||
Type getLowerBoundType() {
|
||||
result = this.getLowerBound().getType()
|
||||
}
|
||||
Type getLowerBoundType() { result = this.getLowerBound().getType() }
|
||||
|
||||
/**
|
||||
* Holds if this is the unconstrained wildcard `?`.
|
||||
@@ -273,7 +259,7 @@ class TypeBound extends @typebound {
|
||||
* For example, `T` is the type variable bounded by the
|
||||
* type `Number` in `T extends Number`.
|
||||
*/
|
||||
BoundedType getBoundedType() { typeBounds(this,_,_,result) }
|
||||
BoundedType getBoundedType() { typeBounds(this, _, _, result) }
|
||||
|
||||
/**
|
||||
* Gets the type of this bound.
|
||||
@@ -281,7 +267,7 @@ class TypeBound extends @typebound {
|
||||
* For example, `Number` is the type of the bound (of
|
||||
* the type variable `T`) in `T extends Number`.
|
||||
*/
|
||||
RefType getType() { typeBounds(this,result,_,_) }
|
||||
RefType getType() { typeBounds(this, result, _, _) }
|
||||
|
||||
/**
|
||||
* Gets the (zero-indexed) position of this bound.
|
||||
@@ -294,14 +280,13 @@ class TypeBound extends @typebound {
|
||||
* the position of the bound `Runnable` is 0 and
|
||||
* the position of the bound `Cloneable` is 1.
|
||||
*/
|
||||
int getPosition() { typeBounds(this,_,result,_) }
|
||||
int getPosition() { typeBounds(this, _, result, _) }
|
||||
|
||||
/** Gets a textual representation of this type bound. */
|
||||
string toString() { result = this.getType().getName() }
|
||||
}
|
||||
|
||||
// -------- Parameterizations of generic types --------
|
||||
|
||||
/**
|
||||
* A parameterized type is an instantiation of a generic type, where
|
||||
* each formal type variable has been replaced with a type argument.
|
||||
@@ -311,8 +296,8 @@ class TypeBound extends @typebound {
|
||||
*/
|
||||
class ParameterizedType extends RefType {
|
||||
ParameterizedType() {
|
||||
typeArgs(_,_,this) or
|
||||
typeVars(_,_,_,_,this)
|
||||
typeArgs(_, _, this) or
|
||||
typeVars(_, _, _, _, this)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -320,7 +305,7 @@ class ParameterizedType extends RefType {
|
||||
*
|
||||
* For example, the erasure of both `X<Number>` and `X<Integer>` is `X<T>`.
|
||||
*/
|
||||
override RefType getErasure() { erasure(this,result) or this.(GenericType) = result }
|
||||
override RefType getErasure() { erasure(this, result) or this.(GenericType) = result }
|
||||
|
||||
/**
|
||||
* Gets the generic type corresponding to this parameterized type.
|
||||
@@ -335,35 +320,33 @@ class ParameterizedType extends RefType {
|
||||
* For example, `Number` in `List<Number>`.
|
||||
*/
|
||||
RefType getATypeArgument() {
|
||||
typeArgs(result,_,this) or
|
||||
typeVars(result,_,_,_,this)
|
||||
typeArgs(result, _, this) or
|
||||
typeVars(result, _, _, _, this)
|
||||
}
|
||||
|
||||
/** Gets the type argument of this parameterized type at the specified position. */
|
||||
RefType getTypeArgument(int pos) {
|
||||
typeArgs(result,pos,this) or
|
||||
typeVars(result,_,pos,_,this)
|
||||
typeArgs(result, pos, this) or
|
||||
typeVars(result, _, pos, _, this)
|
||||
}
|
||||
|
||||
/** Gets the number of type arguments of this parameterized type. */
|
||||
int getNumberOfTypeArguments() {
|
||||
result = count(int pos |
|
||||
typeArgs(_,pos,this) or
|
||||
typeVars(_,_,pos,_,this)
|
||||
)
|
||||
typeArgs(_, pos, this) or
|
||||
typeVars(_, _, pos, _, this)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this type originates from source code. */
|
||||
override predicate fromSource() { typeVars(_,_,_,_,this) and RefType.super.fromSource() }
|
||||
override predicate fromSource() { typeVars(_, _, _, _, this) and RefType.super.fromSource() }
|
||||
}
|
||||
|
||||
/** A parameterized type that is a class. */
|
||||
class ParameterizedClass extends Class, ParameterizedType {
|
||||
}
|
||||
class ParameterizedClass extends Class, ParameterizedType { }
|
||||
|
||||
/** A parameterized type that is an interface. */
|
||||
class ParameterizedInterface extends Interface, ParameterizedType {
|
||||
}
|
||||
class ParameterizedInterface extends Interface, ParameterizedType { }
|
||||
|
||||
/**
|
||||
* The raw version of a generic type is the type that is formed by
|
||||
@@ -383,31 +366,28 @@ class RawType extends RefType {
|
||||
*
|
||||
* For example, the erasure of `List` is `List<E>`.
|
||||
*/
|
||||
override RefType getErasure() { erasure(this,result) }
|
||||
override RefType getErasure() { erasure(this, result) }
|
||||
|
||||
/** Holds if this type originates from source code. */
|
||||
override predicate fromSource() { not any() }
|
||||
}
|
||||
|
||||
/** A raw type that is a class. */
|
||||
class RawClass extends Class, RawType {
|
||||
}
|
||||
class RawClass extends Class, RawType { }
|
||||
|
||||
/** A raw type that is an interface. */
|
||||
class RawInterface extends Interface, RawType {
|
||||
}
|
||||
class RawInterface extends Interface, RawType { }
|
||||
|
||||
// -------- Generic callables --------
|
||||
|
||||
/**
|
||||
* A generic callable is a callable with a type parameter.
|
||||
*/
|
||||
class GenericCallable extends Callable {
|
||||
GenericCallable() {
|
||||
exists(Callable srcDecl |
|
||||
methods(this,_,_,_,_,srcDecl) or constrs(this,_,_,_,_,srcDecl)
|
||||
|
|
||||
typeVars(_,_,_,_,srcDecl)
|
||||
methods(this, _, _, _, _, srcDecl) or constrs(this, _, _, _, _, srcDecl)
|
||||
|
|
||||
typeVars(_, _, _, _, srcDecl)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -431,9 +411,7 @@ class GenericCallable extends Callable {
|
||||
* A call where the callee is a generic callable.
|
||||
*/
|
||||
class GenericCall extends Call {
|
||||
GenericCall() {
|
||||
this.getCallee() instanceof GenericCallable
|
||||
}
|
||||
GenericCall() { this.getCallee() instanceof GenericCallable }
|
||||
|
||||
private RefType getAnInferredTypeArgument(TypeVariable v) {
|
||||
typevarArg(this, v, result)
|
||||
@@ -454,7 +432,8 @@ class GenericCall extends Call {
|
||||
|
||||
/** Gets a type argument of the call for the given `TypeVariable`. */
|
||||
RefType getATypeArgument(TypeVariable v) {
|
||||
result = getAnExplicitTypeArgument(v) or
|
||||
result = getAnExplicitTypeArgument(v)
|
||||
or
|
||||
not exists(getAnExplicitTypeArgument(v)) and
|
||||
result = getAnInferredTypeArgument(v)
|
||||
}
|
||||
@@ -465,36 +444,38 @@ private predicate typevarArg(Call call, TypeVariable v, RefType typearg) {
|
||||
exists(GenericCallable gen |
|
||||
gen = call.getCallee() and
|
||||
v = gen.getATypeParameter()
|
||||
|
|
||||
hasSubstitution(gen.getReturnType(), call.(Expr).getType(), v, typearg)
|
||||
or
|
||||
exists(int n | hasSubtypedSubstitution(gen.getParameterType(n), call.getArgument(n).getType(), v, typearg))
|
||||
|
|
||||
hasSubstitution(gen.getReturnType(), call.(Expr).getType(), v, typearg) or
|
||||
exists(int n |
|
||||
hasSubtypedSubstitution(gen.getParameterType(n), call.getArgument(n).getType(), v, typearg)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The reflexive transitive closure of `RefType.extendsOrImplements` including reflexivity on `Type`s.
|
||||
*/
|
||||
private Type getShallowSupertype(Type t) {
|
||||
result = t or t.(RefType).extendsOrImplements+(result)
|
||||
}
|
||||
private Type getShallowSupertype(Type t) { result = t or t.(RefType).extendsOrImplements+(result) }
|
||||
|
||||
/**
|
||||
* Manual magic sets optimization for the "inputs" of `hasSubstitution` and
|
||||
* `hasParameterSubstitution`.
|
||||
*/
|
||||
private predicate unificationTargets(RefType t1, Type t2) {
|
||||
exists(GenericCallable gen, Call call |
|
||||
gen = call.getCallee()
|
||||
|
|
||||
t1 = gen.getReturnType() and t2 = call.(Expr).getType() or
|
||||
exists(int n | t1 = gen.getParameterType(n) and t2 = getShallowSupertype(call.getArgument(n).getType()))
|
||||
) or
|
||||
exists(GenericCallable gen, Call call | gen = call.getCallee() |
|
||||
t1 = gen.getReturnType() and t2 = call.(Expr).getType()
|
||||
or
|
||||
exists(int n |
|
||||
t1 = gen.getParameterType(n) and t2 = getShallowSupertype(call.getArgument(n).getType())
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Array a1, Array a2 |
|
||||
unificationTargets(a1, a2) and
|
||||
t1 = a1.getComponentType() and
|
||||
t2 = a2.getComponentType()
|
||||
) or
|
||||
)
|
||||
or
|
||||
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
|
||||
unificationTargets(pt1, pt2) and
|
||||
t1 = pt1.getTypeArgument(pos) and
|
||||
@@ -526,17 +507,21 @@ private predicate hasSubtypedSubstitution(RefType t1, Type t2, TypeVariable v, R
|
||||
private predicate hasSubstitution(RefType t1, Type t2, TypeVariable v, RefType subst) {
|
||||
unificationTargets(t1, t2) and
|
||||
(
|
||||
t1 = v and (t2 = subst or t2.(PrimitiveType).getBoxedType() = subst) or
|
||||
hasSubstitution(t1.(Array).getComponentType(), t2.(Array).getComponentType(), v, subst) or
|
||||
t1 = v and
|
||||
(t2 = subst or t2.(PrimitiveType).getBoxedType() = subst)
|
||||
or
|
||||
hasSubstitution(t1.(Array).getComponentType(), t2.(Array).getComponentType(), v, subst)
|
||||
or
|
||||
exists(GenericType g | hasParameterSubstitution(g, t1, g, t2, v, subst))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasParameterSubstitution(GenericType g1, ParameterizedType pt1, GenericType g2, ParameterizedType pt2, TypeVariable v, RefType subst) {
|
||||
private predicate hasParameterSubstitution(
|
||||
GenericType g1, ParameterizedType pt1, GenericType g2, ParameterizedType pt2, TypeVariable v,
|
||||
RefType subst
|
||||
) {
|
||||
unificationTargets(pt1, pt2) and
|
||||
exists(int pos |
|
||||
hasSubstitution(pt1.getTypeArgument(pos), pt2.getTypeArgument(pos), v, subst)
|
||||
) and
|
||||
exists(int pos | hasSubstitution(pt1.getTypeArgument(pos), pt2.getTypeArgument(pos), v, subst)) and
|
||||
g1 = pt1.getGenericType() and
|
||||
g2 = pt2.getGenericType()
|
||||
}
|
||||
@@ -547,7 +532,10 @@ private predicate hasParameterSubstitution(GenericType g1, ParameterizedType pt1
|
||||
* For example, `<T> C(T t) { }` is a generic constructor for type `C`.
|
||||
*/
|
||||
class GenericConstructor extends Constructor, GenericCallable {
|
||||
override GenericConstructor getSourceDeclaration() { result = Constructor.super.getSourceDeclaration() }
|
||||
override GenericConstructor getSourceDeclaration() {
|
||||
result = Constructor.super.getSourceDeclaration()
|
||||
}
|
||||
|
||||
override ConstructorCall getAReference() { result = Constructor.super.getAReference() }
|
||||
}
|
||||
|
||||
@@ -561,5 +549,4 @@ class GenericMethod extends Method, GenericCallable {
|
||||
}
|
||||
|
||||
/** A generic method that is the same as its source declaration. */
|
||||
class GenericSrcMethod extends SrcMethod, GenericMethod {
|
||||
}
|
||||
class GenericSrcMethod extends SrcMethod, GenericMethod { }
|
||||
|
||||
@@ -22,10 +22,10 @@ class Import extends Element, @import {
|
||||
* For example, `import java.util.Set;`.
|
||||
*/
|
||||
class ImportType extends Import {
|
||||
ImportType() { imports(this,_,_,1) }
|
||||
ImportType() { imports(this, _, _, 1) }
|
||||
|
||||
/** Gets the imported type. */
|
||||
RefType getImportedType() { imports(this,result,_,_) }
|
||||
RefType getImportedType() { imports(this, result, _, _) }
|
||||
|
||||
override string toString() { result = "import " + this.getImportedType().toString() }
|
||||
}
|
||||
@@ -39,17 +39,15 @@ class ImportType extends Import {
|
||||
* `java.util.Map`.
|
||||
*/
|
||||
class ImportOnDemandFromType extends Import {
|
||||
ImportOnDemandFromType() { imports(this,_,_,2) }
|
||||
ImportOnDemandFromType() { imports(this, _, _, 2) }
|
||||
|
||||
/** Gets the type from which accessible nested types are imported. */
|
||||
RefType getTypeHoldingImport() { imports(this,result,_,_) }
|
||||
RefType getTypeHoldingImport() { imports(this, result, _, _) }
|
||||
|
||||
/** Gets an imported type. */
|
||||
NestedType getAnImport() { result.getEnclosingType() = this.getTypeHoldingImport() }
|
||||
|
||||
override string toString() {
|
||||
result = "import " + this.getTypeHoldingImport().toString() + ".*"
|
||||
}
|
||||
override string toString() { result = "import " + this.getTypeHoldingImport().toString() + ".*" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,10 +57,10 @@ class ImportOnDemandFromType extends Import {
|
||||
* For example, `import java.util.*;`.
|
||||
*/
|
||||
class ImportOnDemandFromPackage extends Import {
|
||||
ImportOnDemandFromPackage() { imports(this,_,_,3) }
|
||||
ImportOnDemandFromPackage() { imports(this, _, _, 3) }
|
||||
|
||||
/** Gets the package from which accessible types are imported. */
|
||||
Package getPackageHoldingImport() { imports(this,result,_,_) }
|
||||
Package getPackageHoldingImport() { imports(this, result, _, _) }
|
||||
|
||||
/** Gets an imported type. */
|
||||
RefType getAnImport() { result.getPackage() = this.getPackageHoldingImport() }
|
||||
@@ -80,10 +78,10 @@ class ImportOnDemandFromPackage extends Import {
|
||||
* For example, `import static java.lang.System.*;`.
|
||||
*/
|
||||
class ImportStaticOnDemand extends Import {
|
||||
ImportStaticOnDemand() { imports(this,_,_,4) }
|
||||
ImportStaticOnDemand() { imports(this, _, _, 4) }
|
||||
|
||||
/** Gets the type from which accessible static members are imported. */
|
||||
RefType getTypeHoldingImport() { imports(this,result,_,_) }
|
||||
RefType getTypeHoldingImport() { imports(this, result, _, _) }
|
||||
|
||||
/** Gets an imported type. */
|
||||
NestedType getATypeImport() { result.getEnclosingType() = this.getTypeHoldingImport() }
|
||||
@@ -109,18 +107,19 @@ class ImportStaticOnDemand extends Import {
|
||||
* class `java.util.Collections`.
|
||||
*/
|
||||
class ImportStaticTypeMember extends Import {
|
||||
ImportStaticTypeMember() { imports(this,_,_,5) }
|
||||
ImportStaticTypeMember() { imports(this, _, _, 5) }
|
||||
|
||||
/** Gets the type from which static members with a given name are imported. */
|
||||
RefType getTypeHoldingImport() { imports(this,result,_,_) }
|
||||
RefType getTypeHoldingImport() { imports(this, result, _, _) }
|
||||
|
||||
/** Gets the name of the imported member(s). */
|
||||
override string getName() { imports(this,_,result,_) }
|
||||
override string getName() { imports(this, _, result, _) }
|
||||
|
||||
/** Gets an imported member. */
|
||||
Member getAMemberImport() {
|
||||
this.getTypeHoldingImport().getAMember() = result and
|
||||
result.getName() = this.getName() and result.isStatic()
|
||||
result.getName() = this.getName() and
|
||||
result.isStatic()
|
||||
}
|
||||
|
||||
/** Gets an imported type. */
|
||||
@@ -134,7 +133,6 @@ class ImportStaticTypeMember extends Import {
|
||||
|
||||
/** Gets a printable representation of this import declaration. */
|
||||
override string toString() {
|
||||
result = "import static " + this.getTypeHoldingImport().toString()
|
||||
+ "." + this.getName()
|
||||
result = "import static " + this.getTypeHoldingImport().toString() + "." + this.getName()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,61 +7,49 @@ import Type
|
||||
/** An entity bean. */
|
||||
class EntityBean extends Class {
|
||||
EntityBean() {
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb","EntityBean") |
|
||||
this.hasSupertype+(i)
|
||||
)
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb", "EntityBean") | this.hasSupertype+(i))
|
||||
}
|
||||
}
|
||||
|
||||
/** An enterprise bean. */
|
||||
class EnterpriseBean extends RefType {
|
||||
EnterpriseBean() {
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb","EnterpriseBean") |
|
||||
this.hasSupertype+(i)
|
||||
)
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb", "EnterpriseBean") | this.hasSupertype+(i))
|
||||
}
|
||||
}
|
||||
|
||||
/** A local EJB home interface. */
|
||||
class LocalEJBHomeInterface extends Interface {
|
||||
LocalEJBHomeInterface() {
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb","EJBLocalHome") |
|
||||
this.hasSupertype+(i)
|
||||
)
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb", "EJBLocalHome") | this.hasSupertype+(i))
|
||||
}
|
||||
}
|
||||
|
||||
/** A remote EJB home interface. */
|
||||
class RemoteEJBHomeInterface extends Interface {
|
||||
RemoteEJBHomeInterface() {
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb","EJBHome") |
|
||||
this.hasSupertype+(i)
|
||||
)
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb", "EJBHome") | this.hasSupertype+(i))
|
||||
}
|
||||
}
|
||||
|
||||
/** A local EJB interface. */
|
||||
class LocalEJBInterface extends Interface {
|
||||
LocalEJBInterface() {
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb","EJBLocalObject") |
|
||||
this.hasSupertype+(i)
|
||||
)
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb", "EJBLocalObject") | this.hasSupertype+(i))
|
||||
}
|
||||
}
|
||||
|
||||
/** A remote EJB interface. */
|
||||
class RemoteEJBInterface extends Interface {
|
||||
RemoteEJBInterface() {
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb","EJBObject") |
|
||||
this.hasSupertype+(i)
|
||||
)
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb", "EJBObject") | this.hasSupertype+(i))
|
||||
}
|
||||
}
|
||||
|
||||
/** A message bean. */
|
||||
class MessageBean extends Class {
|
||||
MessageBean() {
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb","MessageDrivenBean") |
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb", "MessageDrivenBean") |
|
||||
this.hasSupertype+(i)
|
||||
)
|
||||
}
|
||||
@@ -70,8 +58,6 @@ class MessageBean extends Class {
|
||||
/** A session bean. */
|
||||
class SessionBean extends Class {
|
||||
SessionBean() {
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb","SessionBean") |
|
||||
this.hasSupertype+(i)
|
||||
)
|
||||
exists(Interface i | i.hasQualifiedName("javax.ejb", "SessionBean") | this.hasSupertype+(i))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,104 +5,67 @@
|
||||
import Member
|
||||
|
||||
// --- Standard types ---
|
||||
|
||||
/** The class `java.lang.Object`. */
|
||||
class TypeObject extends Class {
|
||||
pragma[noinline]
|
||||
TypeObject() {
|
||||
this.hasQualifiedName("java.lang", "Object")
|
||||
}
|
||||
TypeObject() { this.hasQualifiedName("java.lang", "Object") }
|
||||
}
|
||||
|
||||
/** The interface `java.lang.Cloneable`. */
|
||||
class TypeCloneable extends Interface {
|
||||
TypeCloneable() {
|
||||
this.hasQualifiedName("java.lang", "Cloneable")
|
||||
}
|
||||
TypeCloneable() { this.hasQualifiedName("java.lang", "Cloneable") }
|
||||
}
|
||||
|
||||
/** The class `java.lang.ProcessBuilder`. */
|
||||
class TypeProcessBuilder extends Class {
|
||||
TypeProcessBuilder() {
|
||||
hasQualifiedName("java.lang", "ProcessBuilder")
|
||||
}
|
||||
TypeProcessBuilder() { hasQualifiedName("java.lang", "ProcessBuilder") }
|
||||
}
|
||||
|
||||
/** The class `java.lang.Runtime`. */
|
||||
class TypeRuntime extends Class {
|
||||
TypeRuntime() {
|
||||
hasQualifiedName("java.lang", "Runtime")
|
||||
}
|
||||
}
|
||||
class TypeRuntime extends Class { TypeRuntime() { hasQualifiedName("java.lang", "Runtime") } }
|
||||
|
||||
/** The class `java.lang.String`. */
|
||||
class TypeString extends Class {
|
||||
TypeString() {
|
||||
this.hasQualifiedName("java.lang", "String")
|
||||
}
|
||||
}
|
||||
class TypeString extends Class { TypeString() { this.hasQualifiedName("java.lang", "String") } }
|
||||
|
||||
/** The `length()` method of the class `java.lang.String`. */
|
||||
class StringLengthMethod extends Method {
|
||||
StringLengthMethod() {
|
||||
this.hasName("length") and this.getDeclaringType() instanceof TypeString
|
||||
}
|
||||
StringLengthMethod() { this.hasName("length") and this.getDeclaringType() instanceof TypeString }
|
||||
}
|
||||
|
||||
/** The class `java.lang.StringBuffer`. */
|
||||
class TypeStringBuffer extends Class {
|
||||
TypeStringBuffer() {
|
||||
this.hasQualifiedName("java.lang", "StringBuffer")
|
||||
}
|
||||
TypeStringBuffer() { this.hasQualifiedName("java.lang", "StringBuffer") }
|
||||
}
|
||||
|
||||
/** The class `java.lang.StringBuilder`. */
|
||||
class TypeStringBuilder extends Class {
|
||||
TypeStringBuilder() {
|
||||
this.hasQualifiedName("java.lang", "StringBuilder")
|
||||
}
|
||||
TypeStringBuilder() { this.hasQualifiedName("java.lang", "StringBuilder") }
|
||||
}
|
||||
|
||||
/** The class `java.lang.System`. */
|
||||
class TypeSystem extends Class {
|
||||
TypeSystem() {
|
||||
this.hasQualifiedName("java.lang", "System")
|
||||
}
|
||||
}
|
||||
class TypeSystem extends Class { TypeSystem() { this.hasQualifiedName("java.lang", "System") } }
|
||||
|
||||
/** The class `java.lang.Throwable`. */
|
||||
class TypeThrowable extends Class {
|
||||
TypeThrowable() {
|
||||
this.hasQualifiedName("java.lang", "Throwable")
|
||||
}
|
||||
TypeThrowable() { this.hasQualifiedName("java.lang", "Throwable") }
|
||||
}
|
||||
|
||||
/** The class `java.lang.Exception`. */
|
||||
class TypeException extends Class {
|
||||
TypeException() {
|
||||
this.hasQualifiedName("java.lang", "Exception")
|
||||
}
|
||||
TypeException() { this.hasQualifiedName("java.lang", "Exception") }
|
||||
}
|
||||
|
||||
/** The class `java.lang.Error`. */
|
||||
class TypeError extends Class {
|
||||
TypeError() {
|
||||
this.hasQualifiedName("java.lang", "Error")
|
||||
}
|
||||
}
|
||||
class TypeError extends Class { TypeError() { this.hasQualifiedName("java.lang", "Error") } }
|
||||
|
||||
/** The class `java.lang.RuntimeException`. */
|
||||
class TypeRuntimeException extends Class {
|
||||
TypeRuntimeException() {
|
||||
this.hasQualifiedName("java.lang", "RuntimeException")
|
||||
}
|
||||
TypeRuntimeException() { this.hasQualifiedName("java.lang", "RuntimeException") }
|
||||
}
|
||||
|
||||
/** The class `java.lang.ClassCastException`. */
|
||||
class TypeClassCastException extends Class {
|
||||
TypeClassCastException() {
|
||||
this.hasQualifiedName("java.lang", "ClassCastException")
|
||||
}
|
||||
TypeClassCastException() { this.hasQualifiedName("java.lang", "ClassCastException") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,9 +74,7 @@ class TypeClassCastException extends Class {
|
||||
* This includes the generic source declaration, any parameterized instances and the raw type.
|
||||
*/
|
||||
class TypeClass extends Class {
|
||||
TypeClass() {
|
||||
this.getSourceDeclaration().hasQualifiedName("java.lang", "Class")
|
||||
}
|
||||
TypeClass() { this.getSourceDeclaration().hasQualifiedName("java.lang", "Class") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,11 +89,7 @@ class TypeConstructor extends Class {
|
||||
}
|
||||
|
||||
/** The class `java.lang.Math`. */
|
||||
class TypeMath extends Class {
|
||||
TypeMath() {
|
||||
this.hasQualifiedName("java.lang", "Math")
|
||||
}
|
||||
}
|
||||
class TypeMath extends Class { TypeMath() { this.hasQualifiedName("java.lang", "Math") } }
|
||||
|
||||
/** A numeric type, including both primitive and boxed types. */
|
||||
class NumericType extends Type {
|
||||
@@ -140,7 +97,7 @@ class NumericType extends Type {
|
||||
exists(string name |
|
||||
name = this.(PrimitiveType).getName() or
|
||||
name = this.(BoxedType).getPrimitiveType().getName()
|
||||
|
|
||||
|
|
||||
name.regexpMatch("byte|short|int|long|double|float")
|
||||
)
|
||||
}
|
||||
@@ -158,58 +115,36 @@ class ImmutableType extends Type {
|
||||
}
|
||||
|
||||
// --- Java IO ---
|
||||
|
||||
/** The interface `java.io.Serializable`. */
|
||||
class TypeSerializable extends Interface {
|
||||
TypeSerializable() {
|
||||
hasQualifiedName("java.io", "Serializable")
|
||||
}
|
||||
TypeSerializable() { hasQualifiedName("java.io", "Serializable") }
|
||||
}
|
||||
|
||||
/** The interface `java.io.ObjectOutput`. */
|
||||
class TypeObjectOutput extends Interface {
|
||||
TypeObjectOutput() {
|
||||
hasQualifiedName("java.io", "ObjectOutput")
|
||||
}
|
||||
TypeObjectOutput() { hasQualifiedName("java.io", "ObjectOutput") }
|
||||
}
|
||||
|
||||
/** The type `java.io.ObjectOutputStream`. */
|
||||
class TypeObjectOutputStream extends RefType {
|
||||
TypeObjectOutputStream() {
|
||||
hasQualifiedName("java.io", "ObjectOutputStream")
|
||||
}
|
||||
TypeObjectOutputStream() { hasQualifiedName("java.io", "ObjectOutputStream") }
|
||||
}
|
||||
|
||||
/** The class `java.nio.file.Paths`. */
|
||||
class TypePaths extends Class {
|
||||
TypePaths() {
|
||||
this.hasQualifiedName("java.nio.file", "Paths")
|
||||
}
|
||||
}
|
||||
class TypePaths extends Class { TypePaths() { this.hasQualifiedName("java.nio.file", "Paths") } }
|
||||
|
||||
/** The class `java.nio.file.Path`. */
|
||||
class TypePath extends Class {
|
||||
TypePath() {
|
||||
this.hasQualifiedName("java.nio.file", "Path")
|
||||
}
|
||||
}
|
||||
class TypePath extends Class { TypePath() { this.hasQualifiedName("java.nio.file", "Path") } }
|
||||
|
||||
/** The class `java.nio.file.FileSystem`. */
|
||||
class TypeFileSystem extends Class {
|
||||
TypeFileSystem() {
|
||||
this.hasQualifiedName("java.nio.file", "FileSystem")
|
||||
}
|
||||
TypeFileSystem() { this.hasQualifiedName("java.nio.file", "FileSystem") }
|
||||
}
|
||||
|
||||
/** The class `java.io.File`. */
|
||||
class TypeFile extends Class {
|
||||
TypeFile() {
|
||||
this.hasQualifiedName("java.io", "File")
|
||||
}
|
||||
}
|
||||
class TypeFile extends Class { TypeFile() { this.hasQualifiedName("java.io", "File") } }
|
||||
|
||||
// --- Standard methods ---
|
||||
|
||||
/**
|
||||
* Any of the methods named `command` on class `java.lang.ProcessBuilder`.
|
||||
*/
|
||||
@@ -315,7 +250,6 @@ class MethodAbs extends Method {
|
||||
}
|
||||
|
||||
// --- Standard fields ---
|
||||
|
||||
/** The field `System.in`. */
|
||||
class SystemIn extends Field {
|
||||
SystemIn() {
|
||||
@@ -341,7 +275,6 @@ class SystemErr extends Field {
|
||||
}
|
||||
|
||||
// --- User-defined methods with a particular meaning ---
|
||||
|
||||
/** A method with the same signature as `java.lang.Object.equals`. */
|
||||
class EqualsMethod extends Method {
|
||||
EqualsMethod() {
|
||||
@@ -351,9 +284,7 @@ class EqualsMethod extends Method {
|
||||
}
|
||||
|
||||
/** Gets the single parameter of this method. */
|
||||
Parameter getParameter() {
|
||||
result = this.getAParameter()
|
||||
}
|
||||
Parameter getParameter() { result = this.getAParameter() }
|
||||
}
|
||||
|
||||
/** A method with the same signature as `java.lang.Object.hashCode`. */
|
||||
@@ -399,8 +330,7 @@ class PreMainMethod extends Method {
|
||||
this.getReturnType().hasName("void") and
|
||||
this.getNumberOfParameters() < 3 and
|
||||
this.getParameter(0).getType() instanceof TypeString and
|
||||
(exists(this.getParameter(1)) implies
|
||||
this.getParameter(1).getType().hasName("Instrumentation"))
|
||||
(exists(this.getParameter(1)) implies this.getParameter(1).getType().hasName("Instrumentation"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,9 +344,7 @@ class ArrayLengthField extends Field {
|
||||
|
||||
/** A (reflexive, transitive) subtype of `java.lang.Throwable`. */
|
||||
class ThrowableType extends RefType {
|
||||
ThrowableType() {
|
||||
exists(TypeThrowable throwable | hasSubtype*(throwable, this))
|
||||
}
|
||||
ThrowableType() { exists(TypeThrowable throwable | hasSubtype*(throwable, this)) }
|
||||
}
|
||||
|
||||
/** An unchecked exception. That is, a (reflexive, transitive) subtype of `java.lang.Error` or `java.lang.RuntimeException`. */
|
||||
|
||||
@@ -6,23 +6,17 @@ import java
|
||||
|
||||
/** A `@Deprecated` annotation. */
|
||||
class DeprecatedAnnotation extends Annotation {
|
||||
DeprecatedAnnotation() {
|
||||
this.getType().hasQualifiedName("java.lang", "Deprecated")
|
||||
}
|
||||
DeprecatedAnnotation() { this.getType().hasQualifiedName("java.lang", "Deprecated") }
|
||||
}
|
||||
|
||||
/** An `@Override` annotation. */
|
||||
class OverrideAnnotation extends Annotation {
|
||||
OverrideAnnotation() {
|
||||
this.getType().hasQualifiedName("java.lang", "Override")
|
||||
}
|
||||
OverrideAnnotation() { this.getType().hasQualifiedName("java.lang", "Override") }
|
||||
}
|
||||
|
||||
/** A `@SuppressWarnings` annotation. */
|
||||
class SuppressWarningsAnnotation extends Annotation {
|
||||
SuppressWarningsAnnotation() {
|
||||
this.getType().hasQualifiedName("java.lang", "SuppressWarnings")
|
||||
}
|
||||
SuppressWarningsAnnotation() { this.getType().hasQualifiedName("java.lang", "SuppressWarnings") }
|
||||
|
||||
/** Gets the name of a warning suppressed by this annotation. */
|
||||
string getASuppressedWarning() {
|
||||
@@ -33,9 +27,7 @@ class SuppressWarningsAnnotation extends Annotation {
|
||||
|
||||
/** A `@Target` annotation. */
|
||||
class TargetAnnotation extends Annotation {
|
||||
TargetAnnotation() {
|
||||
this.getType().hasQualifiedName("java.lang.annotation", "Target")
|
||||
}
|
||||
TargetAnnotation() { this.getType().hasQualifiedName("java.lang.annotation", "Target") }
|
||||
|
||||
/**
|
||||
* Gets a target expression within this annotation.
|
||||
@@ -61,16 +53,15 @@ class TargetAnnotation extends Annotation {
|
||||
exists(EnumConstant ec |
|
||||
ec = this.getATargetExpression().(VarAccess).getVariable() and
|
||||
ec.getDeclaringType().hasQualifiedName("java.lang.annotation", "ElementType")
|
||||
|
|
||||
result = ec.getName())
|
||||
|
|
||||
result = ec.getName()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A `@Retention` annotation. */
|
||||
class RetentionAnnotation extends Annotation {
|
||||
RetentionAnnotation() {
|
||||
this.getType().hasQualifiedName("java.lang.annotation", "Retention")
|
||||
}
|
||||
RetentionAnnotation() { this.getType().hasQualifiedName("java.lang.annotation", "Retention") }
|
||||
|
||||
/**
|
||||
* Gets the retention policy expression within this annotation.
|
||||
@@ -78,9 +69,7 @@ class RetentionAnnotation extends Annotation {
|
||||
* For example, the field access `RetentionPolicy.RUNTIME` is the
|
||||
* retention policy expression in `@Retention(RetentionPolicy.RUNTIME)`.
|
||||
*/
|
||||
Expr getRetentionPolicyExpression() {
|
||||
result = this.getValue("value")
|
||||
}
|
||||
Expr getRetentionPolicyExpression() { result = this.getValue("value") }
|
||||
|
||||
/**
|
||||
* Gets the name of the retention policy of this annotation.
|
||||
@@ -92,8 +81,9 @@ class RetentionAnnotation extends Annotation {
|
||||
exists(EnumConstant ec |
|
||||
ec = this.getRetentionPolicyExpression().(VarAccess).getVariable() and
|
||||
ec.getDeclaringType().hasQualifiedName("java.lang.annotation", "RetentionPolicy")
|
||||
|
|
||||
result = ec.getName())
|
||||
|
|
||||
result = ec.getName()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +112,7 @@ class ReflectiveAccessAnnotation extends Annotation {
|
||||
* Any annotation that is not a subclass of `NonReflectiveAnnotation` is assumed to
|
||||
* allow for reflective access.
|
||||
*/
|
||||
abstract class NonReflectiveAnnotation extends Annotation {}
|
||||
abstract class NonReflectiveAnnotation extends Annotation { }
|
||||
|
||||
library class StandardNonReflectiveAnnotation extends NonReflectiveAnnotation {
|
||||
StandardNonReflectiveAnnotation() {
|
||||
|
||||
@@ -5,15 +5,10 @@
|
||||
import Type
|
||||
|
||||
/** A managed bean. */
|
||||
abstract class ManagedBean extends Interface {
|
||||
}
|
||||
abstract class ManagedBean extends Interface { }
|
||||
|
||||
/** An `MBean`. */
|
||||
class MBean extends ManagedBean {
|
||||
MBean() {
|
||||
this.getQualifiedName().matches("%MBean%")
|
||||
}
|
||||
}
|
||||
class MBean extends ManagedBean { MBean() { this.getQualifiedName().matches("%MBean%") } }
|
||||
|
||||
/** An `MXBean`. */
|
||||
class MXBean extends ManagedBean {
|
||||
@@ -30,26 +25,20 @@ class MXBean extends ManagedBean {
|
||||
class RegisteredManagedBeanImpl extends Class {
|
||||
RegisteredManagedBeanImpl() {
|
||||
getAnAncestor() instanceof ManagedBean and
|
||||
exists(JMXRegistrationCall registerCall |
|
||||
registerCall.getObjectArgument().getType() = this
|
||||
)
|
||||
exists(JMXRegistrationCall registerCall | registerCall.getObjectArgument().getType() = this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a managed bean that this registered bean class implements.
|
||||
*/
|
||||
ManagedBean getAnImplementedManagedBean() {
|
||||
result = getAnAncestor()
|
||||
}
|
||||
ManagedBean getAnImplementedManagedBean() { result = getAnAncestor() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call that registers an object with the `MBeanServer`, directly or indirectly.
|
||||
*/
|
||||
class JMXRegistrationCall extends MethodAccess {
|
||||
JMXRegistrationCall() {
|
||||
getCallee() instanceof JMXRegistrationMethod
|
||||
}
|
||||
JMXRegistrationCall() { getCallee() instanceof JMXRegistrationMethod }
|
||||
|
||||
/**
|
||||
* Gets the argument that represents the object in the registration call.
|
||||
@@ -71,16 +60,19 @@ class JMXRegistrationMethod extends Method {
|
||||
// A direct registration with the `MBeanServer`.
|
||||
getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and
|
||||
getName() = "registerMBean"
|
||||
) or
|
||||
)
|
||||
or
|
||||
/*
|
||||
* The `MBeanServer` is often wrapped by an application specific management class, so identify
|
||||
* methods that wrap a call to another `JMXRegistrationMethod`.
|
||||
*/
|
||||
|
||||
exists(JMXRegistrationCall c |
|
||||
/*
|
||||
* This must be a call to another JMX registration method, where the object argument is an access
|
||||
* of one of the parameters of this method.
|
||||
*/
|
||||
|
||||
c.getObjectArgument().(VarAccess).getVariable() = getAParameter()
|
||||
)
|
||||
}
|
||||
@@ -94,7 +86,8 @@ class JMXRegistrationMethod extends Method {
|
||||
getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and
|
||||
getName() = "registerMBean" and
|
||||
result = 0
|
||||
) or
|
||||
)
|
||||
or
|
||||
// Identify the position in this method where the object parameter should be passed.
|
||||
exists(JMXRegistrationCall c |
|
||||
c.getObjectArgument().(VarAccess).getVariable() = getParameter(result)
|
||||
|
||||
@@ -11,64 +11,43 @@ class JavadocParent extends @javadocParent, Top {
|
||||
JavadocElement getAChild() { result.getParent() = this }
|
||||
|
||||
/** Gets the child documentation element at the specified (zero-based) position. */
|
||||
JavadocElement getChild(int index) {
|
||||
result = this.getAChild() and result.getIndex() = index
|
||||
}
|
||||
JavadocElement getChild(int index) { result = this.getAChild() and result.getIndex() = index }
|
||||
|
||||
/** Gets the number of documentation elements attached to this parent. */
|
||||
int getNumChild() {
|
||||
result = count(getAChild())
|
||||
}
|
||||
int getNumChild() { result = count(getAChild()) }
|
||||
|
||||
/** Gets a documentation element with the specified Javadoc tag name. */
|
||||
JavadocTag getATag(string name) {
|
||||
result = this.getAChild() and result.getTagName() = name
|
||||
}
|
||||
JavadocTag getATag(string name) { result = this.getAChild() and result.getTagName() = name }
|
||||
|
||||
/*abstract*/ override string toString() { result = "Javadoc" }
|
||||
}
|
||||
|
||||
/** A Javadoc comment. */
|
||||
class Javadoc extends JavadocParent, @javadoc {
|
||||
|
||||
/** Gets the number of lines in this Javadoc comment. */
|
||||
int getNumberOfLines() {
|
||||
result = this.getLocation().getNumberOfCommentLines()
|
||||
}
|
||||
int getNumberOfLines() { result = this.getLocation().getNumberOfCommentLines() }
|
||||
|
||||
/** Gets the value of the `@version` tag, if any. */
|
||||
string getVersion() {
|
||||
result = this.getATag("@version").getChild(0).toString()
|
||||
}
|
||||
string getVersion() { result = this.getATag("@version").getChild(0).toString() }
|
||||
|
||||
/** Gets the value of the `@author` tag, if any. */
|
||||
string getAuthor() {
|
||||
result = this.getATag("@author").getChild(0).toString()
|
||||
}
|
||||
string getAuthor() { result = this.getATag("@author").getChild(0).toString() }
|
||||
|
||||
override string toString() {
|
||||
result = toStringPrefix() + getChild(0) + toStringPostfix()
|
||||
}
|
||||
override string toString() { result = toStringPrefix() + getChild(0) + toStringPostfix() }
|
||||
|
||||
private string toStringPrefix() {
|
||||
if isEolComment(this) then
|
||||
result = "//"
|
||||
if isEolComment(this)
|
||||
then result = "//"
|
||||
else (
|
||||
if isNormalComment(this) then
|
||||
result = "/* "
|
||||
else
|
||||
result = "/** "
|
||||
if isNormalComment(this) then result = "/* " else result = "/** "
|
||||
)
|
||||
}
|
||||
|
||||
private string toStringPostfix() {
|
||||
if isEolComment(this) then
|
||||
result = ""
|
||||
if isEolComment(this)
|
||||
then result = ""
|
||||
else (
|
||||
if strictcount(getAChild()) = 1 then
|
||||
result = " */"
|
||||
else
|
||||
result = " ... */"
|
||||
if strictcount(getAChild()) = 1 then result = " */" else result = " ... */"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -79,25 +58,19 @@ class Javadoc extends JavadocParent, @javadoc {
|
||||
/** A documentable element that can have an attached Javadoc comment. */
|
||||
class Documentable extends Element, @member {
|
||||
/** Gets the Javadoc comment attached to this element. */
|
||||
Javadoc getJavadoc() { hasJavadoc(this,result) and not isNormalComment(result) }
|
||||
Javadoc getJavadoc() { hasJavadoc(this, result) and not isNormalComment(result) }
|
||||
|
||||
/** Gets the name of the author(s) of this element, if any. */
|
||||
string getAuthor() {
|
||||
result = this.getJavadoc().getAuthor()
|
||||
}
|
||||
string getAuthor() { result = this.getJavadoc().getAuthor() }
|
||||
}
|
||||
|
||||
/** A common super-class for Javadoc elements, which may be either tags or text. */
|
||||
abstract class JavadocElement extends @javadocElement, Top {
|
||||
/** Gets the parent of this Javadoc element. */
|
||||
JavadocParent getParent() {
|
||||
javadocTag(this,_,result,_) or javadocText(this,_,result,_)
|
||||
}
|
||||
JavadocParent getParent() { javadocTag(this, _, result, _) or javadocText(this, _, result, _) }
|
||||
|
||||
/** Gets the index of this child element relative to its parent. */
|
||||
int getIndex() {
|
||||
javadocTag(this,_,_,result) or javadocText(this,_,_,result)
|
||||
}
|
||||
int getIndex() { javadocTag(this, _, _, result) or javadocText(this, _, _, result) }
|
||||
|
||||
/** Gets a printable representation of this Javadoc element. */
|
||||
/*abstract*/ override string toString() { result = "Javadoc element" }
|
||||
@@ -109,7 +82,7 @@ abstract class JavadocElement extends @javadocElement, Top {
|
||||
/** A Javadoc tag. */
|
||||
class JavadocTag extends JavadocElement, JavadocParent, @javadocTag {
|
||||
/** Gets the name of this Javadoc tag. */
|
||||
string getTagName() { javadocTag(this,result,_,_) }
|
||||
string getTagName() { javadocTag(this, result, _, _) }
|
||||
|
||||
/** Gets a printable representation of this Javadoc tag. */
|
||||
override string toString() { result = this.getTagName() }
|
||||
@@ -158,12 +131,11 @@ class AuthorTag extends JavadocTag {
|
||||
|
||||
/** A piece of Javadoc text. */
|
||||
class JavadocText extends JavadocElement, @javadocText {
|
||||
|
||||
/** Gets the Javadoc comment that contains this piece of text. */
|
||||
Javadoc getJavadoc() { result.getAChild+() = this }
|
||||
|
||||
/** Gets the text itself. */
|
||||
override string getText() { javadocText(this,result,_,_) }
|
||||
override string getText() { javadocText(this, result, _, _) }
|
||||
|
||||
/** Gets a printable representation of this Javadoc element. */
|
||||
override string toString() { result = this.getText() }
|
||||
|
||||
@@ -6,7 +6,7 @@ class MapType extends RefType {
|
||||
MapType() {
|
||||
exists(ParameterizedInterface coll |
|
||||
coll.getSourceDeclaration().hasQualifiedName("java.util", "Map")
|
||||
|
|
||||
|
|
||||
this.hasSupertype*(coll)
|
||||
)
|
||||
}
|
||||
@@ -28,44 +28,30 @@ class MapType extends RefType {
|
||||
|
||||
/** A method declared in a map type. */
|
||||
class MapMethod extends Method {
|
||||
MapMethod() {
|
||||
this.getDeclaringType() instanceof MapType
|
||||
}
|
||||
MapMethod() { this.getDeclaringType() instanceof MapType }
|
||||
|
||||
/** Gets the type of keys of the map to which this method belongs. */
|
||||
RefType getReceiverKeyType() {
|
||||
result = this.getDeclaringType().(MapType).getKeyType()
|
||||
}
|
||||
RefType getReceiverKeyType() { result = this.getDeclaringType().(MapType).getKeyType() }
|
||||
|
||||
/** Gets the type of values of the map to which this method belongs. */
|
||||
RefType getReceiverValueType() {
|
||||
result = this.getDeclaringType().(MapType).getValueType()
|
||||
}
|
||||
RefType getReceiverValueType() { result = this.getDeclaringType().(MapType).getValueType() }
|
||||
}
|
||||
|
||||
/** A method that mutates the map it belongs to. */
|
||||
class MapMutator extends MapMethod {
|
||||
MapMutator() {
|
||||
this.getName().regexpMatch("(put.*|remove|clear)")
|
||||
}
|
||||
MapMutator() { this.getName().regexpMatch("(put.*|remove|clear)") }
|
||||
}
|
||||
|
||||
/** The `size` method of `java.util.Map`. */
|
||||
class MapSizeMethod extends MapMethod {
|
||||
MapSizeMethod() {
|
||||
this.hasName("size") and this.hasNoParameters()
|
||||
}
|
||||
MapSizeMethod() { this.hasName("size") and this.hasNoParameters() }
|
||||
}
|
||||
|
||||
/** A method call that mutates a map. */
|
||||
class MapMutation extends MethodAccess {
|
||||
MapMutation() {
|
||||
this.getMethod() instanceof MapMutator
|
||||
}
|
||||
MapMutation() { this.getMethod() instanceof MapMutator }
|
||||
|
||||
predicate resultIsChecked() {
|
||||
not this.getParent() instanceof ExprStmt
|
||||
}
|
||||
predicate resultIsChecked() { not this.getParent() instanceof ExprStmt }
|
||||
}
|
||||
|
||||
/** A method that queries the contents of the map it belongs to without mutating it. */
|
||||
@@ -88,15 +74,9 @@ class FreshMap extends ClassInstanceExpr {
|
||||
* A call to `Map.put(key, value)`.
|
||||
*/
|
||||
class MapPutCall extends MethodAccess {
|
||||
MapPutCall() {
|
||||
getCallee().(MapMethod).hasName("put")
|
||||
}
|
||||
MapPutCall() { getCallee().(MapMethod).hasName("put") }
|
||||
|
||||
Expr getKey() {
|
||||
result = getArgument(0)
|
||||
}
|
||||
Expr getKey() { result = getArgument(0) }
|
||||
|
||||
Expr getValue() {
|
||||
result = getArgument(1)
|
||||
}
|
||||
Expr getValue() { result = getArgument(1) }
|
||||
}
|
||||
|
||||
@@ -14,17 +14,13 @@ import metrics.MetricField
|
||||
* including methods, constructors, fields, and nested types.
|
||||
*/
|
||||
class Member extends Element, Annotatable, Modifiable, @member {
|
||||
Member() {
|
||||
declaresMember(_,this)
|
||||
}
|
||||
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()
|
||||
}
|
||||
string getQualifiedName() { result = getDeclaringType().getName() + "." + getName() }
|
||||
|
||||
/** Holds if this member is package protected, that is, neither public nor private nor protected. */
|
||||
predicate isPackageProtected() {
|
||||
@@ -78,16 +74,15 @@ class Callable extends StmtParent, Member, @callable {
|
||||
}
|
||||
|
||||
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()
|
||||
(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))
|
||||
}
|
||||
predicate calls(Callable target) { exists(getACallSite(target)) }
|
||||
|
||||
/**
|
||||
* Holds if this callable calls `target`
|
||||
@@ -109,28 +104,23 @@ class Callable extends StmtParent, Member, @callable {
|
||||
* Holds if this callable calls `target`
|
||||
* using a `super` method call.
|
||||
*/
|
||||
predicate callsSuper(Method target) {
|
||||
getACallSite(target) instanceof SuperMethodAccess
|
||||
}
|
||||
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)
|
||||
}
|
||||
predicate callsConstructor(Constructor c) { this.callsSuperConstructor(c) or this.callsThis(c) }
|
||||
|
||||
/**
|
||||
* Holds if this callable may call the specified callable,
|
||||
* taking overriding into account.
|
||||
*/
|
||||
predicate polyCalls(Callable m) {
|
||||
this.calls(m) or
|
||||
exists(Method mSuper, VirtualMethodAccess c |
|
||||
c.getCaller() = this and c.getMethod() = mSuper
|
||||
|
|
||||
this.calls(m)
|
||||
or
|
||||
exists(Method mSuper, VirtualMethodAccess c | c.getCaller() = this and c.getMethod() = mSuper |
|
||||
m.(Method).overrides(mSuper)
|
||||
)
|
||||
}
|
||||
@@ -139,17 +129,13 @@ class Callable extends StmtParent, Member, @callable {
|
||||
* Holds if field `f` may be assigned a value
|
||||
* within the body of this callable.
|
||||
*/
|
||||
predicate writes(Field f) {
|
||||
f.getAnAccess().(LValue).getEnclosingCallable() = this
|
||||
}
|
||||
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
|
||||
}
|
||||
predicate reads(Field f) { f.getAnAccess().(RValue).getEnclosingCallable() = this }
|
||||
|
||||
/**
|
||||
* Holds if field `f` may be either read or written
|
||||
@@ -169,9 +155,7 @@ class Callable extends StmtParent, Member, @callable {
|
||||
predicate hasNoParameters() { not exists(getAParameter()) }
|
||||
|
||||
/** Gets the number of formal parameters of this callable. */
|
||||
int getNumberOfParameters() {
|
||||
result = count(getAParameter())
|
||||
}
|
||||
int getNumberOfParameters() { result = count(getAParameter()) }
|
||||
|
||||
/** Gets a formal parameter of this callable. */
|
||||
Parameter getAParameter() { result.getCallable() = this }
|
||||
@@ -188,9 +172,7 @@ class Callable extends StmtParent, Member, @callable {
|
||||
*
|
||||
* Use `getSignature` to obtain a signature including fully qualified type names.
|
||||
*/
|
||||
string getStringSignature() {
|
||||
result = this.getName() + this.paramsString()
|
||||
}
|
||||
string getStringSignature() { result = this.getName() + this.paramsString() }
|
||||
|
||||
/** Gets a parenthesized string containing all parameter types of this callable, separated by a comma. */
|
||||
pragma[nomagic]
|
||||
@@ -198,7 +180,7 @@ class Callable extends StmtParent, Member, @callable {
|
||||
exists(int n | n = getNumberOfParameters() |
|
||||
n = 0 and result = "()"
|
||||
or
|
||||
n > 0 and result = "(" + this.paramUpTo(n-1) + ")"
|
||||
n > 0 and result = "(" + this.paramUpTo(n - 1) + ")"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -209,24 +191,20 @@ class Callable extends StmtParent, Member, @callable {
|
||||
private string paramUpTo(int n) {
|
||||
n = 0 and result = getParameterType(0).toString()
|
||||
or
|
||||
n > 0 and result = paramUpTo(n-1) + ", " + getParameterType(n)
|
||||
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()
|
||||
}
|
||||
predicate hasStringSignature(string sig) { sig = this.getStringSignature() }
|
||||
|
||||
/** Gets an exception that occurs in the `throws` clause of this callable. */
|
||||
Exception getAnException() { exceptions(result,_,this) }
|
||||
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
|
||||
}
|
||||
Call getAReference() { result.getCallee() = this }
|
||||
|
||||
/** Gets the body of this callable, if any. */
|
||||
Block getBody() { result.getParent() = this }
|
||||
@@ -266,11 +244,12 @@ class Callable extends StmtParent, Member, @callable {
|
||||
}
|
||||
|
||||
/** Holds if method `m1` overrides method `m2`. */
|
||||
private
|
||||
predicate overrides(Method m1, 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.isPublic()
|
||||
or
|
||||
m2.isProtected()
|
||||
or
|
||||
m2.isPackageProtected() and t1.getPackage() = t2.getPackage()
|
||||
)
|
||||
}
|
||||
@@ -290,7 +269,7 @@ predicate overridesIgnoringAccess(Method m1, RefType t1, Method m2, RefType t2)
|
||||
}
|
||||
|
||||
private predicate virtualMethodWithSignature(string sig, RefType t, Method m) {
|
||||
methods(m,_,_,_,t,_) and
|
||||
methods(m, _, _, _, t, _) and
|
||||
sig = m.getSignature() and
|
||||
m.isVirtual()
|
||||
}
|
||||
@@ -326,21 +305,20 @@ class Method extends Callable, @method {
|
||||
* source declaration of this method (and not equal to it).
|
||||
*/
|
||||
predicate overridesOrInstantiates(Method m) {
|
||||
this.overrides(m) or
|
||||
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)
|
||||
}
|
||||
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,_,_,_) }
|
||||
override string getSignature() { methods(this, _, result, _, _, _) }
|
||||
|
||||
/**
|
||||
* Holds if this method and method `m` are declared in the same type
|
||||
@@ -357,7 +335,7 @@ class Method extends Callable, @method {
|
||||
not exists(int n | this.getParameterType(n) != m.getParameterType(n))
|
||||
}
|
||||
|
||||
override SrcMethod getSourceDeclaration() { methods(this,_,_,_,_,result) }
|
||||
override SrcMethod getSourceDeclaration() { methods(this, _, _, _, _, result) }
|
||||
|
||||
/**
|
||||
* All the methods that could possibly be called when this method
|
||||
@@ -372,9 +350,7 @@ class Method extends Callable, @method {
|
||||
this.getSourceDeclaration().getAPossibleImplementationOfSrcMethod() = result
|
||||
}
|
||||
|
||||
override MethodAccess getAReference() {
|
||||
result = Callable.super.getAReference()
|
||||
}
|
||||
override MethodAccess getAReference() { result = Callable.super.getAReference() }
|
||||
|
||||
override predicate isPublic() {
|
||||
Callable.super.isPublic() or
|
||||
@@ -413,9 +389,7 @@ class Method extends Callable, @method {
|
||||
* Holds if this method is neither private nor static, and hence
|
||||
* uses dynamic dispatch.
|
||||
*/
|
||||
predicate isVirtual() {
|
||||
not isPrivate() and not isStatic()
|
||||
}
|
||||
predicate isVirtual() { not isPrivate() and not isStatic() }
|
||||
|
||||
/** Holds if this method can be overridden. */
|
||||
predicate isOverridable() {
|
||||
@@ -427,7 +401,7 @@ class Method extends Callable, @method {
|
||||
|
||||
/** A method that is the same as its source declaration. */
|
||||
class SrcMethod extends Method {
|
||||
SrcMethod() { methods(_,_,_,_,_,this) }
|
||||
SrcMethod() { methods(_, _, _, _, _, this) }
|
||||
|
||||
/**
|
||||
* All the methods that could possibly be called when this method
|
||||
@@ -440,10 +414,9 @@ class SrcMethod extends Method {
|
||||
*/
|
||||
SrcMethod getAPossibleImplementationOfSrcMethod() {
|
||||
(
|
||||
if this.getDeclaringType() instanceof Interface and this.isVirtual() then
|
||||
implementsInterfaceMethod(result, this)
|
||||
else
|
||||
result.getASourceOverriddenMethod*() = this
|
||||
if this.getDeclaringType() instanceof Interface and this.isVirtual()
|
||||
then implementsInterfaceMethod(result, this)
|
||||
else result.getASourceOverriddenMethod*() = this
|
||||
) and
|
||||
(exists(result.getBody()) or result.hasModifier("native"))
|
||||
}
|
||||
@@ -462,7 +435,7 @@ class SetterMethod extends Method {
|
||||
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()
|
||||
@@ -472,9 +445,7 @@ class SetterMethod extends Method {
|
||||
|
||||
/** Gets the field assigned by this setter method. */
|
||||
Field getField() {
|
||||
exists(Assignment a | a.getEnclosingCallable() = this |
|
||||
a.getDest() = result.getAnAccess()
|
||||
)
|
||||
exists(Assignment a | a.getEnclosingCallable() = this | a.getDest() = result.getAnAccess())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,9 +466,7 @@ class GetterMethod extends Method {
|
||||
|
||||
/** Gets the field whose value is returned by this getter method. */
|
||||
Field getField() {
|
||||
exists(ReturnStmt r | r.getEnclosingCallable() = this |
|
||||
r.getResult() = result.getAnAccess()
|
||||
)
|
||||
exists(ReturnStmt r | r.getEnclosingCallable() = this | r.getResult() = result.getAnAccess())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,9 +487,9 @@ 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 Constructor getSourceDeclaration() { constrs(this, _, _, _, _, result) }
|
||||
|
||||
override string getSignature() { constrs(this,_,result,_,_,_) }
|
||||
override string getSignature() { constrs(this, _, result, _, _, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -528,26 +497,20 @@ class Constructor extends Callable, @constructor {
|
||||
* non-static), which is used to hold (static or non-static) field
|
||||
* initializers, as well as explicit initializer blocks.
|
||||
*/
|
||||
abstract class InitializerMethod extends Method {}
|
||||
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>")
|
||||
}
|
||||
}
|
||||
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>")
|
||||
}
|
||||
InstanceInitializer() { this.hasName("<obinit>") }
|
||||
}
|
||||
|
||||
/** A field declaration that declares one or more class or instance fields. */
|
||||
@@ -565,10 +528,9 @@ class FieldDeclaration extends ExprParent, @fielddecl, Annotatable {
|
||||
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) + ", ...;"
|
||||
if this.getNumField() = 0
|
||||
then result = this.getTypeAccess() + " " + this.getField(0) + ";"
|
||||
else result = this.getTypeAccess() + " " + this.getField(0) + ", ...;"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,7 +569,7 @@ class Field extends Member, ExprParent, @field, Variable {
|
||||
*
|
||||
* For all other fields, the source declaration is the field itself.
|
||||
*/
|
||||
Field getSourceDeclaration() { fields(this,_,_,_,result) }
|
||||
Field getSourceDeclaration() { fields(this, _, _, _, result) }
|
||||
|
||||
/** Holds if this field is the same as its source declaration. */
|
||||
predicate isSourceDeclaration() { this.getSourceDeclaration() = this }
|
||||
@@ -638,8 +600,4 @@ class Field extends Member, ExprParent, @field, Variable {
|
||||
}
|
||||
|
||||
/** An instance field. */
|
||||
class InstanceField extends Field {
|
||||
InstanceField() {
|
||||
not this.isStatic()
|
||||
}
|
||||
}
|
||||
class InstanceField extends Field { InstanceField() { not this.isStatic() } }
|
||||
|
||||
@@ -7,7 +7,7 @@ import Element
|
||||
/** A modifier such as `private`, `static` or `abstract`. */
|
||||
class Modifier extends Element, @modifier {
|
||||
/** Gets the element to which this modifier applies. */
|
||||
Element getElement() { hasModifier(result,this) }
|
||||
Element getElement() { hasModifier(result, this) }
|
||||
}
|
||||
|
||||
/** An element of the Java syntax tree that may have a modifier. */
|
||||
@@ -21,12 +21,10 @@ abstract class Modifiable extends Element {
|
||||
* abstract, so `isAbstract()` will hold for them even if `hasModifier("abstract")`
|
||||
* does not.
|
||||
*/
|
||||
predicate hasModifier(string m) {
|
||||
modifiers(getAModifier(), m)
|
||||
}
|
||||
predicate hasModifier(string m) { modifiers(getAModifier(), m) }
|
||||
|
||||
/** Holds if this element has no modifier. */
|
||||
predicate hasNoModifier() { not hasModifier(this,_) }
|
||||
predicate hasNoModifier() { not hasModifier(this, _) }
|
||||
|
||||
/** Gets a modifier of this element. */
|
||||
Modifier getAModifier() { this = result.getElement() }
|
||||
|
||||
@@ -8,9 +8,7 @@ import CompilationUnit
|
||||
* A module.
|
||||
*/
|
||||
class Module extends @module {
|
||||
Module() {
|
||||
modules(this, _)
|
||||
}
|
||||
Module() { modules(this, _) }
|
||||
|
||||
/**
|
||||
* Gets the name of this module.
|
||||
@@ -50,9 +48,7 @@ abstract class Directive extends @directive {
|
||||
* A `requires` directive in a module declaration.
|
||||
*/
|
||||
class RequiresDirective extends Directive, @requires {
|
||||
RequiresDirective() {
|
||||
requires(this,_)
|
||||
}
|
||||
RequiresDirective() { requires(this, _) }
|
||||
|
||||
/**
|
||||
* Holds if this `requires` directive is `transitive`,
|
||||
@@ -75,12 +71,11 @@ class RequiresDirective extends Directive, @requires {
|
||||
*/
|
||||
Module getTargetModule() { requires(this, result) }
|
||||
|
||||
override
|
||||
string toString() {
|
||||
override string toString() {
|
||||
exists(string transitive, string static |
|
||||
(if isTransitive() then transitive = "transitive " else transitive = "") and
|
||||
(if isStatic() then static = "static " else static = "")
|
||||
|
|
||||
|
|
||||
result = "requires " + transitive + static + getTargetModule() + ";"
|
||||
)
|
||||
}
|
||||
@@ -90,9 +85,7 @@ class RequiresDirective extends Directive, @requires {
|
||||
* An `exports` directive in a module declaration.
|
||||
*/
|
||||
class ExportsDirective extends Directive, @exports {
|
||||
ExportsDirective() {
|
||||
exports(this,_)
|
||||
}
|
||||
ExportsDirective() { exports(this, _) }
|
||||
|
||||
/**
|
||||
* Gets the package exported by this `exports` directive.
|
||||
@@ -116,11 +109,12 @@ class ExportsDirective extends Directive, @exports {
|
||||
*/
|
||||
Module getATargetModule() { exportsTo(this, result) }
|
||||
|
||||
override
|
||||
string toString() {
|
||||
override string toString() {
|
||||
exists(string toClause |
|
||||
if isQualified() then toClause = (" to " + concat(getATargetModule().getName(), ", ")) else toClause = ""
|
||||
|
|
||||
if isQualified()
|
||||
then toClause = (" to " + concat(getATargetModule().getName(), ", "))
|
||||
else toClause = ""
|
||||
|
|
||||
result = "exports " + getExportedPackage() + toClause + ";"
|
||||
)
|
||||
}
|
||||
@@ -130,9 +124,7 @@ class ExportsDirective extends Directive, @exports {
|
||||
* An `opens` directive in a module declaration.
|
||||
*/
|
||||
class OpensDirective extends Directive, @opens {
|
||||
OpensDirective() {
|
||||
opens(this,_)
|
||||
}
|
||||
OpensDirective() { opens(this, _) }
|
||||
|
||||
/**
|
||||
* Gets the package opened by this `opens` directive.
|
||||
@@ -156,11 +148,12 @@ class OpensDirective extends Directive, @opens {
|
||||
*/
|
||||
Module getATargetModule() { opensTo(this, result) }
|
||||
|
||||
override
|
||||
string toString() {
|
||||
override string toString() {
|
||||
exists(string toClause |
|
||||
if isQualified() then toClause = (" to " + concat(getATargetModule().getName(), ", ")) else toClause = ""
|
||||
|
|
||||
if isQualified()
|
||||
then toClause = (" to " + concat(getATargetModule().getName(), ", "))
|
||||
else toClause = ""
|
||||
|
|
||||
result = "opens " + getOpenedPackage() + toClause + ";"
|
||||
)
|
||||
}
|
||||
@@ -170,28 +163,21 @@ class OpensDirective extends Directive, @opens {
|
||||
* A `uses` directive in a module declaration.
|
||||
*/
|
||||
class UsesDirective extends Directive, @uses {
|
||||
UsesDirective() {
|
||||
uses(this,_)
|
||||
}
|
||||
UsesDirective() { uses(this, _) }
|
||||
|
||||
/**
|
||||
* Gets the qualified name of the service interface specified in this `uses` directive.
|
||||
*/
|
||||
string getServiceInterfaceName() { uses(this, result) }
|
||||
|
||||
override
|
||||
string toString() {
|
||||
result = "uses " + getServiceInterfaceName() + ";"
|
||||
}
|
||||
override string toString() { result = "uses " + getServiceInterfaceName() + ";" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `provides` directive in a module declaration.
|
||||
*/
|
||||
class ProvidesDirective extends Directive, @provides {
|
||||
ProvidesDirective() {
|
||||
provides(this,_)
|
||||
}
|
||||
ProvidesDirective() { provides(this, _) }
|
||||
|
||||
/**
|
||||
* Gets the qualified name of the service interface specified in this `provides` directive.
|
||||
@@ -203,9 +189,8 @@ class ProvidesDirective extends Directive, @provides {
|
||||
*/
|
||||
string getServiceImplementationName() { providesWith(this, result) }
|
||||
|
||||
override
|
||||
string toString() {
|
||||
result = "provides " + getServiceInterfaceName() + " with " + concat(getServiceImplementationName(), ", ") + ";"
|
||||
override string toString() {
|
||||
result = "provides " + getServiceInterfaceName() + " with " +
|
||||
concat(getServiceImplementationName(), ", ") + ";"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,9 +15,7 @@ class Package extends Element, Annotatable, @package {
|
||||
TopLevelType getATopLevelType() { result.getPackage() = this }
|
||||
|
||||
/** Holds if at least one reference type in this package originates from source code. */
|
||||
override predicate fromSource() {
|
||||
exists(RefType t | t.fromSource() and t.getPackage() = this)
|
||||
}
|
||||
override predicate fromSource() { exists(RefType t | t.fromSource() and t.getPackage() = this) }
|
||||
|
||||
/** Cast this package to a class that provides access to metrics information. */
|
||||
MetricPackage getMetrics() { result = this }
|
||||
|
||||
@@ -7,13 +7,13 @@ import JDKAnnotations
|
||||
import Serializability
|
||||
import semmle.code.java.dataflow.DefUse
|
||||
|
||||
predicate reflectivelyRead(Field f){
|
||||
predicate reflectivelyRead(Field f) {
|
||||
f instanceof SerializableField or
|
||||
f.getAnAnnotation() instanceof ReflectiveAccessAnnotation or
|
||||
referencedInXmlFile(f)
|
||||
}
|
||||
|
||||
predicate reflectivelyWritten(Field f){
|
||||
predicate reflectivelyWritten(Field f) {
|
||||
f instanceof DeserializableField or
|
||||
f.getAnAnnotation() instanceof ReflectiveAccessAnnotation or
|
||||
referencedInXmlFile(f)
|
||||
@@ -44,7 +44,7 @@ private XMLElement elementReferencingType(RefType rt) {
|
||||
result.getAnAttribute().getValue() = rt.getSourceDeclaration().getQualifiedName()
|
||||
}
|
||||
|
||||
private abstract class ReflectiveClassIdentifier extends Expr {
|
||||
abstract private class ReflectiveClassIdentifier extends Expr {
|
||||
abstract RefType getReflectivelyIdentifiedClass();
|
||||
}
|
||||
|
||||
@@ -60,17 +60,17 @@ private class ReflectiveClassIdentifierLiteral extends ReflectiveClassIdentifier
|
||||
library class ReflectiveClassIdentifierMethodAccess extends ReflectiveClassIdentifier, MethodAccess {
|
||||
ReflectiveClassIdentifierMethodAccess() {
|
||||
// A call to `Class.forName(...)`, from which we can infer `T` in the returned type `Class<T>`.
|
||||
getCallee().getDeclaringType() instanceof TypeClass and getCallee().hasName("forName") or
|
||||
getCallee().getDeclaringType() instanceof TypeClass and getCallee().hasName("forName")
|
||||
or
|
||||
// A call to `ClassLoader.loadClass(...)`, from which we can infer `T` in the returned type `Class<T>`.
|
||||
getCallee().getDeclaringType().hasQualifiedName("java.lang", "ClassLoader") and getCallee().hasName("loadClass")
|
||||
getCallee().getDeclaringType().hasQualifiedName("java.lang", "ClassLoader") and
|
||||
getCallee().hasName("loadClass")
|
||||
}
|
||||
|
||||
/**
|
||||
* If the argument to this call is a `StringLiteral`, then return that string.
|
||||
*/
|
||||
string getTypeName() {
|
||||
result = getArgument(0).(StringLiteral).getRepresentedString()
|
||||
}
|
||||
string getTypeName() { result = getArgument(0).(StringLiteral).getRepresentedString() }
|
||||
|
||||
override RefType getReflectivelyIdentifiedClass() {
|
||||
// We only handle cases where the class is specified as a string literal to this call.
|
||||
@@ -82,16 +82,17 @@ library class ReflectiveClassIdentifierMethodAccess extends ReflectiveClassIdent
|
||||
* Gets a `ReflectiveClassIdentifier` that we believe may represent the value of `expr`.
|
||||
*/
|
||||
private ReflectiveClassIdentifier pointsToReflectiveClassIdentifier(Expr expr) {
|
||||
// If this is an expression creating a `Class<T>`, return the inferred `T` from the creation expression.
|
||||
result = expr or
|
||||
// Or if this is an access of a variable which was defined as an expression creating a `Class<T>`,
|
||||
// return the inferred `T` from the definition expression.
|
||||
exists(RValue use, VariableAssign assign |
|
||||
use = expr and
|
||||
defUsePair(assign, use) and
|
||||
// The source of the assignment must be a `ReflectiveClassIdentifier`.
|
||||
result = assign.getSource()
|
||||
)
|
||||
// If this is an expression creating a `Class<T>`, return the inferred `T` from the creation expression.
|
||||
result = expr
|
||||
or
|
||||
// Or if this is an access of a variable which was defined as an expression creating a `Class<T>`,
|
||||
// return the inferred `T` from the definition expression.
|
||||
exists(RValue use, VariableAssign assign |
|
||||
use = expr and
|
||||
defUsePair(assign, use) and
|
||||
// The source of the assignment must be a `ReflectiveClassIdentifier`.
|
||||
result = assign.getSource()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,11 +108,7 @@ private predicate overlyGenericType(Type type) {
|
||||
* `? extends Object` and `? extends Serializable`.
|
||||
*/
|
||||
private predicate catchallType(BoundedType type) {
|
||||
exists(Type upperBound |
|
||||
upperBound = type.getUpperBoundType()
|
||||
|
|
||||
overlyGenericType(upperBound)
|
||||
)
|
||||
exists(Type upperBound | upperBound = type.getUpperBoundType() | overlyGenericType(upperBound))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,9 +120,7 @@ private predicate catchallType(BoundedType type) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Type parameterForSubTypes(ParameterizedType type) {
|
||||
(
|
||||
type instanceof TypeClass or type instanceof TypeConstructor
|
||||
) and
|
||||
(type instanceof TypeClass or type instanceof TypeConstructor) and
|
||||
// Only report "real" types.
|
||||
not result instanceof TypeVariable and
|
||||
// Identify which types the type argument `arg` could represent.
|
||||
@@ -133,27 +128,31 @@ private Type parameterForSubTypes(ParameterizedType type) {
|
||||
arg = type.getTypeArgument(0) and
|
||||
// Must not be a catch-all.
|
||||
not catchallType(arg)
|
||||
|
|
||||
|
|
||||
(
|
||||
// Simple case - this type is not a bounded type, so must represent exactly the `arg` class.
|
||||
not arg instanceof BoundedType and result = arg
|
||||
) or
|
||||
)
|
||||
or
|
||||
exists(RefType upperBound |
|
||||
// Upper bound case
|
||||
upperBound = arg.(BoundedType).getUpperBoundType()
|
||||
|
|
||||
|
|
||||
/*
|
||||
* `T extends Foo` implies that `Foo`, or any sub-type of `Foo`, may be represented.
|
||||
*/
|
||||
|
||||
result.(RefType).getAnAncestor() = upperBound
|
||||
) or
|
||||
)
|
||||
or
|
||||
exists(RefType lowerBound |
|
||||
// Lower bound case
|
||||
lowerBound = arg.(Wildcard).getLowerBoundType()
|
||||
|
|
||||
|
|
||||
/*
|
||||
* `T super Foo` implies that `Foo`, or any super-type of `Foo`, may be represented.
|
||||
*/
|
||||
|
||||
lowerBound.(RefType).getAnAncestor() = result
|
||||
)
|
||||
)
|
||||
@@ -170,21 +169,23 @@ Type inferClassParameterType(Expr expr) {
|
||||
* If this `expr` is a `VarAccess` of a final or effectively final parameter, then look at the
|
||||
* arguments to calls to this method, to see if we can infer anything from that case.
|
||||
*/
|
||||
|
||||
exists(Parameter p |
|
||||
p = expr.(VarAccess).getVariable() and
|
||||
p.isEffectivelyFinal()
|
||||
|
|
||||
|
|
||||
result = inferClassParameterType(p.getAnArgument())
|
||||
)
|
||||
or
|
||||
if exists(pointsToReflectiveClassIdentifier(expr).getReflectivelyIdentifiedClass()) then
|
||||
if exists(pointsToReflectiveClassIdentifier(expr).getReflectivelyIdentifiedClass())
|
||||
then
|
||||
/*
|
||||
* We've been able to identify where this `Class` instance was created, and identified the
|
||||
* particular class that was loaded.
|
||||
*/
|
||||
|
||||
result = pointsToReflectiveClassIdentifier(expr).getReflectivelyIdentifiedClass()
|
||||
else
|
||||
(
|
||||
else (
|
||||
/*
|
||||
* If we haven't been able to find where the value for this expression was defined, then we
|
||||
* resort to the type `T` in `Class<T>`.
|
||||
@@ -195,6 +196,7 @@ Type inferClassParameterType(Expr expr) {
|
||||
* A "catch-all" type is something like `? extends Object` or `? extends Serialization`, which
|
||||
* would return too many sub-types.
|
||||
*/
|
||||
|
||||
result = parameterForSubTypes(expr.getType())
|
||||
)
|
||||
)
|
||||
@@ -224,7 +226,10 @@ private predicate expectsEnclosingInstance(RefType r) {
|
||||
*/
|
||||
class NewInstance extends MethodAccess {
|
||||
NewInstance() {
|
||||
(getCallee().getDeclaringType() instanceof TypeClass or getCallee().getDeclaringType() instanceof TypeConstructor) and
|
||||
(
|
||||
getCallee().getDeclaringType() instanceof TypeClass or
|
||||
getCallee().getDeclaringType() instanceof TypeConstructor
|
||||
) and
|
||||
getCallee().hasName("newInstance")
|
||||
}
|
||||
|
||||
@@ -234,25 +239,31 @@ class NewInstance extends MethodAccess {
|
||||
*/
|
||||
Constructor getInferredConstructor() {
|
||||
result = getInferredConstructedType().getAConstructor() and
|
||||
if getCallee().getDeclaringType() instanceof TypeClass then
|
||||
result.getNumberOfParameters() = 0
|
||||
else if getNumArgument() = 1 and getArgument(0).getType() instanceof Array then
|
||||
/*
|
||||
* This is a var-args array argument. If array argument is initialized inline, then identify
|
||||
* the number of arguments specified in the array.
|
||||
*/
|
||||
if exists(getArgument(0).(ArrayCreationExpr).getInit()) then
|
||||
// Count the number of elements in the initializer, and find the matching constructors.
|
||||
matchConstructorArguments(result, count(getArgument(0).(ArrayCreationExpr).getInit().getAnInit()))
|
||||
else
|
||||
// Could be any of the constructors on this class.
|
||||
any()
|
||||
if getCallee().getDeclaringType() instanceof TypeClass
|
||||
then result.getNumberOfParameters() = 0
|
||||
else
|
||||
/*
|
||||
* No var-args in play, just use the number of arguments to the `newInstance(..)` to determine
|
||||
* which constructors may be called.
|
||||
*/
|
||||
matchConstructorArguments(result, getNumArgument())
|
||||
if getNumArgument() = 1 and getArgument(0).getType() instanceof Array
|
||||
then
|
||||
/*
|
||||
* This is a var-args array argument. If array argument is initialized inline, then identify
|
||||
* the number of arguments specified in the array.
|
||||
*/
|
||||
|
||||
if exists(getArgument(0).(ArrayCreationExpr).getInit())
|
||||
then
|
||||
// Count the number of elements in the initializer, and find the matching constructors.
|
||||
matchConstructorArguments(result,
|
||||
count(getArgument(0).(ArrayCreationExpr).getInit().getAnInit()))
|
||||
else
|
||||
// Could be any of the constructors on this class.
|
||||
any()
|
||||
else
|
||||
/*
|
||||
* No var-args in play, just use the number of arguments to the `newInstance(..)` to determine
|
||||
* which constructors may be called.
|
||||
*/
|
||||
|
||||
matchConstructorArguments(result, getNumArgument())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,10 +274,9 @@ class NewInstance extends MethodAccess {
|
||||
* provided for the enclosing instance.
|
||||
*/
|
||||
private predicate matchConstructorArguments(Constructor c, int numArguments) {
|
||||
if expectsEnclosingInstance(c.getDeclaringType()) then
|
||||
c.getNumberOfParameters() = numArguments - 1
|
||||
else
|
||||
c.getNumberOfParameters() = numArguments
|
||||
if expectsEnclosingInstance(c.getDeclaringType())
|
||||
then c.getNumberOfParameters() = numArguments - 1
|
||||
else c.getNumberOfParameters() = numArguments
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,15 +306,15 @@ class NewInstance extends MethodAccess {
|
||||
* cast.
|
||||
*/
|
||||
private Type getCastInferredConstructedTypes() {
|
||||
exists(CastExpr cast |
|
||||
cast.getExpr() = this or cast.getExpr().(ParExpr).getExpr() = this
|
||||
|
|
||||
result = cast.getType() or
|
||||
exists(CastExpr cast | cast.getExpr() = this or cast.getExpr().(ParExpr).getExpr() = this |
|
||||
result = cast.getType()
|
||||
or
|
||||
(
|
||||
/*
|
||||
* If we cast the result of this method, then this is either the type specified, or a
|
||||
* sub-type of that type. Make sure we exclude overly generic types such as `Object`.
|
||||
*/
|
||||
|
||||
not overlyGenericType(cast.getType()) and
|
||||
hasSubtype*(cast.getType(), result)
|
||||
)
|
||||
@@ -316,9 +326,7 @@ class NewInstance extends MethodAccess {
|
||||
* A `MethodAccess` on a `Class` element.
|
||||
*/
|
||||
class ClassMethodAccess extends MethodAccess {
|
||||
ClassMethodAccess() {
|
||||
this.getCallee().getDeclaringType() instanceof TypeClass
|
||||
}
|
||||
ClassMethodAccess() { this.getCallee().getDeclaringType() instanceof TypeClass }
|
||||
|
||||
/**
|
||||
* Gets an inferred type for the `Class` represented by this expression.
|
||||
@@ -345,14 +353,14 @@ class ReflectiveMethodAccess extends ClassMethodAccess {
|
||||
*/
|
||||
Method inferAccessedMethod() {
|
||||
(
|
||||
if this.getCallee().hasName("getDeclaredMethod") then
|
||||
if this.getCallee().hasName("getDeclaredMethod")
|
||||
then
|
||||
// The method must be declared on the type itself.
|
||||
result.getDeclaringType() = getInferredClassType()
|
||||
else
|
||||
// The method may be declared on an inferred type or a super-type.
|
||||
getInferredClassType().inherits(result)
|
||||
)
|
||||
and
|
||||
) and
|
||||
// Only consider instances where the method name is provided as a `StringLiteral`.
|
||||
result.hasName(getArgument(0).(StringLiteral).getRepresentedString())
|
||||
}
|
||||
@@ -362,16 +370,12 @@ class ReflectiveMethodAccess extends ClassMethodAccess {
|
||||
* A call to `Class.getAnnotation(..)`.
|
||||
*/
|
||||
class ReflectiveAnnotationAccess extends ClassMethodAccess {
|
||||
ReflectiveAnnotationAccess() {
|
||||
this.getCallee().hasName("getAnnotation")
|
||||
}
|
||||
ReflectiveAnnotationAccess() { this.getCallee().hasName("getAnnotation") }
|
||||
|
||||
/**
|
||||
* Gets a possible annotation type for this reflective annotation access.
|
||||
*/
|
||||
AnnotationType getAPossibleAnnotationType() {
|
||||
result = inferClassParameterType(getArgument(0))
|
||||
}
|
||||
AnnotationType getAPossibleAnnotationType() { result = inferClassParameterType(getArgument(0)) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,15 +389,15 @@ class ReflectiveFieldAccess extends ClassMethodAccess {
|
||||
|
||||
Field inferAccessedField() {
|
||||
(
|
||||
if this.getCallee().hasName("getDeclaredField") then
|
||||
if this.getCallee().hasName("getDeclaredField")
|
||||
then
|
||||
// Declared fields must be on the type itself.
|
||||
result.getDeclaringType() = getInferredClassType()
|
||||
else
|
||||
(
|
||||
// This field must be public, and be inherited by one of the inferred class types.
|
||||
result.isPublic() and
|
||||
getInferredClassType().inherits(result)
|
||||
)
|
||||
else (
|
||||
// This field must be public, and be inherited by one of the inferred class types.
|
||||
result.isPublic() and
|
||||
getInferredClassType().inherits(result)
|
||||
)
|
||||
) and
|
||||
result.hasName(getArgument(0).(StringLiteral).getRepresentedString())
|
||||
}
|
||||
|
||||
@@ -10,16 +10,13 @@ private import frameworks.google.GoogleHttpClientApi
|
||||
* A serializable field may be read without code referencing it,
|
||||
* due to the use of serialization.
|
||||
*/
|
||||
abstract class SerializableField extends Field {
|
||||
abstract class SerializableField extends Field { }
|
||||
|
||||
}
|
||||
/**
|
||||
* A deserializable field may be written without code referencing it,
|
||||
* due to the use of serialization.
|
||||
*/
|
||||
abstract class DeserializableField extends Field {
|
||||
|
||||
}
|
||||
abstract class DeserializableField extends Field { }
|
||||
|
||||
/**
|
||||
* A non-`transient` field in a type that (directly or indirectly) implements the `Serializable` interface
|
||||
|
||||
@@ -16,13 +16,13 @@ class Stmt extends StmtParent, ExprParent, @stmt {
|
||||
* Gets the immediately enclosing callable (method or constructor)
|
||||
* whose body contains this statement.
|
||||
*/
|
||||
Callable getEnclosingCallable() { stmts(this,_,_,_,result) }
|
||||
Callable getEnclosingCallable() { stmts(this, _, _, _, result) }
|
||||
|
||||
/** Gets the index of this statement as a child of its parent. */
|
||||
int getIndex() { stmts(this,_,_,result,_) }
|
||||
int getIndex() { stmts(this, _, _, result, _) }
|
||||
|
||||
/** Gets the parent of this statement. */
|
||||
StmtParent getParent() { stmts(this,_,result,_,_) }
|
||||
StmtParent getParent() { stmts(this, _, result, _, _) }
|
||||
|
||||
/** Holds if this statement is the child of the specified parent at the specified (zero-based) position. */
|
||||
predicate isNthChildOf(StmtParent parent, int index) {
|
||||
@@ -49,11 +49,10 @@ class Stmt extends StmtParent, ExprParent, @stmt {
|
||||
}
|
||||
|
||||
/** A statement parent is any element that can have a statement as its child. */
|
||||
class StmtParent extends @stmtparent, Top {
|
||||
}
|
||||
class StmtParent extends @stmtparent, Top { }
|
||||
|
||||
/** A block of statements. */
|
||||
class Block extends Stmt,@block {
|
||||
class Block extends Stmt, @block {
|
||||
/** Gets a statement that is an immediate child of this block. */
|
||||
Stmt getAStmt() { result.getParent() = this }
|
||||
|
||||
@@ -64,7 +63,7 @@ class Block extends Stmt,@block {
|
||||
int getNumStmt() { result = count(this.getAStmt()) }
|
||||
|
||||
/** Gets the last statement in this block. */
|
||||
Stmt getLastStmt() { result = getStmt(getNumStmt()-1) }
|
||||
Stmt getLastStmt() { result = getStmt(getNumStmt() - 1) }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() { result = "{ ... }" }
|
||||
@@ -95,11 +94,11 @@ abstract class ConditionalStmt extends Stmt {
|
||||
*
|
||||
* DEPRECATED: use `ConditionNode.getATrueSuccessor()` instead.
|
||||
*/
|
||||
deprecated abstract Stmt getTrueSuccessor();
|
||||
abstract deprecated Stmt getTrueSuccessor();
|
||||
}
|
||||
|
||||
/** An `if` statement. */
|
||||
class IfStmt extends ConditionalStmt,@ifstmt {
|
||||
class IfStmt extends ConditionalStmt, @ifstmt {
|
||||
/** Gets the boolean condition of this `if` statement. */
|
||||
override Expr getCondition() { result.isNthChildOf(this, 0) }
|
||||
|
||||
@@ -127,16 +126,14 @@ class IfStmt extends ConditionalStmt,@ifstmt {
|
||||
}
|
||||
|
||||
/** A `for` loop. */
|
||||
class ForStmt extends ConditionalStmt,@forstmt {
|
||||
class ForStmt extends ConditionalStmt, @forstmt {
|
||||
/**
|
||||
* Gets an initializer expression of the loop.
|
||||
*
|
||||
* This may be an assignment expression or a
|
||||
* local variable declaration expression.
|
||||
*/
|
||||
Expr getAnInit() {
|
||||
exists(int index | result.isNthChildOf(this, index) | index <= -1)
|
||||
}
|
||||
Expr getAnInit() { exists(int index | result.isNthChildOf(this, index) | index <= -1) }
|
||||
|
||||
/** Gets the initializer expression of the loop at the specified (zero-based) position. */
|
||||
Expr getInit(int index) {
|
||||
@@ -148,9 +145,7 @@ class ForStmt extends ConditionalStmt,@forstmt {
|
||||
override Expr getCondition() { result.isNthChildOf(this, 1) }
|
||||
|
||||
/** Gets an update expression of this `for` loop. */
|
||||
Expr getAnUpdate() {
|
||||
exists(int index | result.isNthChildOf(this, index) | index >= 3)
|
||||
}
|
||||
Expr getAnUpdate() { exists(int index | result.isNthChildOf(this, index) | index >= 3) }
|
||||
|
||||
/** Gets the update expression of this loop at the specified (zero-based) position. */
|
||||
Expr getUpdate(int index) {
|
||||
@@ -189,16 +184,14 @@ class ForStmt extends ConditionalStmt,@forstmt {
|
||||
}
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "for (...;...;...) " + this.getStmt().pp()
|
||||
}
|
||||
override string pp() { result = "for (...;...;...) " + this.getStmt().pp() }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "ForStmt" }
|
||||
}
|
||||
|
||||
/** An enhanced `for` loop. (Introduced in Java 5.) */
|
||||
class EnhancedForStmt extends Stmt,@enhancedforstmt {
|
||||
class EnhancedForStmt extends Stmt, @enhancedforstmt {
|
||||
/** Gets the local variable declaration expression of this enhanced `for` loop. */
|
||||
LocalVariableDeclExpr getVariable() { result.getParent() = this }
|
||||
|
||||
@@ -209,16 +202,14 @@ class EnhancedForStmt extends Stmt,@enhancedforstmt {
|
||||
Stmt getStmt() { result.getParent() = this }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "for (...) " + this.getStmt().pp()
|
||||
}
|
||||
override string pp() { result = "for (...) " + this.getStmt().pp() }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "EnhancedForStmt" }
|
||||
}
|
||||
|
||||
/** A `while` loop. */
|
||||
class WhileStmt extends ConditionalStmt,@whilestmt {
|
||||
class WhileStmt extends ConditionalStmt, @whilestmt {
|
||||
/** Gets the boolean condition of this `while` loop. */
|
||||
override Expr getCondition() { result.getParent() = this }
|
||||
|
||||
@@ -232,16 +223,14 @@ class WhileStmt extends ConditionalStmt,@whilestmt {
|
||||
override Stmt getTrueSuccessor() { result = getStmt() }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "while (...) " + this.getStmt().pp()
|
||||
}
|
||||
override string pp() { result = "while (...) " + this.getStmt().pp() }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "WhileStmt" }
|
||||
}
|
||||
|
||||
/** A `do` loop. */
|
||||
class DoStmt extends ConditionalStmt,@dostmt {
|
||||
class DoStmt extends ConditionalStmt, @dostmt {
|
||||
/** Gets the condition of this `do` loop. */
|
||||
override Expr getCondition() { result.getParent() = this }
|
||||
|
||||
@@ -255,9 +244,7 @@ class DoStmt extends ConditionalStmt,@dostmt {
|
||||
override Stmt getTrueSuccessor() { result = getStmt() }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "do " + this.getStmt().pp() + " while (...)"
|
||||
}
|
||||
override string pp() { result = "do " + this.getStmt().pp() + " while (...)" }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "DoStmt" }
|
||||
@@ -292,7 +279,7 @@ class LoopStmt extends Stmt {
|
||||
}
|
||||
|
||||
/** A `try` statement. */
|
||||
class TryStmt extends Stmt,@trystmt {
|
||||
class TryStmt extends Stmt, @trystmt {
|
||||
/** Gets the block of the `try` statement. */
|
||||
Stmt getBlock() { result.isNthChildOf(this, -1) }
|
||||
|
||||
@@ -312,9 +299,7 @@ class TryStmt extends Stmt,@trystmt {
|
||||
Block getFinally() { result.isNthChildOf(this, -2) }
|
||||
|
||||
/** Gets a resource variable declaration, if any. */
|
||||
LocalVariableDeclStmt getAResourceDecl() {
|
||||
result.getParent() = this and result.getIndex() <= -3
|
||||
}
|
||||
LocalVariableDeclStmt getAResourceDecl() { result.getParent() = this and result.getIndex() <= -3 }
|
||||
|
||||
/** Gets the resource variable declaration at the specified position in this `try` statement. */
|
||||
LocalVariableDeclStmt getResourceDecl(int index) {
|
||||
@@ -323,9 +308,7 @@ class TryStmt extends Stmt,@trystmt {
|
||||
}
|
||||
|
||||
/** Gets a resource expression, if any. */
|
||||
VarAccess getAResourceExpr() {
|
||||
result.getParent() = this and result.getIndex() <= -3
|
||||
}
|
||||
VarAccess getAResourceExpr() { result.getParent() = this and result.getIndex() <= -3 }
|
||||
|
||||
/** Gets the resource expression at the specified position in this `try` statement. */
|
||||
VarAccess getResourceExpr(int index) {
|
||||
@@ -334,9 +317,7 @@ class TryStmt extends Stmt,@trystmt {
|
||||
}
|
||||
|
||||
/** Gets a resource in this `try` statement, if any. */
|
||||
ExprParent getAResource() {
|
||||
result = getAResourceDecl() or result = getAResourceExpr()
|
||||
}
|
||||
ExprParent getAResource() { result = getAResourceDecl() or result = getAResourceExpr() }
|
||||
|
||||
/** Gets the resource at the specified position in this `try` statement. */
|
||||
ExprParent getResource(int index) {
|
||||
@@ -350,16 +331,14 @@ class TryStmt extends Stmt,@trystmt {
|
||||
}
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "try " + this.getBlock().pp() + " catch (...)"
|
||||
}
|
||||
override string pp() { result = "try " + this.getBlock().pp() + " catch (...)" }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "TryStmt" }
|
||||
}
|
||||
|
||||
/** A `catch` clause in a `try` statement. */
|
||||
class CatchClause extends Stmt,@catchclause {
|
||||
class CatchClause extends Stmt, @catchclause {
|
||||
/** Gets the block of this `catch` clause. */
|
||||
Block getBlock() { result.getParent() = this }
|
||||
|
||||
@@ -370,9 +349,7 @@ class CatchClause extends Stmt,@catchclause {
|
||||
LocalVariableDeclExpr getVariable() { result.getParent() = this }
|
||||
|
||||
/** Holds if this `catch` clause is a _multi_-`catch` clause. */
|
||||
predicate isMultiCatch() {
|
||||
this.getVariable().getTypeAccess() instanceof UnionTypeAccess
|
||||
}
|
||||
predicate isMultiCatch() { this.getVariable().getTypeAccess() instanceof UnionTypeAccess }
|
||||
|
||||
/** Gets a type caught by this `catch` clause. */
|
||||
RefType getACaughtType() {
|
||||
@@ -383,16 +360,14 @@ class CatchClause extends Stmt,@catchclause {
|
||||
}
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "catch (...) " + this.getBlock().pp()
|
||||
}
|
||||
override string pp() { result = "catch (...) " + this.getBlock().pp() }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "CatchClause" }
|
||||
}
|
||||
|
||||
/** A `switch` statement. */
|
||||
class SwitchStmt extends Stmt,@switchstmt {
|
||||
class SwitchStmt extends Stmt, @switchstmt {
|
||||
/** Gets an immediate child statement of this `switch` statement. */
|
||||
Stmt getAStmt() { result.getParent() = this }
|
||||
|
||||
@@ -418,9 +393,7 @@ class SwitchStmt extends Stmt,@switchstmt {
|
||||
Expr getExpr() { result.getParent() = this }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "switch (...)"
|
||||
}
|
||||
override string pp() { result = "switch (...)" }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "SwitchStmt" }
|
||||
@@ -431,9 +404,7 @@ class SwitchStmt extends Stmt,@switchstmt {
|
||||
*
|
||||
* This includes both normal `case`s and the `default` case.
|
||||
*/
|
||||
class SwitchCase extends Stmt, @case {
|
||||
SwitchStmt getSwitch() { result.getACase() = this }
|
||||
}
|
||||
class SwitchCase extends Stmt, @case { SwitchStmt getSwitch() { result.getACase() = this } }
|
||||
|
||||
/** A constant `case` of a switch statement. */
|
||||
class ConstCase extends SwitchCase {
|
||||
@@ -443,9 +414,7 @@ class ConstCase extends SwitchCase {
|
||||
Expr getValue() { result.getParent() = this }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "case ...:"
|
||||
}
|
||||
override string pp() { result = "case ...:" }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "ConstCase" }
|
||||
@@ -456,16 +425,14 @@ class DefaultCase extends SwitchCase {
|
||||
DefaultCase() { not exists(Expr e | e.getParent() = this) }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "default"
|
||||
}
|
||||
override string pp() { result = "default" }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "DefaultCase" }
|
||||
}
|
||||
|
||||
/** A `synchronized` statement. */
|
||||
class SynchronizedStmt extends Stmt,@synchronizedstmt {
|
||||
class SynchronizedStmt extends Stmt, @synchronizedstmt {
|
||||
/** Gets the expression on which this `synchronized` statement synchronizes. */
|
||||
Expr getExpr() { result.getParent() = this }
|
||||
|
||||
@@ -473,37 +440,31 @@ class SynchronizedStmt extends Stmt,@synchronizedstmt {
|
||||
Stmt getBlock() { result.getParent() = this }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "synchronized (...) " + this.getBlock().pp()
|
||||
}
|
||||
override string pp() { result = "synchronized (...) " + this.getBlock().pp() }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "SynchronizedStmt" }
|
||||
}
|
||||
|
||||
/** A `return` statement. */
|
||||
class ReturnStmt extends Stmt,@returnstmt {
|
||||
class ReturnStmt extends Stmt, @returnstmt {
|
||||
/** Gets the expression returned by this `return` statement, if any. */
|
||||
Expr getResult() { result.getParent() = this }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "return ..."
|
||||
}
|
||||
override string pp() { result = "return ..." }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "ReturnStmt" }
|
||||
}
|
||||
|
||||
/** A `throw` statement. */
|
||||
class ThrowStmt extends Stmt,@throwstmt {
|
||||
class ThrowStmt extends Stmt, @throwstmt {
|
||||
/** Gets the expression thrown by this `throw` statement. */
|
||||
Expr getExpr() { result.getParent() = this }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "throw ..."
|
||||
}
|
||||
override string pp() { result = "throw ..." }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "ThrowStmt" }
|
||||
@@ -522,10 +483,11 @@ class ThrowStmt extends Stmt,@throwstmt {
|
||||
}
|
||||
|
||||
private Stmt findEnclosing() {
|
||||
result = getParent() or
|
||||
result = getParent()
|
||||
or
|
||||
exists(Stmt mid |
|
||||
mid = findEnclosing() and
|
||||
not exists(this.catchClauseForThis((TryStmt)mid)) and
|
||||
not exists(this.catchClauseForThis(mid.(TryStmt))) and
|
||||
result = mid.getParent()
|
||||
)
|
||||
}
|
||||
@@ -533,7 +495,7 @@ class ThrowStmt extends Stmt,@throwstmt {
|
||||
private CatchClause catchClauseForThis(TryStmt try) {
|
||||
result = try.getACatchClause() and
|
||||
result.getEnclosingCallable() = this.getEnclosingCallable() and
|
||||
((RefType)getExpr().getType()).hasSupertype*((RefType)result.getVariable().getType()) and
|
||||
(getExpr().getType().(RefType)).hasSupertype*(result.getVariable().getType().(RefType)) and
|
||||
not this.getParent+() = result
|
||||
}
|
||||
}
|
||||
@@ -554,14 +516,13 @@ class JumpStmt extends Stmt {
|
||||
namestrings(result.getLabel(), _, this)
|
||||
}
|
||||
|
||||
private Stmt getLabelTarget() {
|
||||
result = getTargetLabel().getStmt()
|
||||
}
|
||||
private Stmt getLabelTarget() { result = getTargetLabel().getStmt() }
|
||||
|
||||
private Stmt getAPotentialTarget() {
|
||||
this.getParent+() = result and
|
||||
(
|
||||
result instanceof LoopStmt or
|
||||
result instanceof LoopStmt
|
||||
or
|
||||
this instanceof BreakStmt and result instanceof SwitchStmt
|
||||
)
|
||||
}
|
||||
@@ -575,25 +536,23 @@ class JumpStmt extends Stmt {
|
||||
* Gets the statement that this `break` or `continue` jumps to.
|
||||
*/
|
||||
Stmt getTarget() {
|
||||
result = getLabelTarget() or
|
||||
result = getLabelTarget()
|
||||
or
|
||||
(not exists(getLabelTarget()) and result = getEnclosingTarget())
|
||||
}
|
||||
}
|
||||
|
||||
/** A `break` statement. */
|
||||
class BreakStmt extends Stmt,@breakstmt {
|
||||
class BreakStmt extends Stmt, @breakstmt {
|
||||
/** Gets the label targeted by this `break` statement, if any. */
|
||||
string getLabel() { namestrings(result,_,this) }
|
||||
string getLabel() { namestrings(result, _, this) }
|
||||
|
||||
/** Holds if this `break` statement has an explicit label. */
|
||||
predicate hasLabel() { exists(string s | s = this.getLabel()) }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
if this.hasLabel() then
|
||||
result = "break " + this.getLabel()
|
||||
else
|
||||
result = "break"
|
||||
if this.hasLabel() then result = "break " + this.getLabel() else result = "break"
|
||||
}
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
@@ -601,19 +560,16 @@ class BreakStmt extends Stmt,@breakstmt {
|
||||
}
|
||||
|
||||
/** A `continue` statement. */
|
||||
class ContinueStmt extends Stmt,@continuestmt {
|
||||
class ContinueStmt extends Stmt, @continuestmt {
|
||||
/** Gets the label targeted by this `continue` statement, if any. */
|
||||
string getLabel() { namestrings(result,_,this) }
|
||||
string getLabel() { namestrings(result, _, this) }
|
||||
|
||||
/** Holds if this `continue` statement has an explicit label. */
|
||||
predicate hasLabel() { exists(string s | s = this.getLabel()) }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
if this.hasLabel() then
|
||||
result = "continue " + this.getLabel()
|
||||
else
|
||||
result = "continue"
|
||||
if this.hasLabel() then result = "continue " + this.getLabel() else result = "continue"
|
||||
}
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
@@ -621,11 +577,9 @@ class ContinueStmt extends Stmt,@continuestmt {
|
||||
}
|
||||
|
||||
/** The empty statement. */
|
||||
class EmptyStmt extends Stmt,@emptystmt {
|
||||
class EmptyStmt extends Stmt, @emptystmt {
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = ";"
|
||||
}
|
||||
override string pp() { result = ";" }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "EmptyStmt" }
|
||||
@@ -636,14 +590,12 @@ class EmptyStmt extends Stmt,@emptystmt {
|
||||
*
|
||||
* Certain kinds of expressions may be used as statements by appending a semicolon.
|
||||
*/
|
||||
class ExprStmt extends Stmt,@exprstmt {
|
||||
class ExprStmt extends Stmt, @exprstmt {
|
||||
/** Gets the expression of this expression statement. */
|
||||
Expr getExpr() { result.getParent() = this }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "...;"
|
||||
}
|
||||
override string pp() { result = "...;" }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "ExprStmt" }
|
||||
@@ -653,7 +605,7 @@ class ExprStmt extends Stmt,@exprstmt {
|
||||
getEnclosingCallable() instanceof InitializerMethod and
|
||||
exists(FieldDeclaration fd, Location fdl, Location sl |
|
||||
fdl = fd.getLocation() and sl = getLocation()
|
||||
|
|
||||
|
|
||||
fdl.getFile() = sl.getFile() and
|
||||
fdl.getStartLine() = sl.getStartLine() and
|
||||
fdl.getStartColumn() = sl.getStartColumn()
|
||||
@@ -662,36 +614,31 @@ class ExprStmt extends Stmt,@exprstmt {
|
||||
}
|
||||
|
||||
/** A labeled statement. */
|
||||
class LabeledStmt extends Stmt,@labeledstmt {
|
||||
class LabeledStmt extends Stmt, @labeledstmt {
|
||||
/** Gets the statement of this labeled statement. */
|
||||
Stmt getStmt() { result.getParent() = this }
|
||||
|
||||
/** Gets the label of this labeled statement. */
|
||||
string getLabel() { namestrings(result,_,this) }
|
||||
string getLabel() { namestrings(result, _, this) }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = this.getLabel() + ": " + this.getStmt().pp()
|
||||
}
|
||||
override string pp() { result = this.getLabel() + ": " + this.getStmt().pp() }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = this.getLabel() + ":" }
|
||||
}
|
||||
|
||||
/** An `assert` statement. */
|
||||
class AssertStmt extends Stmt,@assertstmt {
|
||||
class AssertStmt extends Stmt, @assertstmt {
|
||||
/** Gets the boolean expression of this `assert` statement. */
|
||||
Expr getExpr() { exprs(result,_,_,this,_) and result.getIndex() = 0 }
|
||||
Expr getExpr() { exprs(result, _, _, this, _) and result.getIndex() = 0 }
|
||||
|
||||
/** Gets the assertion message expression, if any. */
|
||||
Expr getMessage() { exprs(result,_,_,this,_) and result.getIndex() = 1 }
|
||||
Expr getMessage() { exprs(result, _, _, this, _) and result.getIndex() = 1 }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
if exists(this.getMessage()) then
|
||||
result = "assert ... : ..."
|
||||
else
|
||||
result = "assert ..."
|
||||
if exists(this.getMessage()) then result = "assert ... : ..." else result = "assert ..."
|
||||
}
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
@@ -699,7 +646,7 @@ class AssertStmt extends Stmt,@assertstmt {
|
||||
}
|
||||
|
||||
/** A statement that declares one or more local variables. */
|
||||
class LocalVariableDeclStmt extends Stmt,@localvariabledeclstmt {
|
||||
class LocalVariableDeclStmt extends Stmt, @localvariabledeclstmt {
|
||||
/** Gets a declared variable. */
|
||||
LocalVariableDeclExpr getAVariable() { result.getParent() = this }
|
||||
|
||||
@@ -710,28 +657,22 @@ class LocalVariableDeclStmt extends Stmt,@localvariabledeclstmt {
|
||||
}
|
||||
|
||||
/** Gets an index of a variable declared in this local variable declaration statement. */
|
||||
int getAVariableIndex() {
|
||||
exists(getVariable(result))
|
||||
}
|
||||
int getAVariableIndex() { exists(getVariable(result)) }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "local variable declaration"
|
||||
}
|
||||
override string pp() { result = "local variable declaration" }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "LocalVariableDeclStmt" }
|
||||
}
|
||||
|
||||
/** A statement that declares a local class. */
|
||||
class LocalClassDeclStmt extends Stmt,@localclassdeclstmt {
|
||||
class LocalClassDeclStmt extends Stmt, @localclassdeclstmt {
|
||||
/** Gets the local class declared by this statement. */
|
||||
LocalClass getLocalClass() { isLocalClass(result,this) }
|
||||
LocalClass getLocalClass() { isLocalClass(result, this) }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "local class declaration: " + this.getLocalClass().toString()
|
||||
}
|
||||
override string pp() { result = "local class declaration: " + this.getLocalClass().toString() }
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
override string getHalsteadID() { result = "LocalClassDeclStmt" }
|
||||
@@ -758,7 +699,7 @@ class ThisConstructorInvocationStmt extends Stmt, ConstructorCall, @constructori
|
||||
}
|
||||
|
||||
/** Gets the constructor invoked by this constructor invocation. */
|
||||
override Constructor getConstructor() { callableBinding(this,result) }
|
||||
override Constructor getConstructor() { callableBinding(this, result) }
|
||||
|
||||
override Expr getQualifier() { none() }
|
||||
|
||||
@@ -769,9 +710,7 @@ class ThisConstructorInvocationStmt extends Stmt, ConstructorCall, @constructori
|
||||
override Stmt getEnclosingStmt() { result = this }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "this(...)"
|
||||
}
|
||||
override string pp() { result = "this(...)" }
|
||||
|
||||
/** Gets a printable representation of this statement. */
|
||||
override string toString() { result = pp() }
|
||||
@@ -801,7 +740,7 @@ class SuperConstructorInvocationStmt extends Stmt, ConstructorCall, @superconstr
|
||||
}
|
||||
|
||||
/** Gets the constructor invoked by this constructor invocation. */
|
||||
override Constructor getConstructor() { callableBinding(this,result) }
|
||||
override Constructor getConstructor() { callableBinding(this, result) }
|
||||
|
||||
/** Gets the qualifier expression of this `super(...)` constructor invocation, if any. */
|
||||
override Expr getQualifier() { result.isNthChildOf(this, -1) }
|
||||
@@ -813,9 +752,7 @@ class SuperConstructorInvocationStmt extends Stmt, ConstructorCall, @superconstr
|
||||
override Stmt getEnclosingStmt() { result = this }
|
||||
|
||||
/** Gets a printable representation of this statement. May include more detail than `toString()`. */
|
||||
override string pp() {
|
||||
result = "super(...)"
|
||||
}
|
||||
override string pp() { result = "super(...)" }
|
||||
|
||||
/** Gets a printable representation of this statement. */
|
||||
override string toString() { result = pp() }
|
||||
|
||||
@@ -20,33 +20,32 @@ import JDK
|
||||
cached
|
||||
predicate hasSubtype(RefType t, Type sub) {
|
||||
// Direct subtype.
|
||||
(extendsReftype(sub, t) and t != sub) or
|
||||
implInterface(sub, t) or
|
||||
(extendsReftype(sub, t) and t != sub)
|
||||
or
|
||||
implInterface(sub, t)
|
||||
or
|
||||
// A parameterized type `T<A>` is a subtype of the corresponding raw type `T<>`.
|
||||
(parSubtypeRaw(t, sub) and t != sub) or
|
||||
(parSubtypeRaw(t, sub) and t != sub)
|
||||
or
|
||||
// Array subtyping is covariant.
|
||||
(arraySubtype(t, sub) and t != sub) or
|
||||
(arraySubtype(t, sub) and t != sub)
|
||||
or
|
||||
// Type parameter containment for parameterized types.
|
||||
(parContainmentSubtype(t, sub) and t != sub) or
|
||||
(parContainmentSubtype(t, sub) and t != sub)
|
||||
or
|
||||
// Type variables are subtypes of their upper bounds.
|
||||
(typeVarSubtypeBound(t, sub) and t != sub)
|
||||
}
|
||||
|
||||
private
|
||||
predicate typeVarSubtypeBound(RefType t, TypeVariable tv) {
|
||||
if tv.hasTypeBound() then
|
||||
t = tv.getATypeBound().getType()
|
||||
else
|
||||
t instanceof TypeObject
|
||||
private predicate typeVarSubtypeBound(RefType t, TypeVariable tv) {
|
||||
if tv.hasTypeBound() then t = tv.getATypeBound().getType() else t instanceof TypeObject
|
||||
}
|
||||
|
||||
private
|
||||
predicate parSubtypeRaw(RefType t, ParameterizedType sub) {
|
||||
private predicate parSubtypeRaw(RefType t, ParameterizedType sub) {
|
||||
t = sub.getErasure().(GenericType).getRawType()
|
||||
}
|
||||
|
||||
private
|
||||
predicate arraySubtype(Array sup, Array sub) {
|
||||
private predicate arraySubtype(Array sup, Array sub) {
|
||||
hasSubtype(sup.getComponentType(), sub.getComponentType())
|
||||
}
|
||||
|
||||
@@ -67,10 +66,10 @@ predicate arraySubtype(Array sup, Array sub) {
|
||||
* base case for `typeArgumentsContain` is therefore `n=1` and this allows an
|
||||
* improved join order implemented by `contains01`.
|
||||
*/
|
||||
private
|
||||
predicate parContainmentSubtype(ParameterizedType pt, ParameterizedType psub) {
|
||||
|
||||
private predicate parContainmentSubtype(ParameterizedType pt, ParameterizedType psub) {
|
||||
pt != psub and
|
||||
typeArgumentsContain(_, pt, psub, pt.getNumberOfTypeArguments()-1)
|
||||
typeArgumentsContain(_, pt, psub, pt.getNumberOfTypeArguments() - 1)
|
||||
or
|
||||
typeArgumentsContain0(_, pt, psub)
|
||||
}
|
||||
@@ -78,8 +77,7 @@ predicate parContainmentSubtype(ParameterizedType pt, ParameterizedType psub) {
|
||||
/**
|
||||
* Gets the `index`-th type parameter of `t`, which is a parameterization of `g`.
|
||||
*/
|
||||
private
|
||||
RefType parameterisationTypeArgument(GenericType g, ParameterizedType t, int index) {
|
||||
private RefType parameterisationTypeArgument(GenericType g, ParameterizedType t, int index) {
|
||||
g = t.getGenericType() and
|
||||
result = t.getTypeArgument(index)
|
||||
}
|
||||
@@ -89,7 +87,9 @@ private predicate varianceCandidate(ParameterizedType pt) {
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private RefType parameterisationTypeArgumentVarianceCand(GenericType g, ParameterizedType t, int index) {
|
||||
private RefType parameterisationTypeArgumentVarianceCand(
|
||||
GenericType g, ParameterizedType t, int index
|
||||
) {
|
||||
result = parameterisationTypeArgument(g, t, index) and
|
||||
varianceCandidate(t)
|
||||
}
|
||||
@@ -100,15 +100,18 @@ private RefType parameterisationTypeArgumentVarianceCand(GenericType g, Paramete
|
||||
* being parameterizations of `g`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private
|
||||
predicate typeArgumentsContain(GenericType g, ParameterizedType s, ParameterizedType t, int n) {
|
||||
private predicate typeArgumentsContain(
|
||||
GenericType g, ParameterizedType s, ParameterizedType t, int n
|
||||
) {
|
||||
contains01(g, s, t) and n = 1
|
||||
or
|
||||
contains(g, s, t, n) and
|
||||
typeArgumentsContain(g, s, t, n-1)
|
||||
typeArgumentsContain(g, s, t, n - 1)
|
||||
}
|
||||
|
||||
private predicate typeArgumentsContain0(GenericType g, ParameterizedType sParm, ParameterizedType tParm) {
|
||||
private predicate typeArgumentsContain0(
|
||||
GenericType g, ParameterizedType sParm, ParameterizedType tParm
|
||||
) {
|
||||
exists(RefType s, RefType t |
|
||||
containsAux0(g, tParm, s, t) and
|
||||
s = parameterisationTypeArgument(g, sParm, 0) and
|
||||
@@ -136,14 +139,18 @@ private predicate contains01(GenericType g, ParameterizedType sParm, Parameteriz
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate contains01Aux0(GenericType g, ParameterizedType tParm, RefType s0, RefType t0, RefType t1) {
|
||||
private predicate contains01Aux0(
|
||||
GenericType g, ParameterizedType tParm, RefType s0, RefType t0, RefType t1
|
||||
) {
|
||||
typeArgumentContains(g, s0, t0, 0) and
|
||||
t0 = parameterisationTypeArgument(g, tParm, 0) and
|
||||
t1 = parameterisationTypeArgument(g, tParm, 1)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate contains01Aux1(GenericType g, ParameterizedType sParm, RefType s0, RefType s1, RefType t1) {
|
||||
private predicate contains01Aux1(
|
||||
GenericType g, ParameterizedType sParm, RefType s0, RefType s1, RefType t1
|
||||
) {
|
||||
typeArgumentContains(g, s1, t1, 1) and
|
||||
s0 = parameterisationTypeArgumentVarianceCand(g, sParm, 0) and
|
||||
s1 = parameterisationTypeArgumentVarianceCand(g, sParm, 1)
|
||||
@@ -164,8 +171,7 @@ private predicate containsAux0(GenericType g, ParameterizedType tParm, RefType s
|
||||
*
|
||||
* See JLS 4.5.1, Type Arguments of Parameterized Types.
|
||||
*/
|
||||
private
|
||||
predicate contains(GenericType g, ParameterizedType sParm, ParameterizedType tParm, int n) {
|
||||
private predicate contains(GenericType g, ParameterizedType sParm, ParameterizedType tParm, int n) {
|
||||
exists(RefType s, RefType t |
|
||||
containsAux(g, tParm, n, s, t) and
|
||||
s = parameterisationTypeArgumentVarianceCand(g, sParm, n)
|
||||
@@ -201,19 +207,20 @@ private predicate typeArgumentContainsAux2(GenericType g, RefType s, RefType t,
|
||||
*
|
||||
* See JLS 4.5.1, Type Arguments of Parameterized Types.
|
||||
*/
|
||||
private
|
||||
predicate typeArgumentContainsAux1(RefType s, RefType t, int n) {
|
||||
private predicate typeArgumentContainsAux1(RefType s, RefType t, int n) {
|
||||
exists(int i |
|
||||
s = parameterisationTypeArgumentVarianceCand(_, _, i) and
|
||||
t = parameterisationTypeArgument(_, _, n) and
|
||||
i <= n and n <= i
|
||||
|
|
||||
i <= n and
|
||||
n <= i
|
||||
|
|
||||
exists(RefType tUpperBound | tUpperBound = t.(Wildcard).getUpperBound().getType() |
|
||||
// ? extends T <= ? extends S if T <: S
|
||||
hasSubtypeStar0(s.(Wildcard).getUpperBound().getType(), tUpperBound) or
|
||||
// ? extends T <= ?
|
||||
s.(Wildcard).isUnconstrained()
|
||||
) or
|
||||
)
|
||||
or
|
||||
exists(RefType tLowerBound | tLowerBound = t.(Wildcard).getLowerBound().getType() |
|
||||
// ? super T <= ? super S if s <: T
|
||||
hasSubtypeStar0(tLowerBound, s.(Wildcard).getLowerBound().getType()) or
|
||||
@@ -221,11 +228,14 @@ predicate typeArgumentContainsAux1(RefType s, RefType t, int n) {
|
||||
s.(Wildcard).isUnconstrained() or
|
||||
// ? super T <= ? extends Object
|
||||
wildcardExtendsObject(s)
|
||||
) or
|
||||
)
|
||||
or
|
||||
// T <= T
|
||||
s = t or
|
||||
s = t
|
||||
or
|
||||
// T <= ? extends T
|
||||
hasSubtypeStar0(s.(Wildcard).getUpperBound().getType(), t) or
|
||||
hasSubtypeStar0(s.(Wildcard).getUpperBound().getType(), t)
|
||||
or
|
||||
// T <= ? super T
|
||||
hasSubtypeStar0(t, s.(Wildcard).getLowerBound().getType())
|
||||
)
|
||||
@@ -239,9 +249,7 @@ private predicate wildcardExtendsObject(Wildcard wc) {
|
||||
/**
|
||||
* DEPRECATED: Use `hasSubtype*` instead.
|
||||
*/
|
||||
deprecated predicate hasSubtypeStar(RefType t, RefType sub) {
|
||||
hasSubtype*(t, sub)
|
||||
}
|
||||
deprecated predicate hasSubtypeStar(RefType t, RefType sub) { hasSubtype*(t, sub) }
|
||||
|
||||
private predicate hasSubtypeStar0(RefType t, RefType sub) {
|
||||
sub = t
|
||||
@@ -253,13 +261,13 @@ private predicate hasSubtypeStar0(RefType t, RefType sub) {
|
||||
|
||||
/** Holds if type `t` declares member `m`. */
|
||||
predicate declaresMember(Type t, @member m) {
|
||||
methods(m,_,_,_,t,_)
|
||||
methods(m, _, _, _, t, _)
|
||||
or
|
||||
constrs(m,_,_,_,t,_)
|
||||
constrs(m, _, _, _, t, _)
|
||||
or
|
||||
fields(m,_,_,t,_)
|
||||
fields(m, _, _, t, _)
|
||||
or
|
||||
enclInReftype(m,t) and
|
||||
enclInReftype(m, t) and
|
||||
// Since the type `@member` in the dbscheme includes all `@reftype`s,
|
||||
// anonymous and local classes need to be excluded here.
|
||||
not m instanceof AnonymousClass and
|
||||
@@ -311,9 +319,7 @@ class Array extends RefType, @array {
|
||||
/**
|
||||
* Gets the JVM descriptor for this type, as used in bytecode.
|
||||
*/
|
||||
override string getTypeDescriptor() {
|
||||
result = "[" + this.getComponentType().getTypeDescriptor()
|
||||
}
|
||||
override string getTypeDescriptor() { result = "[" + this.getComponentType().getTypeDescriptor() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,29 +329,27 @@ class Array extends RefType, @array {
|
||||
class RefType extends Type, Annotatable, Modifiable, @reftype {
|
||||
/** Gets the package in which this type is declared. */
|
||||
Package getPackage() {
|
||||
classes(this,_,result,_) or
|
||||
interfaces(this,_,result,_)
|
||||
classes(this, _, result, _) or
|
||||
interfaces(this, _, result, _)
|
||||
}
|
||||
|
||||
/** Gets the type in which this reference type is enclosed, if any. */
|
||||
RefType getEnclosingType() {
|
||||
enclInReftype(this, result)
|
||||
}
|
||||
RefType getEnclosingType() { enclInReftype(this, result) }
|
||||
|
||||
/** Gets the compilation unit in which this type is declared. */
|
||||
override CompilationUnit getCompilationUnit() { result = this.getFile() }
|
||||
|
||||
/** Holds if `t` is an immediate supertype of this type. */
|
||||
predicate hasSupertype(RefType t) { hasSubtype(t,this) }
|
||||
predicate hasSupertype(RefType t) { hasSubtype(t, this) }
|
||||
|
||||
/** Holds if `t` is an immediate subtype of this type. */
|
||||
predicate hasSubtype(RefType t) { hasSubtype(this,t) }
|
||||
predicate hasSubtype(RefType t) { hasSubtype(this, t) }
|
||||
|
||||
/** Gets a direct subtype of this type. */
|
||||
RefType getASubtype() { hasSubtype(this,result) }
|
||||
RefType getASubtype() { hasSubtype(this, result) }
|
||||
|
||||
/** Gets a direct supertype of this type. */
|
||||
RefType getASupertype() { hasSubtype(result,this) }
|
||||
RefType getASupertype() { hasSubtype(result, this) }
|
||||
|
||||
/** Gets a direct or indirect supertype of this type, including itself. */
|
||||
RefType getAnAncestor() { hasSubtype*(result, this) }
|
||||
@@ -413,9 +417,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype {
|
||||
* Holds if this type declares or inherits method `m`, which is declared
|
||||
* in `declaringType`.
|
||||
*/
|
||||
predicate hasMethod(Method m, RefType declaringType) {
|
||||
hasMethod(m, declaringType, false)
|
||||
}
|
||||
predicate hasMethod(Method m, RefType declaringType) { hasMethod(m, declaringType, false) }
|
||||
|
||||
/**
|
||||
* Holds if this type declares or inherits method `m`, which is declared
|
||||
@@ -425,13 +427,14 @@ class RefType extends Type, Annotatable, Modifiable, @reftype {
|
||||
*/
|
||||
cached
|
||||
predicate hasMethod(Method m, RefType declaringType, boolean hidden) {
|
||||
hasNonInterfaceMethod(m, declaringType, hidden) or
|
||||
hasNonInterfaceMethod(m, declaringType, hidden)
|
||||
or
|
||||
hasInterfaceMethod(m, declaringType) and hidden = false
|
||||
}
|
||||
|
||||
private predicate noMethodExtraction() {
|
||||
not methods(_,_,_,_,this,_) and
|
||||
exists(Method m | methods(m,_,_,_,getSourceDeclaration(),_) and m.isInheritable())
|
||||
not methods(_, _, _, _, this, _) and
|
||||
exists(Method m | methods(m, _, _, _, getSourceDeclaration(), _) and m.isInheritable())
|
||||
}
|
||||
|
||||
private predicate canInheritFromSupertype(RefType sup) {
|
||||
@@ -446,25 +449,42 @@ class RefType extends Type, Annotatable, Modifiable, @reftype {
|
||||
}
|
||||
|
||||
private predicate hasNonInterfaceMethod(Method m, RefType declaringType, boolean hidden) {
|
||||
m = getAMethod() and this = declaringType and not declaringType instanceof Interface and hidden = false or
|
||||
m = getAMethod() and
|
||||
this = declaringType and
|
||||
not declaringType instanceof Interface and
|
||||
hidden = false
|
||||
or
|
||||
exists(RefType sup, boolean h1, boolean h2 |
|
||||
(if m.isPackageProtected() and sup.getPackage() != this.getPackage() then h1 = true else h1 = false) and
|
||||
(
|
||||
if m.isPackageProtected() and sup.getPackage() != this.getPackage()
|
||||
then h1 = true
|
||||
else h1 = false
|
||||
) and
|
||||
(not sup instanceof Interface or this instanceof Interface) and
|
||||
canInheritFromSupertype(sup) and
|
||||
sup.hasNonInterfaceMethod(m, declaringType, h2) and
|
||||
hidden = h1.booleanOr(h2) and
|
||||
exists(string signature | methods(m,_,signature,_,_,_) and not methods(_,_,signature,_,this,_)) and
|
||||
exists(string signature |
|
||||
methods(m, _, signature, _, _, _) and not methods(_, _, signature, _, this, _)
|
||||
) and
|
||||
m.isInheritable()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate cannotInheritInterfaceMethod(string signature) {
|
||||
methods(_,_,signature,_,this,_) or
|
||||
exists(Method m | hasNonInterfaceMethod(m, _, false) and methods(m,_,signature,_,_,_))
|
||||
methods(_, _, signature, _, this, _)
|
||||
or
|
||||
exists(Method m | hasNonInterfaceMethod(m, _, false) and methods(m, _, signature, _, _, _))
|
||||
}
|
||||
|
||||
private predicate interfaceMethodCandidateWithSignature(Method m, string signature, RefType declaringType) {
|
||||
m = getAMethod() and this = declaringType and declaringType instanceof Interface and methods(m,_,signature,_,_,_) or
|
||||
private predicate interfaceMethodCandidateWithSignature(
|
||||
Method m, string signature, RefType declaringType
|
||||
) {
|
||||
m = getAMethod() and
|
||||
this = declaringType and
|
||||
declaringType instanceof Interface and
|
||||
methods(m, _, signature, _, _, _)
|
||||
or
|
||||
exists(RefType sup |
|
||||
sup.interfaceMethodCandidateWithSignature(m, signature, declaringType) and
|
||||
not cannotInheritInterfaceMethod(signature) and
|
||||
@@ -500,12 +520,14 @@ class RefType extends Type, Annotatable, Modifiable, @reftype {
|
||||
/** Holds if this type declares or inherits the specified member. */
|
||||
predicate inherits(Member m) {
|
||||
exists(Field f | f = m |
|
||||
f = getAField() or
|
||||
not f.isPrivate() and not declaresField(f.getName()) and getASupertype().inherits(f) or
|
||||
f = getAField()
|
||||
or
|
||||
not f.isPrivate() and not declaresField(f.getName()) and getASupertype().inherits(f)
|
||||
or
|
||||
getSourceDeclaration().inherits(f)
|
||||
)
|
||||
or
|
||||
hasMethod((Method)m, _)
|
||||
hasMethod(m.(Method), _)
|
||||
}
|
||||
|
||||
/** Holds if this is a top-level type, which is not nested inside any other types. */
|
||||
@@ -521,7 +543,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype {
|
||||
*/
|
||||
override string getTypeDescriptor() {
|
||||
result = "L" + this.getPackage().getName().replaceAll(".", "/") + "/" +
|
||||
this.getSourceDeclaration().nestedName() + ";"
|
||||
this.getSourceDeclaration().nestedName() + ";"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -529,10 +551,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype {
|
||||
*/
|
||||
string getQualifiedName() {
|
||||
exists(string pkgName | pkgName = getPackage().getName() |
|
||||
if pkgName = "" then
|
||||
result = nestedName()
|
||||
else
|
||||
result = pkgName + "." + nestedName()
|
||||
if pkgName = "" then result = nestedName() else result = pkgName + "." + nestedName()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -583,19 +602,17 @@ class RefType extends Type, Annotatable, Modifiable, @reftype {
|
||||
}
|
||||
|
||||
/** A type that is the same as its source declaration. */
|
||||
class SrcRefType extends RefType {
|
||||
SrcRefType() { this.isSourceDeclaration() }
|
||||
}
|
||||
class SrcRefType extends RefType { SrcRefType() { this.isSourceDeclaration() } }
|
||||
|
||||
/** A class declaration. */
|
||||
class Class extends RefType, @class {
|
||||
/** Holds if this class is an anonymous class. */
|
||||
predicate isAnonymous() { isAnonymClass(this,_) }
|
||||
predicate isAnonymous() { isAnonymClass(this, _) }
|
||||
|
||||
/** Holds if this class is a local class. */
|
||||
predicate isLocal() { isLocalClass(this,_) }
|
||||
predicate isLocal() { isLocalClass(this, _) }
|
||||
|
||||
override RefType getSourceDeclaration() { classes(this,_,_,result) }
|
||||
override RefType getSourceDeclaration() { classes(this, _, _, result) }
|
||||
|
||||
/**
|
||||
* Gets an annotation that applies to this class.
|
||||
@@ -603,7 +620,8 @@ class Class extends RefType, @class {
|
||||
* Note that a class may inherit annotations from super-classes.
|
||||
*/
|
||||
override Annotation getAnAnnotation() {
|
||||
result = RefType.super.getAnAnnotation() or
|
||||
result = RefType.super.getAnAnnotation()
|
||||
or
|
||||
exists(AnnotationType tp | tp = result.getType() |
|
||||
tp.isInherited() and
|
||||
not exists(Annotation ann | ann = RefType.super.getAnAnnotation() | ann.getType() = tp) and
|
||||
@@ -620,14 +638,16 @@ class IntersectionType extends RefType, @class {
|
||||
shortname.matches("% & ...")
|
||||
)
|
||||
}
|
||||
|
||||
private RefType superType() { extendsReftype(this, result) }
|
||||
|
||||
private RefType superInterface() { implInterface(this, result) }
|
||||
|
||||
string getLongName() {
|
||||
result = superType().toString() + concat(" & " + superInterface().toString())
|
||||
}
|
||||
RefType getFirstBound() {
|
||||
extendsReftype(this, result)
|
||||
}
|
||||
|
||||
RefType getFirstBound() { extendsReftype(this, result) }
|
||||
}
|
||||
|
||||
/** An anonymous class. */
|
||||
@@ -656,7 +676,9 @@ class AnonymousClass extends NestedClass {
|
||||
*/
|
||||
override string getTypeDescriptor() {
|
||||
exists(RefType parent | parent = this.getEnclosingType() |
|
||||
exists(int num | num = 1 + count(AnonymousClass other | other.rankInParent(parent) < rankInParent(parent)) |
|
||||
exists(int num |
|
||||
num = 1 + count(AnonymousClass other | other.rankInParent(parent) < rankInParent(parent))
|
||||
|
|
||||
exists(string parentWithSemi | parentWithSemi = parent.getTypeDescriptor() |
|
||||
result = parentWithSemi.prefix(parentWithSemi.length() - 1) + "$" + num + ";"
|
||||
)
|
||||
@@ -667,7 +689,9 @@ class AnonymousClass extends NestedClass {
|
||||
/** Gets the class instance expression where this anonymous class occurs. */
|
||||
ClassInstanceExpr getClassInstanceExpr() { isAnonymClass(this, result) }
|
||||
|
||||
override string toString() { result = "new " + this.getClassInstanceExpr().getTypeName() + "(...) { ... }" }
|
||||
override string toString() {
|
||||
result = "new " + this.getClassInstanceExpr().getTypeName() + "(...) { ... }"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the qualified name of this type.
|
||||
@@ -689,32 +713,26 @@ class LocalClass extends NestedClass {
|
||||
/** A top-level type. */
|
||||
class TopLevelType extends RefType {
|
||||
TopLevelType() {
|
||||
not enclInReftype(this,_) and
|
||||
not enclInReftype(this, _) and
|
||||
(this instanceof Class or this instanceof Interface)
|
||||
}
|
||||
}
|
||||
|
||||
/** A top-level class. */
|
||||
class TopLevelClass extends TopLevelType, Class {
|
||||
}
|
||||
class TopLevelClass extends TopLevelType, Class { }
|
||||
|
||||
/** A nested type is a type declared within another type. */
|
||||
class NestedType extends RefType {
|
||||
NestedType() {
|
||||
enclInReftype(this,_)
|
||||
}
|
||||
NestedType() { enclInReftype(this, _) }
|
||||
|
||||
/** Gets the type enclosing this nested type. */
|
||||
override RefType getEnclosingType() {
|
||||
enclInReftype(this,result)
|
||||
}
|
||||
override RefType getEnclosingType() { enclInReftype(this, result) }
|
||||
|
||||
/** Gets the nesting depth of this nested type. Top-level types have nesting depth 0. */
|
||||
int getNestingDepth() {
|
||||
if getEnclosingType() instanceof NestedType then
|
||||
result = getEnclosingType().(NestedType).getNestingDepth() + 1
|
||||
else
|
||||
result = 1
|
||||
if getEnclosingType() instanceof NestedType
|
||||
then result = getEnclosingType().(NestedType).getNestingDepth() + 1
|
||||
else result = 1
|
||||
}
|
||||
|
||||
override predicate isPublic() {
|
||||
@@ -760,17 +778,14 @@ class NestedType extends RefType {
|
||||
* This includes (static and non-static) member classes,
|
||||
* local classes and anonymous classes.
|
||||
*/
|
||||
class NestedClass extends NestedType, Class {
|
||||
}
|
||||
class NestedClass extends NestedType, Class { }
|
||||
|
||||
/**
|
||||
* An inner class is a nested class that is neither
|
||||
* explicitly nor implicitly declared static.
|
||||
*/
|
||||
class InnerClass extends NestedClass {
|
||||
InnerClass() {
|
||||
not this.isStatic()
|
||||
}
|
||||
InnerClass() { not this.isStatic() }
|
||||
|
||||
/**
|
||||
* Holds if an instance of this inner class holds a reference to its
|
||||
@@ -785,7 +800,7 @@ class InnerClass extends NestedClass {
|
||||
|
||||
/** An interface. */
|
||||
class Interface extends RefType, @interface {
|
||||
override RefType getSourceDeclaration() { interfaces(this,_,_,result) }
|
||||
override RefType getSourceDeclaration() { interfaces(this, _, _, result) }
|
||||
|
||||
override predicate isAbstract() {
|
||||
// JLS 9.1.1.1: "Every interface is implicitly abstract"
|
||||
@@ -809,26 +824,29 @@ class ClassOrInterface extends RefType {
|
||||
* and `double`.
|
||||
*/
|
||||
class PrimitiveType extends Type, @primitive {
|
||||
PrimitiveType() {
|
||||
this.getName().regexpMatch("float|double|int|boolean|short|byte|char|long")
|
||||
}
|
||||
PrimitiveType() { this.getName().regexpMatch("float|double|int|boolean|short|byte|char|long") }
|
||||
|
||||
/** Gets the boxed type corresponding to this primitive type. */
|
||||
BoxedType getBoxedType() {
|
||||
result.getPrimitiveType() = this
|
||||
}
|
||||
BoxedType getBoxedType() { result.getPrimitiveType() = this }
|
||||
|
||||
/**
|
||||
* Gets the JVM descriptor for this type, as used in bytecode.
|
||||
*/
|
||||
override string getTypeDescriptor() {
|
||||
(this.hasName("float") and result = "F") or
|
||||
(this.hasName("double") and result = "D") or
|
||||
(this.hasName("int") and result = "I") or
|
||||
(this.hasName("boolean") and result = "Z") or
|
||||
(this.hasName("short") and result = "S") or
|
||||
(this.hasName("byte") and result = "B") or
|
||||
(this.hasName("char") and result = "C") or
|
||||
(this.hasName("float") and result = "F")
|
||||
or
|
||||
(this.hasName("double") and result = "D")
|
||||
or
|
||||
(this.hasName("int") and result = "I")
|
||||
or
|
||||
(this.hasName("boolean") and result = "Z")
|
||||
or
|
||||
(this.hasName("short") and result = "S")
|
||||
or
|
||||
(this.hasName("byte") and result = "B")
|
||||
or
|
||||
(this.hasName("char") and result = "C")
|
||||
or
|
||||
(this.hasName("long") and result = "J")
|
||||
}
|
||||
|
||||
@@ -842,16 +860,18 @@ class PrimitiveType extends Type, @primitive {
|
||||
* require an explicit cast.
|
||||
*/
|
||||
Literal getADefaultValue() {
|
||||
getName() = "boolean" and result.getLiteral() = "false" or
|
||||
getName() = "char" and (result.getLiteral() = "'\\0'" or result.getLiteral() = "'\\u0000'") or
|
||||
getName().regexpMatch("(float|double|int|short|byte|long)") and result.getLiteral().regexpMatch("0(\\.0)?+[lLfFdD]?+")
|
||||
getName() = "boolean" and result.getLiteral() = "false"
|
||||
or
|
||||
getName() = "char" and
|
||||
(result.getLiteral() = "'\\0'" or result.getLiteral() = "'\\u0000'")
|
||||
or
|
||||
getName().regexpMatch("(float|double|int|short|byte|long)") and
|
||||
result.getLiteral().regexpMatch("0(\\.0)?+[lLfFdD]?+")
|
||||
}
|
||||
}
|
||||
|
||||
/** The type of the `null` literal. */
|
||||
class NullType extends Type, @primitive {
|
||||
NullType() { this.hasName("<nulltype>") }
|
||||
}
|
||||
class NullType extends Type, @primitive { NullType() { this.hasName("<nulltype>") } }
|
||||
|
||||
/** The `void` type. */
|
||||
class VoidType extends Type, @primitive {
|
||||
@@ -860,9 +880,7 @@ class VoidType extends Type, @primitive {
|
||||
/**
|
||||
* Gets the JVM descriptor for this type, as used in bytecode.
|
||||
*/
|
||||
override string getTypeDescriptor() {
|
||||
result = "V"
|
||||
}
|
||||
override string getTypeDescriptor() { result = "V" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -886,13 +904,20 @@ class BoxedType extends RefType {
|
||||
|
||||
/** Gets the primitive type corresponding to this boxed type. */
|
||||
PrimitiveType getPrimitiveType() {
|
||||
(this.hasName("Float") and result.hasName("float")) or
|
||||
(this.hasName("Double") and result.hasName("double")) or
|
||||
(this.hasName("Integer") and result.hasName("int")) or
|
||||
(this.hasName("Boolean") and result.hasName("boolean")) or
|
||||
(this.hasName("Short") and result.hasName("short")) or
|
||||
(this.hasName("Byte") and result.hasName("byte")) or
|
||||
(this.hasName("Character") and result.hasName("char")) or
|
||||
(this.hasName("Float") and result.hasName("float"))
|
||||
or
|
||||
(this.hasName("Double") and result.hasName("double"))
|
||||
or
|
||||
(this.hasName("Integer") and result.hasName("int"))
|
||||
or
|
||||
(this.hasName("Boolean") and result.hasName("boolean"))
|
||||
or
|
||||
(this.hasName("Short") and result.hasName("short"))
|
||||
or
|
||||
(this.hasName("Byte") and result.hasName("byte"))
|
||||
or
|
||||
(this.hasName("Character") and result.hasName("char"))
|
||||
or
|
||||
(this.hasName("Long") and result.hasName("long"))
|
||||
}
|
||||
}
|
||||
@@ -917,13 +942,11 @@ class EnumType extends Class {
|
||||
|
||||
/** Gets the enum constant with the specified name. */
|
||||
EnumConstant getEnumConstant(string name) {
|
||||
fields(result,_,_,this,_) and result.hasName(name)
|
||||
fields(result, _, _, this, _) and result.hasName(name)
|
||||
}
|
||||
|
||||
/** Gets an enum constant declared in this enum type. */
|
||||
EnumConstant getAnEnumConstant() {
|
||||
fields(result,_,_,this,_)
|
||||
}
|
||||
EnumConstant getAnEnumConstant() { fields(result, _, _, this, _) }
|
||||
|
||||
override predicate isFinal() {
|
||||
// JLS 8.9: An enum declaration is implicitly `final` unless it contains
|
||||
@@ -940,7 +963,9 @@ class EnumConstant extends Field {
|
||||
// [enum type] `E`, `E` has an implicitly declared `public static final`
|
||||
// field of type `E` that has the same name as `c`.
|
||||
override predicate isPublic() { any() }
|
||||
|
||||
override predicate isStatic() { any() }
|
||||
|
||||
override predicate isFinal() { any() }
|
||||
}
|
||||
|
||||
@@ -949,15 +974,23 @@ class EnumConstant extends Field {
|
||||
*
|
||||
* See JLS v8, section 4.6 (Type Erasure).
|
||||
*/
|
||||
private cached Type erase(Type t) {
|
||||
result = t.(Class).getSourceDeclaration() and not t instanceof IntersectionType or
|
||||
result = erase(t.(IntersectionType).getFirstBound()) or
|
||||
result = t.(Interface).getSourceDeclaration() or
|
||||
result.(Array).getComponentType() = erase(t.(Array).getComponentType()) or
|
||||
result = erase(t.(BoundedType).getFirstUpperBoundType()) or
|
||||
result = (NullType)t or
|
||||
result = (VoidType)t or
|
||||
result = (PrimitiveType)t
|
||||
cached
|
||||
private Type erase(Type t) {
|
||||
result = t.(Class).getSourceDeclaration() and not t instanceof IntersectionType
|
||||
or
|
||||
result = erase(t.(IntersectionType).getFirstBound())
|
||||
or
|
||||
result = t.(Interface).getSourceDeclaration()
|
||||
or
|
||||
result.(Array).getComponentType() = erase(t.(Array).getComponentType())
|
||||
or
|
||||
result = erase(t.(BoundedType).getFirstUpperBoundType())
|
||||
or
|
||||
result = t.(NullType)
|
||||
or
|
||||
result = t.(VoidType)
|
||||
or
|
||||
result = t.(PrimitiveType)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -984,7 +1017,9 @@ predicate haveIntersection(RefType t1, RefType t2) {
|
||||
* types `t1` and `t2`.
|
||||
*/
|
||||
predicate erasedHaveIntersection(RefType t1, RefType t2) {
|
||||
exists(SrcRefType commonSub | commonSub.getASourceSupertype*() = t1 and commonSub.getASourceSupertype*() = t2) and
|
||||
exists(SrcRefType commonSub |
|
||||
commonSub.getASourceSupertype*() = t1 and commonSub.getASourceSupertype*() = t2
|
||||
) and
|
||||
t1 = erase(_) and
|
||||
t2 = erase(_)
|
||||
}
|
||||
@@ -994,7 +1029,7 @@ class IntegralType extends Type {
|
||||
IntegralType() {
|
||||
exists(string name |
|
||||
name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName()
|
||||
|
|
||||
|
|
||||
name.regexpMatch("byte|char|short|int|long")
|
||||
)
|
||||
}
|
||||
@@ -1005,7 +1040,7 @@ class BooleanType extends Type {
|
||||
BooleanType() {
|
||||
exists(string name |
|
||||
name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName()
|
||||
|
|
||||
|
|
||||
name = "boolean"
|
||||
)
|
||||
}
|
||||
@@ -1016,7 +1051,7 @@ class CharacterType extends Type {
|
||||
CharacterType() {
|
||||
exists(string name |
|
||||
name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName()
|
||||
|
|
||||
|
|
||||
name = "char"
|
||||
)
|
||||
}
|
||||
@@ -1027,7 +1062,7 @@ class NumericOrCharType extends Type {
|
||||
NumericOrCharType() {
|
||||
exists(string name |
|
||||
name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName()
|
||||
|
|
||||
|
|
||||
name.regexpMatch("byte|char|short|int|long|double|float")
|
||||
)
|
||||
}
|
||||
@@ -1038,7 +1073,7 @@ class FloatingPointType extends Type {
|
||||
FloatingPointType() {
|
||||
exists(string name |
|
||||
name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName()
|
||||
|
|
||||
|
|
||||
name.regexpMatch("float|double")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,30 +8,22 @@ import semmle.code.java.frameworks.JUnitAnnotations
|
||||
|
||||
/** The Java class `junit.framework.TestCase`. */
|
||||
class TypeJUnitTestCase extends RefType {
|
||||
TypeJUnitTestCase() {
|
||||
this.hasQualifiedName("junit.framework", "TestCase")
|
||||
}
|
||||
TypeJUnitTestCase() { this.hasQualifiedName("junit.framework", "TestCase") }
|
||||
}
|
||||
|
||||
/** The Java interface `junit.framework.Test`. */
|
||||
class TypeJUnitTest extends RefType {
|
||||
TypeJUnitTest() {
|
||||
this.hasQualifiedName("junit.framework", "Test")
|
||||
}
|
||||
TypeJUnitTest() { this.hasQualifiedName("junit.framework", "Test") }
|
||||
}
|
||||
|
||||
/** The Java class `junit.framework.TestSuite`. */
|
||||
class TypeJUnitTestSuite extends RefType {
|
||||
TypeJUnitTestSuite() {
|
||||
this.hasQualifiedName("junit.framework", "TestSuite")
|
||||
}
|
||||
TypeJUnitTestSuite() { this.hasQualifiedName("junit.framework", "TestSuite") }
|
||||
}
|
||||
|
||||
/** A JUnit 3.8 test class. */
|
||||
class JUnit38TestClass extends Class {
|
||||
JUnit38TestClass() {
|
||||
exists(TypeJUnitTestCase tc | this.hasSupertype+(tc))
|
||||
}
|
||||
JUnit38TestClass() { exists(TypeJUnitTestCase tc | this.hasSupertype+(tc)) }
|
||||
}
|
||||
|
||||
/** A JUnit 3.8 `tearDown` method. */
|
||||
@@ -40,9 +32,7 @@ class TearDownMethod extends Method {
|
||||
this.hasName("tearDown") and
|
||||
this.hasNoParameters() and
|
||||
this.getReturnType().hasName("void") and
|
||||
exists(Method m | m.getDeclaringType() instanceof TypeJUnitTestCase |
|
||||
this.overrides*(m)
|
||||
)
|
||||
exists(Method m | m.getDeclaringType() instanceof TypeJUnitTestCase | this.overrides*(m))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,14 +77,11 @@ class JUnit3TestSuite extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A JUnit test method that is annotated with the `org.junit.Test` annotation.
|
||||
*/
|
||||
class JUnit4TestMethod extends Method {
|
||||
JUnit4TestMethod() {
|
||||
this.getAnAnnotation().getType().hasQualifiedName("org.junit", "Test")
|
||||
}
|
||||
JUnit4TestMethod() { this.getAnAnnotation().getType().hasQualifiedName("org.junit", "Test") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,9 +97,7 @@ class JUnitJupiterTestMethod extends Method {
|
||||
* A JUnit `@Ignore` annotation.
|
||||
*/
|
||||
class JUnitIgnoreAnnotation extends Annotation {
|
||||
JUnitIgnoreAnnotation() {
|
||||
getType().hasQualifiedName("org.junit", "Ignore")
|
||||
}
|
||||
JUnitIgnoreAnnotation() { getType().hasQualifiedName("org.junit", "Ignore") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,10 +106,9 @@ class JUnitIgnoreAnnotation extends Annotation {
|
||||
*/
|
||||
class JUnitIgnoredMethod extends Method {
|
||||
JUnitIgnoredMethod() {
|
||||
getAnAnnotation() instanceof JUnitIgnoreAnnotation or
|
||||
exists(Class c |
|
||||
c = this.getDeclaringType()
|
||||
|
|
||||
getAnAnnotation() instanceof JUnitIgnoreAnnotation
|
||||
or
|
||||
exists(Class c | c = this.getDeclaringType() |
|
||||
c.getAnAnnotation() instanceof JUnitIgnoreAnnotation
|
||||
)
|
||||
}
|
||||
@@ -134,27 +118,21 @@ class JUnitIgnoredMethod extends Method {
|
||||
* An annotation in TestNG.
|
||||
*/
|
||||
class TestNGAnnotation extends Annotation {
|
||||
TestNGAnnotation() {
|
||||
getType().getPackage().hasName("org.testng.annotations")
|
||||
}
|
||||
TestNGAnnotation() { getType().getPackage().hasName("org.testng.annotations") }
|
||||
}
|
||||
|
||||
/**
|
||||
* An annotation of type `org.test.ng.annotations.Test`.
|
||||
*/
|
||||
class TestNGTestAnnotation extends TestNGAnnotation {
|
||||
TestNGTestAnnotation() {
|
||||
getType().hasName("Test")
|
||||
}
|
||||
TestNGTestAnnotation() { getType().hasName("Test") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A TestNG test method, annotated with the `org.testng.annotations.Test` annotation.
|
||||
*/
|
||||
class TestNGTestMethod extends Method {
|
||||
TestNGTestMethod() {
|
||||
this.getAnAnnotation() instanceof TestNGTestAnnotation
|
||||
}
|
||||
TestNGTestMethod() { this.getAnAnnotation() instanceof TestNGTestAnnotation }
|
||||
|
||||
/**
|
||||
* Identify a possible `DataProvider` for this method, if the annotation includes a `dataProvider`
|
||||
@@ -164,12 +142,19 @@ class TestNGTestMethod extends Method {
|
||||
exists(TestNGTestAnnotation testAnnotation |
|
||||
testAnnotation = getAnAnnotation() and
|
||||
// The data provider must have the same name as the referenced data provider
|
||||
result.getDataProviderName() = testAnnotation.getValue("dataProvider").(StringLiteral).getRepresentedString()
|
||||
|
|
||||
result.getDataProviderName() = testAnnotation
|
||||
.getValue("dataProvider")
|
||||
.(StringLiteral)
|
||||
.getRepresentedString()
|
||||
|
|
||||
// Either the data provider should be on the current class, or a supertype
|
||||
getDeclaringType().getAnAncestor() = result.getDeclaringType() or
|
||||
// Or the data provider class should be declared
|
||||
result.getDeclaringType() = testAnnotation.getValue("dataProviderClass").(TypeLiteral).getTypeName().getType()
|
||||
result.getDeclaringType() = testAnnotation
|
||||
.getValue("dataProviderClass")
|
||||
.(TypeLiteral)
|
||||
.getTypeName()
|
||||
.getType()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -191,18 +176,14 @@ class TestMethod extends Method {
|
||||
* A TestNG annotation used to mark a method that runs "before".
|
||||
*/
|
||||
class TestNGBeforeAnnotation extends TestNGAnnotation {
|
||||
TestNGBeforeAnnotation() {
|
||||
getType().getName().matches("Before%")
|
||||
}
|
||||
TestNGBeforeAnnotation() { getType().getName().matches("Before%") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A TestNG annotation used to mark a method that runs "after".
|
||||
*/
|
||||
class TestNGAfterAnnotation extends TestNGAnnotation {
|
||||
TestNGAfterAnnotation() {
|
||||
getType().getName().matches("After%")
|
||||
}
|
||||
TestNGAfterAnnotation() { getType().getName().matches("After%") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,9 +191,7 @@ class TestNGAfterAnnotation extends TestNGAnnotation {
|
||||
* them as data provider methods for TestNG.
|
||||
*/
|
||||
class TestNGDataProviderAnnotation extends TestNGAnnotation {
|
||||
TestNGDataProviderAnnotation() {
|
||||
getType().hasName("DataProvider")
|
||||
}
|
||||
TestNGDataProviderAnnotation() { getType().hasName("DataProvider") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,9 +199,7 @@ class TestNGDataProviderAnnotation extends TestNGAnnotation {
|
||||
* them as factory methods for TestNG.
|
||||
*/
|
||||
class TestNGFactoryAnnotation extends TestNGAnnotation {
|
||||
TestNGFactoryAnnotation() {
|
||||
getType().hasName("Factory")
|
||||
}
|
||||
TestNGFactoryAnnotation() { getType().hasName("Factory") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,9 +207,7 @@ class TestNGFactoryAnnotation extends TestNGAnnotation {
|
||||
* which listeners apply to them.
|
||||
*/
|
||||
class TestNGListenersAnnotation extends TestNGAnnotation {
|
||||
TestNGListenersAnnotation() {
|
||||
getType().hasName("Listeners")
|
||||
}
|
||||
TestNGListenersAnnotation() { getType().hasName("Listeners") }
|
||||
|
||||
/**
|
||||
* Gets a listener defined in this annotation.
|
||||
@@ -246,9 +221,7 @@ class TestNGListenersAnnotation extends TestNGAnnotation {
|
||||
* A concrete implementation class of one or more of the TestNG listener interfaces.
|
||||
*/
|
||||
class TestNGListenerImpl extends Class {
|
||||
TestNGListenerImpl() {
|
||||
getAnAncestor().hasQualifiedName("org.testng", "ITestNGListener")
|
||||
}
|
||||
TestNGListenerImpl() { getAnAncestor().hasQualifiedName("org.testng", "ITestNGListener") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,15 +232,17 @@ class TestNGListenerImpl extends Class {
|
||||
* an instance of a particular value when running a test method.
|
||||
*/
|
||||
class TestNGDataProviderMethod extends Method {
|
||||
TestNGDataProviderMethod() {
|
||||
getAnAnnotation() instanceof TestNGDataProviderAnnotation
|
||||
}
|
||||
TestNGDataProviderMethod() { getAnAnnotation() instanceof TestNGDataProviderAnnotation }
|
||||
|
||||
/**
|
||||
* Gets the name associated with this data provider.
|
||||
*/
|
||||
string getDataProviderName() {
|
||||
result = getAnAnnotation().(TestNGDataProviderAnnotation).getValue("name").(StringLiteral).getRepresentedString()
|
||||
result = getAnAnnotation()
|
||||
.(TestNGDataProviderAnnotation)
|
||||
.getValue("name")
|
||||
.(StringLiteral)
|
||||
.getRepresentedString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,9 +253,7 @@ class TestNGDataProviderMethod extends Method {
|
||||
* This factory callable is used to generate instances of parameterized test classes.
|
||||
*/
|
||||
class TestNGFactoryCallable extends Callable {
|
||||
TestNGFactoryCallable() {
|
||||
getAnAnnotation() instanceof TestNGFactoryAnnotation
|
||||
}
|
||||
TestNGFactoryCallable() { getAnAnnotation() instanceof TestNGFactoryAnnotation }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,7 +261,11 @@ class TestNGFactoryCallable extends Callable {
|
||||
*/
|
||||
class ParameterizedJUnitTest extends Class {
|
||||
ParameterizedJUnitTest() {
|
||||
getAnAnnotation().(RunWithAnnotation).getRunner().(Class).hasQualifiedName("org.junit.runners", "Parameterized")
|
||||
getAnAnnotation()
|
||||
.(RunWithAnnotation)
|
||||
.getRunner()
|
||||
.(Class)
|
||||
.hasQualifiedName("org.junit.runners", "Parameterized")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +286,8 @@ class JUnitCategoryAnnotation extends Annotation {
|
||||
(
|
||||
literal = value or
|
||||
literal = value.(ArrayCreationExpr).getInit().getAnInit()
|
||||
) |
|
||||
)
|
||||
|
|
||||
result = literal.getTypeName().getType()
|
||||
)
|
||||
}
|
||||
@@ -320,6 +298,10 @@ class JUnitCategoryAnnotation extends Annotation {
|
||||
*/
|
||||
class JUnitTheoryTest extends Class {
|
||||
JUnitTheoryTest() {
|
||||
getAnAnnotation().(RunWithAnnotation).getRunner().(Class).hasQualifiedName("org.junit.experimental.theories", "Theories")
|
||||
getAnAnnotation()
|
||||
.(RunWithAnnotation)
|
||||
.getRunner()
|
||||
.(Class)
|
||||
.hasQualifiedName("org.junit.experimental.theories", "Theories")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,24 +10,22 @@ class Variable extends @variable, Annotatable, Element, Modifiable {
|
||||
/*abstract*/ Type getType() { none() }
|
||||
|
||||
/** Gets an access to this variable. */
|
||||
VarAccess getAnAccess() { variableBinding(result,this) }
|
||||
VarAccess getAnAccess() { variableBinding(result, this) }
|
||||
|
||||
/** Gets an expression on the right-hand side of an assignment to this variable. */
|
||||
Expr getAnAssignedValue() {
|
||||
exists(LocalVariableDeclExpr e | e.getVariable() = this and result = e.getInit())
|
||||
or
|
||||
exists(AssignExpr e | e.getDest().getProperExpr() = this.getAnAccess() and result = e.getSource())
|
||||
exists(AssignExpr e |
|
||||
e.getDest().getProperExpr() = this.getAnAccess() and result = e.getSource()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the initializer expression of this variable. */
|
||||
Expr getInitializer() {
|
||||
none()
|
||||
}
|
||||
Expr getInitializer() { none() }
|
||||
|
||||
/** Gets a printable representation of this variable together with its type. */
|
||||
string pp() {
|
||||
result = this.getType().getName() + " " + this.getName()
|
||||
}
|
||||
string pp() { result = this.getType().getName() + " " + this.getName() }
|
||||
}
|
||||
|
||||
/** A locally scoped variable, that is, either a local variable or a parameter. */
|
||||
@@ -39,13 +37,13 @@ class LocalScopeVariable extends Variable, @localscopevariable {
|
||||
/** A local variable declaration */
|
||||
class LocalVariableDecl extends @localvar, LocalScopeVariable {
|
||||
/** Gets the type of this local variable. */
|
||||
override Type getType() { localvars(this,_,result,_) }
|
||||
override Type getType() { localvars(this, _, result, _) }
|
||||
|
||||
/** Gets the expression declaring this variable. */
|
||||
LocalVariableDeclExpr getDeclExpr() { localvars(this, _, _, result) }
|
||||
|
||||
/** Gets the parent of this declaration. */
|
||||
Expr getParent() { localvars(this,_,_,result) }
|
||||
Expr getParent() { localvars(this, _, _, result) }
|
||||
|
||||
/** Gets the callable in which this declaration occurs. */
|
||||
override Callable getCallable() { result = this.getParent().getEnclosingCallable() }
|
||||
@@ -56,35 +54,31 @@ class LocalVariableDecl extends @localvar, LocalScopeVariable {
|
||||
override string toString() { result = this.getType().getName() + " " + this.getName() }
|
||||
|
||||
/** Gets the initializer expression of this local variable declaration. */
|
||||
override Expr getInitializer() {
|
||||
result = getDeclExpr().getInit()
|
||||
}
|
||||
override Expr getInitializer() { result = getDeclExpr().getInit() }
|
||||
}
|
||||
|
||||
/** A formal parameter of a callable. */
|
||||
class Parameter extends Element, @param, LocalScopeVariable {
|
||||
/** Gets the type of this formal parameter. */
|
||||
override Type getType() { params(this,result,_,_,_) }
|
||||
override Type getType() { params(this, result, _, _, _) }
|
||||
|
||||
/** Holds if the parameter is never assigned a value in the body of the callable. */
|
||||
predicate isEffectivelyFinal() { not exists(getAnAssignedValue()) }
|
||||
|
||||
/** Gets the (zero-based) index of this formal parameter. */
|
||||
int getPosition() { params(this,_,result,_,_) }
|
||||
int getPosition() { params(this, _, result, _, _) }
|
||||
|
||||
/** Gets the callable that declares this formal parameter. */
|
||||
override Callable getCallable() { params(this,_,_,result,_) }
|
||||
override Callable getCallable() { params(this, _, _, result, _) }
|
||||
|
||||
/** Gets the source declaration of this formal parameter. */
|
||||
Parameter getSourceDeclaration() { params(this,_,_,_,result) }
|
||||
Parameter getSourceDeclaration() { params(this, _, _, _, result) }
|
||||
|
||||
/** Holds if this formal parameter is the same as its source declaration. */
|
||||
predicate isSourceDeclaration() { this.getSourceDeclaration() = this }
|
||||
|
||||
/** Holds if this formal parameter is a variable arity parameter. */
|
||||
predicate isVarargs() {
|
||||
isVarargsParam(this)
|
||||
}
|
||||
predicate isVarargs() { isVarargsParam(this) }
|
||||
|
||||
/**
|
||||
* Gets an argument for this parameter in any call to the callable that declares this formal
|
||||
@@ -97,7 +91,8 @@ class Parameter extends Element, @param, LocalScopeVariable {
|
||||
result = getACallArgument(getPosition())
|
||||
}
|
||||
|
||||
private pragma[noinline] Expr getACallArgument(int i) {
|
||||
pragma[noinline]
|
||||
private Expr getACallArgument(int i) {
|
||||
exists(Call call |
|
||||
result = call.getArgument(i) and
|
||||
call.getCallee().getSourceDeclaration().getAParameter() = this
|
||||
|
||||
@@ -6,9 +6,13 @@ import java
|
||||
* Used as basis for the transitive closure in `exprImplies`.
|
||||
*/
|
||||
private predicate exprImpliesStep(Expr e1, boolean b1, Expr e2, boolean b2) {
|
||||
e1.(ParExpr).getProperExpr() = e2 and b2 = b1 and (b1 = true or b1 = false)
|
||||
e1.(ParExpr).getProperExpr() = e2 and
|
||||
b2 = b1 and
|
||||
(b1 = true or b1 = false)
|
||||
or
|
||||
e1.(LogNotExpr).getExpr() = e2 and b2 = b1.booleanNot() and (b1 = true or b1 = false)
|
||||
e1.(LogNotExpr).getExpr() = e2 and
|
||||
b2 = b1.booleanNot() and
|
||||
(b1 = true or b1 = false)
|
||||
or
|
||||
b1 = true and e1.(AndLogicalExpr).getAnOperand() = e2 and b2 = true
|
||||
or
|
||||
@@ -17,7 +21,11 @@ private predicate exprImpliesStep(Expr e1, boolean b1, Expr e2, boolean b2) {
|
||||
|
||||
/** If `e1` evaluates to `b1` then the subexpression `e2` evaluates to `b2`. */
|
||||
predicate exprImplies(Expr e1, boolean b1, Expr e2, boolean b2) {
|
||||
e1 = e2 and b1 = b2 and (b1 = true or b1 = false)
|
||||
e1 = e2 and
|
||||
b1 = b2 and
|
||||
(b1 = true or b1 = false)
|
||||
or
|
||||
exists(Expr emid, boolean bmid | exprImplies(e1, b1, emid, bmid) and exprImpliesStep(emid, bmid, e2, b2))
|
||||
exists(Expr emid, boolean bmid |
|
||||
exprImplies(e1, b1, emid, bmid) and exprImpliesStep(emid, bmid, e2, b2)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user