/**
* Standard library of SemmleCode queries
* Author: Semmle limited
* Version: 0.4.0
*/
/** -------- Predicates on AST elements -------- */
/** is X immediately above Y in the syntax tree? */
predicate hasChild(@element X, @element Y) {
cus(Y,_,_,X,_,_) or
not(enclInReftype(Y,_,_)) and classes(Y,_,X,_,_) or
enclInReftype(Y,X,_) or
not(enclInReftype(Y,_,_)) and interfaces(Y,_,X,_,_) or
methods(Y,_,_,_,X,_,_) or
constrs(Y,_,_,_,X,_,_) or
params(Y,_,_,_,X,_,_) or
fields(Y,_,_,X,_,_) or
annots(Y,X,_,_) or
typeVars(Y,_,_,X,_,_)
}
/** is X somewhere in package P?
* put differently, is P an ancestor of X in the syntax tree? */
predicate isInPackage(@element X, @package P) {
hasChild+(P,X)
}
/** does X have name Name? */
predicate hasName(@element X, string Name) {
classes(X,Name,_,_,_) or
interfaces(X,Name,_,_,_) or
primitives(X,Name) or
constrs(X,Name,_,_,_,_,_) or
methods(X,Name,_,_,_,_,_) or
fields(X,Name,_,_,_,_) or
packages(X,Name) or
cus(X,Name,_,_,_,_) or
params(X,Name,_,_,_,_,_) or
typeVars(X,Name,_,_,_,_) or
arrays(X,Name,_,_,_,_) or
modifiers(X,Name)
}
/** does X belong to compilation unit C? */
predicate inCompilationUnit(@element X, @cu C) {
classes(X,_,_,C,_) or
interfaces(X,_,_,C,_) or
constrs(X,_,_,_,_,C,_) or
methods(X,_,_,_,_,C,_) or
fields(X,_,_,_,C,_) or
params(X,_,_,_,_,C,_) or
typeVars(X,_,_,_,C,_) or
arrays(X,_,_,_,C,_) or
X = C
}
/** does X have location L? */
predicate hasLocation(@element X, @location L) {
classes(X,_,_,_,L) or
interfaces(X,_,_,_,L) or
constrs(X,_,_,_,_,_,L) or
methods(X,_,_,_,_,_,L) or
fields(X,_,_,_,_,L) or
cus(X,_,_,_,_,L) or
exceptions(X,_,_,_,L) or
params(X,_,_,_,_,_,L)
}
/** does expression X have location L? */
predicate exprHasLocation(@expression X, @location L) {
readsField(X,_,_,_,L) or
writesField(X,_,_,_,L) or
callsMethod(X,_,_,_,_,L) or
callsConstr(X,_,_,_,_,L)
}
/** is accessor the callable that accesses the field in fieldAccess?*/
predicate hasAccessor(@fieldAccessExpr fieldAccess, @callable accessor) {
readsField(fieldAccess,accessor,_,_,_) or
writesField(fieldAccess,accessor,_,_,_)
}
/** is the accessee the field in fieldAccess?*/
predicate hasAccessee(@fieldAccessExpr fieldAccess, @field accessee) {
readsField(fieldAccess,_,accessee,_,_) or
writesField(fieldAccess,_,accessee,_,_)
}
/** does X have a modifier named Str?
* example: (@method(M) and hasStrModifier(m,"private"))
* selects private methods */
predicate hasStrModifier(@element X, string Str) {
exists(@modifier Mod | hasModifier(X,Mod,_) and modifiers(Mod,Str))
}
/** -------- Predicates on types -------- */
/** is T a non-nested type in package P? */
predicate isTopLevelType(@reftype T, @package P) {
classes(T,_,P,_,_) and not(enclInReftype(T,_,_)) or
interfaces(T,_,P,_,_) and not(enclInReftype(T,_,_))
}
/** is T nested inside P? */
predicate isNestedType(@reftype T, @reftype P) {
enclInReftype(T,P,_)
}
/** is T in package P? this also returns true when T is
* a nested type in P */
predicate typeIsInPackage(@type T, @package P) {
classes(T,_,P,_,_) or
interfaces(T,_,P,_,_)
}
/** is T an outermost type? */
predicate outerType(@type T) {
isTopLevelType(T,_)
}
/** is T in compilation unit CU? */
predicate typeIsInCU(@type T, @cu CU) {
classes(T,_,_,CU,_) or
interfaces(T,_,_,CU,_)
}
/** is T an immediate supertype of Sub?
* use hasSubtype*(T,Sub) for "T is a supertype of Sub"
* use hasSubtype+(T,Sub) for "T is a distinct supertype of Sub */
predicate hasSubtype(@reftype T, @type Sub) {
extendsReftype(Sub,T,_) or
implInterface(Sub,T,_)
}
/** does T declare member M? */
predicate declaresMember(@type T, @member M) {
methods(M,_,_,_,T,_,_) or
constrs(M,_,_,_,T,_,_) or
fields(M,_,_,T,_,_) or
enclInReftype(M,T,_)
}
/** does class C declare constructor M? */
predicate declaresConstructor(@class C, @constructor M) {
constrs(M,_,_,_,C,_,_)
}
/** does T declare method M? */
predicate declaresMethod(@reftype T, @method M) {
methods(M,_,_,_,T,_,_)
}
/** does T declare field F? */
predicate declaresField(@reftype T, @field F) {
fields(F,_,_,T,_,_)
}
/** does T have method M, and if so, does it come from From */
predicate hasMethod(@reftype T, @method M, @reftype From) {
( declaresMethod(T,M) and From = T ) or
( exists(@reftype Super | hasSubtype(Super,T) and
hasMethod(Super,M,From)) and
exists(string S | methods(M,_,S,_,_,_,_) and
not methods(_,_,S,_,T,_,_) ) and
inheritableMethod(M)
)
}
/** -------- Predicates on fields -------- */
/** does field F have type T? */
predicate hasType(@field F, @type T) {
fields(F,_,T,_,_,_)
}
/** does B read or write field F? */
predicate accesses(@callable B, @field F) {
readsField(_,B,F,_,_) or
writesField(_,B,F,_,_)
}
/** -------- Predicates on callables -------- */
/** does B have a parameter of type T at position Pos?
* counting positions starts at 0.
* example: p(A x, B y) has a parameter of type B at position 1 */
predicate hasParam(@callable B, @type T, int Pos) {
params(_,_,T,Pos,B,_,_)
}
/** does B have signature S?
* S is a string where all types have been given their full Java
* name, such as "java.lang.String" rather than just "String" */
predicate hasSignature(@callable B, string S) {
constrs(B,_,S,_,_,_,_) or
methods(B,_,S,_,_,_,_)
}
/** could method M be inherited? */
predicate inheritableMethod(@method M) {
not hasStrModifier(M,"private") and
not hasStrModifier(M,"static")
}
/** do methods M1 and M2 have the same signature? */
predicate hasSameSignature(@method M1, @method M2) {
exists(string S | hasSignature(M1,S) and hasSignature(M2,S))
}
/** does method M1 override method M2? */
predicate overrides(@method M1, @method M2) {
exists(string S | methods(M1,_,S,_,_,_,_) and methods(M2,_,S,_,_,_,_)) and
inheritableMethod(M2) and
exists (@reftype T1, @reftype T2 | declaresMethod(T1,M1) and
declaresMethod(T2,M2) and
hasSubtype+(T2,T1))
}
/** does B return a value of type T? */
predicate returnsType(@callable B, @type T) {
methods(B,_,_,T,_,_,_) or
constrs(B,_,_,T,_,_,_)
}
/** do M1 and M2 declared in the same type have the same parameter types? */
predicate sameParamTypes(Method M1, Method M2) {
M1!=M2 and
M1.getDeclaringType() = M2.getDeclaringType() and
M1.getNumberOfParameters() = M2.getNumberOfParameters() and
not exists(Type T, int POS | hasParam(M1, T, POS) and
not hasParam(M2, T, POS))
}
/** any node in the syntax tree that has a name */
class Element extends @element {
predicate hasName(string name) { hasName(this,name) }
string getName() { this.hasName(result) }
string toString() { hasName(this,result) }
/** does this element contain e, i.e., is this an ancestor of e? */
predicate contains(Element e) { hasChild+(this,e) }
/** is this element populated from source code?
this is useful to filter source elements when using on-demand population */
predicate fromSource() {
exists(CompilationUnit C | inCompilationUnit(this,C) and
C.getExtension() == "java")
}
/** is this element populated from a class file, e.g., in a jar file? */
predicate fromLibrary() {
exists(CompilationUnit C | inCompilationUnit(this,C) and
C.getExtension() == "class") }
/** get the source location for this element */
Location getLocation() { hasLocation(this,result) }
}
/** a location maps language elements to positions in source files */
class Location extends @location {
/** return the number of lines that this location ranges over */
int getNumberOfLines() { locations(this,_,_,_,_,_,result,_,_) }
/** return the number of lines of code that this location ranges over */
int getNumberOfLinesOfCode() { locations(this,_,_,_,_,_,_,result,_) }
/** return the number of comment lines that this location ranges over */
int getNumberOfCommentLines() { locations(this,_,_,_,_,_,_,_,result) }
/** return a string representation containing the compilation unit and
range for this source location */
string toString() {
exists(CompilationUnit cu,
int startline,
int endline,
int totallines |
locations(this,_,cu,_,_,startline,totallines,_,_) and
(totallines = 0 and endline = startline or
totallines > 0 and endline = startline + totallines - 1) and
result = cu.toString() + ":" +
startline.toString() + "-" + endline.toString())
}
}
/** a package may be used to abstract over all members of a package,
regardless in which compilation unit they are defined in */
class Package extends Element, Annotatable, @package {
/** find top level types in this package */
RefType getARefType() { isTopLevelType(result, this) }
/** is there at least one reftype in this package that is populated
from source? */
predicate fromSource() {
exists(RefType t | t.fromSource() and t.getPackage() = this)
}
/** is there at least one reftype in this package that is populated
from bytecode? */
predicate fromLibrary() {
exists(RefType t | t.fromLibrary() and t.getPackage() = this)
}
/** select the icon to be used when displaying query results */
string getIconPath() { result = "icons/package.png" }
}
/** a compilation unit for a type declaration, i.e., a .java or .class file */
class CompilationUnit extends Element, @cu {
/** the number of lines of code in this compilation unit */
int getNumberOfLinesOfCode() {
result = this.getLocation().getNumberOfLinesOfCode()
}
/** the number of comment lines in this compilation unit */
int getNumberOfCommentLines() {
result = this.getLocation().getNumberOfCommentLines()
}
/** the total number of lines including everything */
int getNumberOfLines() {
result = this.getLocation().getNumberOfLines()
}
/** the full disk path to this compilation unit */
string getPath() { cus(this,_,result,_,_,_) }
/** the extension of a compiltation unit is either ".java" or ".class" */
string getExtension() { cus(this,_,_,_,result,_) }
/** the declared package of this compilation unit */
Package getPackage() { cus(this,_,_,result,_,_) }
}
/** ------ Modifiers ------- */
class Modifier extends Element, @modifier {
/** the element which this modifier modifies */
Element getElement() { hasModifier(result,this,_) }
}
/** -------- Types -------- */
/** a common abstraction for all Java types, e.g., primitive, class, interface,
* and array types */
class Type extends Element, @type { }
/** primitive types include boolean, byte, short, char, int, long, float,
* and double */
class PrimitiveType extends Type, @primitive {
PrimitiveType() { @primitive(this) }
}
/** any class or interface or type variable or array */
class RefType extends Type, Annotatable, @reftype {
/** return the package in which this type is declared */
Package getPackage() { typeIsInPackage(this,result) }
/** return the compilation unit in which this type is declared */
CompilationUnit getCompilationUnit() { typeIsInCU(this,result) }
/** is t an immediate supertype of this type? */
predicate hasSupertype(RefType t) { hasSubtype(t,this) }
/** is t an immediate subtype of this type? */
predicate hasSubtype(RefType t) { hasSubtype(this,t) }
/** return a direct subtype of this type */
RefType getASubtype() { hasSubtype(this,result) }
/** return a direct supertype of this type */
RefType getASupertype() { hasSubtype(result,this) }
/** does this type declare any members? */
predicate hasMember() { declaresMember(this, _) }
/** return a member declared in this type */
Member getAMember() { this = result.getDeclaringType() }
/** return a method declared in this type */
Method getAMethod() { this = result.getDeclaringType() }
/** return a constructor declared in this type */
Constructor getAConstructor() { this = result.getDeclaringType() }
/** return a method or constructor declared in this type */
Callable getACallable() { this = result.getDeclaringType() }
/** return a field declared in this type */
Field getAField() { this = result.getDeclaringType() }
/** does this type declare a member method named name? */
predicate declaresMethod(string name) { this.getAMethod().getName() = name }
/** does this type declare a member field named name? */
predicate declaresField(string name) { this.getAField().getName() = name }
/** return the number of member methods declared in this type */
int getNumberOfMethods() { result = count(Method m | declaresMember(this,m)) }
/** does this type have a specific modifier? */
predicate hasModifier(string modifier) { hasStrModifier(this,modifier) }
/** does this type not have any modifiers? */
predicate hasNoModifier() { not hasModifier(this,_,_) }
/** return a modifier declared for this type */
Modifier getAModifier() { this = result.getElement() }
/** does this type inherit method m */
predicate inherits(Method m) { hasMethod(this, m, _) }
/** is this a top-level type? */
predicate isTopLevel() { isTopLevelType(this,_) }
/** is this type declared in package and have the name type */
predicate hasQualifiedName(string package, string type) {
this.getPackage().hasName(package) and this.hasName(type)
}
string getQualifiedName() {
(this.getPackage().getName()=="" and result = this.nestedName()) or
(this.getPackage().getName()!="" and result = this.getPackage().getName()
+ "." + this.nestedName())
}
string nestedName() {
not (this instanceof NestedType) and result = this.getName()
or
((this instanceof NestedType) and
((NestedType)this).getEnclosingType().nestedName() +
"$" + this.getName() = result)
}
}
/** any class declaration */
class Class extends RefType, @class {
/** is this class an anonymous class in a method or constructor? */
predicate isAnonymous() { isAnonymClass(this) }
/** is this a local class declared within a method or constructor? */
predicate isLocal() { isLocalClass(this) }
/** select the icon to be used when displaying query results */
string getIconPath() { result = "icons/class.png" }
}
/** any interface declaration */
class Interface extends RefType, @interface {
/** select the icon to be used when displaying query results */
string getIconPath() { result = "icons/interface.png" }
}
/** an anonymous class */
class AnonymousClass extends NestedClass {
AnonymousClass() { this.isAnonymous() }
string getQualifiedName() { result = "" }
}
/** a local class */
class LocalClass extends NestedClass {
LocalClass() { this.isLocal() }
}
/** a non top-level type declared within another type */
class NestedType extends RefType {
NestedType() { isNestedType(this,_) }
/** get the type enclosing this nested type */
RefType getEnclosingType() { isNestedType(this,result) }
}
/** a class declared within another type, e.g. a member class, local class,
* anonymous class */
class NestedClass extends NestedType, Class { }
/** any array type.
these types are implicitly declared when being used, i.e.,
there is an array declaration for each array type used in the system */
class Array extends RefType, @array {
/** the element type of an array type is the base type used to construct the
array. the element type of Object[][] is for instance Object */
Type getElementType() { arrays(this,_,result,_,_,_) }
/** the arity of the array type.
the dimension of Object[][] is for instance 2 */
int getDimension() { arrays(this,_,_,result,_,_) }
}
/** -------- Members of classes and interfaces -------- */
/** a common abstraction for type member declarations, e.g., methods, fields,
* and nested types */
class Member extends Element, Annotatable, @member {
/** the type this member is declared in */
RefType getDeclaringType() { declaresMember(result, this) }
/** members may have modifiers */
predicate hasModifier(string modifier) { hasStrModifier(this,modifier) }
predicate hasNoModifier() { not hasModifier(this,_,_) }
/** return a modifier for this member */
Modifier getAModifier() { this = result.getElement() }
}
/** any class or instance field */
class Field extends Member, @field {
/** the declared type of this field */
Type getType() { hasType(this,result) }
/** the type this member is declared in */
RefType getDeclaringType() { declaresField(result,this) }
/** select the icon to be used when displaying query results */
string getIconPath() { result = "icons/field.png" }
}
/** any method or constructor */
class Callable extends Member, @callable {
/** get the declared type of this callable */
Type getType() { returnsType(this,result) }
/** select a callee that may be called from this callable */
Callable getACall() { this.calls(result) }
/** Gets the call site of a call from this callable to a callee*/
Call getACallSite(Callable callee) {
exists(Call c | c.getCaller() = this and c.getCallee() = callee
and c == result)
}
/** select a callee which is a constructor that may be called from this
callable */
Constructor getAConstructorCall() {
exists(ConstructorCall c | c.getConstructor() = result
and c.getCaller() = this)
}
/** does this callable call target using any kind of call? */
predicate calls(Callable target) {
exists(Call c | c.getCaller() = this and c.getCallee() = target)
}
/** does this callable call c using a super constructor call? */
predicate callsSuper(Constructor target) {
exists(SuperConstructorCall c |
c.getConstructor() = target and c.getCaller() = this)
}
/** does this callable call c using a constructor calll? */
predicate callsThis(Constructor target) {
exists(ThisConstructorCall c |
c.getConstructor() = target and c.getCaller() = this)
}
/** does this callable call c using either a super constructor or a
constructor call */
predicate callsConstructor(Constructor c) {
this.callsSuper(c) or this.callsThis(c)
}
/** may this callable call c taking overriding into acount? */
predicate polyCalls(Callable m) {
exists(Call c | c.getCaller() = this and c.getCallee() = m)
or
exists(Method mSuper, VirtualMethodCall c |
c.getCaller() = this and c.getMethod() = mSuper and
((Method)m).overrides(mSuper))
}
predicate callsSuper(Method target) {
exists(SuperMethodCall c |
c.getMethod() = target and c.getCaller() = this)
}
/** may f be assigned within the body of this callable? */
predicate writes(Field f) { writesField(_, this, f, _,_) }
/** may f be read within the body of this callable */
predicate reads(Field f) { readsField(_, this, f, _,_) }
/** may f be either read or written within the body of this callable */
predicate accesses(Field f) { this.writes(f) or this.reads(f) }
/** get any field accessed in this callable */
Field getAnAccess() { this.accesses(result) }
/** get a formal parameter type */
Type getAParamType() { hasParam(this,result,_) }
/** does this callable not have any formal parameters */
predicate hasNoParameters() { not params(_,_,_,_,this,_,_) }
/** return the number of formal parameters of this callable */
int getNumberOfParameters() {
result = count(int pos | params(_,_,_,pos,this,_,_))
}
/** return a formal paramater of this callable */
Parameter getAParameter() { result.getCallable() = this }
/** get an exception that may be thrown from this callable */
Exception getAnException() { exceptions(result,_,this,_,_) }
/** get a call site that references this callable */
Call getAReference() {
exists( Call c | c.getCallee() = this and c = result )
}
/** select the icon to be used when displaying query results */
string getIconPath() { result = "icons/method.png" }
string paramstr( int n) {
exists (Type t | hasParam( this ,t,n) and result=t.toString())
}
string paramUpTo(int n) {
(n =0 and result = this.paramstr(0))
or
(n > 0 and
exists(Type t |
hasParam(this,t,n) and
(result = this.paramUpTo(n-1) + ", " +t.toString())))
}
string paramsString() {
exists(int n |
this.getNumberOfParameters() = n
and
((n=0 and result = "()")
or
(n>0 and result = "("+this.paramUpTo(n-1)+")")))
}
/** readable signature of this Callable */
string getStringSignature() {
result = this.getName() + this.paramsString()
}
}
/** callables may have paramaters */
class Parameter extends Element, @param {
/** return the type of this formal parameter */
Type getType() { params(this,_,result,_,_,_,_) }
/** get the position of this formal parameter */
int getPosition() { params(this,_,_,result,_,_,_) }
/** get the callable in which this formal parameter is declared */
Callable getCallable() { params(this,_,_,_,result,_,_) }
}
/** callables may throw exceptions, this element represent the actual
* throws clause and not the exception type, being the first X below
void m() throws X;
class X extends Exception { }
*/
class Exception extends Element, @exception {
RefType getType() { exceptions(this,result,_,_,_) }
/** return the callable that throws this exception */
Callable getCallable() { exceptions(this,_,result,_,_) }
/** return the name of this exception which is the same as its type */
string getName() { result = this.getType().getName() }
/** does this exception throw an exception named name? */
predicate hasName(string name) { this.getType().hasName(name) }
/** return the name if the exception as its string representation */
string toString() { result = this.getType().toString() }
}
/** a method is a restricted kind of callable */
class Method extends Callable, @method {
/** does this method override c? */
predicate overrides(Callable c) { overrides(this,c) }
string getSignature() { methods(this,_,result,_,_,_,_) }
/** select the icon to be used when displaying query results, use
different icons for public, protected, and private methods */
string getIconPath() {
(this.hasModifier("private") and result = "icons/privatemethod.png") or
(this.hasModifier("protected") and result = "icons/protectedmethod.png") or
(this.hasModifier("public") and result = "icons/publicmethod.png") or
(not(this.hasModifier("private") or
this.hasModifier("protected") or
this.hasModifier("public")) and
result = "icons/method.png")
}
}
/** a constructor is a restricted kind of callable */
class Constructor extends Callable, @constructor {
/** default constructors are not explicitly declared in source code */
predicate isDefaultConstructor() { isDefConstr(this) }
/** select the icon to be used when displaying query results */
string getIconPath() { result = "icons/constructor.png" }
}
/** -------- Generic types -------- */
/** any generic type that has a type parameter, e.g., X in class X { } */
class GenericType extends RefType {
GenericType() { typeVars(_,_,_,this,_,_) }
/** get a parameterization of this generic type, e.g., X. each use of
a formal type parameter has been replaced by its argument. */
ParameterizedType getAParameterizedType() { result.getErasure() = this }
/** get the raw version of this generic type, i.e., the use of a generic type
as if it was non-generic. this is for instance the case when legacy code
not aware of generics uses collections in Java 5.*/
RawType getRawType() { result.getErasure() = this }
}
class GenericClass extends GenericType, Class { }
class GenericInterface extends GenericType, Interface { }
/** a type variable used in the declaration of a generic type or method, e.g.,
* T in class X { } or void m() { }.*/
class TypeVariable extends RefType, @typevariable {
/** return the generic type that is parameterized using this type variable */
RefType getGenericType() { typeVars(this,_,_,result,_,_) }
/** return the generic method that is parameterized using this type
variable */
Method getGenericMethod() { typeVars(this,_,_,result,_,_) }
/** return a type bound for this type variable */
TypeBound getATypeBound() { result.getTypeVariable() = this }
}
/** each type variable may have zero or more type bounds, e.g.,
* Number in class X { }. */
class TypeBound extends @typebound {
/** get the type variable that this bound restricts, e.g., T in the example
above */
TypeVariable getTypeVariable() { typeBounds(this,_,_,result,_,_) }
/** get type type of this bound, e.g., Number in the example above */
RefType getType() { typeBounds(this,result,_,_,_,_) }
string toString() { result = this.getType().getName() }
}
/** -------- Parameterizations of generic types -------- */
/** a parameterized type is a generic type where each formal type variable has
* been instantiated with a type argument */
class ParameterizedType extends RefType {
ParameterizedType() { isParameterized(this) }
/** the erasure of a parameterized type is its generic counterpart, i.e.,
the erasure of X and X are both X */
RefType getErasure() { erasure(this,result) }
RefType getATypeArgument() { typeArgs(result,_,this,_) }
RefType getTypeArgument(int pos) { typeArgs(result,pos,this,_) }
int getNumberOfTypeArguments() {
result = count(int pos | typeArgs(_,pos,this,_))
}
predicate fromSource() { not any() }
predicate fromLibrary() { not any() }
}
class ParameterizedClass extends Class, ParameterizedType {
predicate fromSource() { ParameterizedType.super.fromSource() }
predicate fromLibrary() { ParameterizedType.super.fromLibrary() }
}
class ParameterizedInterface extends Interface, ParameterizedType {
predicate fromSource() { ParameterizedType.super.fromSource() }
predicate fromLibrary() { ParameterizedType.super.fromLibrary() }
}
/** a raw type is a generic type that is used as if it was a non-generic type,
* e.g., from legacy code not aware of generics. */
class RawType extends RefType {
RawType() { isRaw(this) }
/** the erasure of a raw type is its generic counterpart, i.e.,
the erasure of X is X */
RefType getErasure() { erasure(this,result) }
predicate fromSource() { not any() }
predicate fromLibrary() { not any() }
}
|