/** --- Member ---
Classes to represent members of classes and interfaces, i.e. methods, fields,
and nested types.
*/
import Element
import Type
import Annotation
import Exception
import metrics.MetricField
/** 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) }
/** does this member have no modifier at all? */
predicate hasNoModifier() { not hasModifier(this,_,_) }
/** return a modifier for this member */
Modifier getAModifier() { this = result.getElement() }
/** is this member public? */
predicate isPublic() { isPublic(this) }
/** is this member protected? */
predicate isProtected() { isProtected(this) }
/** is this member package protected? */
predicate isPackageProtected() { isPackageProtected(this) }
/** is this member private? */
predicate isPrivate() { isPrivate(this) }
}
/** A callable is a method or constructor */
class Callable extends StmtParent, Member, @callable {
/** printable representation */
string toString() { result = Member.super.toString() }
/** 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 target using a super constructor call? */
predicate callsSuper(Constructor target) {
exists(SuperConstructorInvocationStmt c |
c.getConstructor() = target and c.getEnclosingCallable() = this)
}
/** does this callable call target using a constructor calll? */
predicate callsThis(Constructor target) {
exists(ThisConstructorInvocationStmt c |
c.getConstructor() = target and c.getEnclosingCallable() = this)
}
/** does this callable call target using a super constructor call? */
predicate callsSuper(Method target) {
exists(SuperMethodCall c |
c.getMethod() = 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 m taking overriding into account? */
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))
}
/** may f be assigned within the body of this callable? */
predicate writes(Field f) {
writesField(_, this, f, _)
or exists(VarAccess v | v.getVariable() = f and
v.getEnclosingCallable() = this and
v.isLValue())
}
/** may f be read within the body of this callable */
predicate reads(Field f) {
readsField(_, this, f, _)
or exists(VarAccess v | v.getVariable() = f and
v.getEnclosingCallable() = this and
v.isRValue())
}
/** 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 hasParam(this,_,_) }
/** return the number of formal parameters of this callable */
int getNumberOfParameters() {
result = count(int pos | hasParam(this,_,pos))
}
/** return a formal parameter of this callable */
Parameter getAParameter() { result.getCallable() = this }
/** return formal parameter at position n */
Parameter getParameter(int n) { result = this.getAParameter() and
result.getPosition() = n }
/** readable signature of this Callable */
string getStringSignature() {
result = this.getName() + this.paramsString()
}
/** produce parenthesised string containing all argument types */
string paramsString() {
exists(int n |
this.getNumberOfParameters() = n
and
((n = 0 and result = "()")
or
(n > 0 and result = "("+this.paramUpTo(n-1)+")")))
}
/** list the parameters from left to right */
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())))
}
/** return a string for the type of parameter number n */
string paramstr(int n) {
exists (Type t | hasParam(this, t, n) and result = t.toString())
}
/** does this callable have signature sig? */
predicate hasStringSignature(string sig) {
sig = this.getStringSignature()
}
/** 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" }
/** get the body of this callable */
Stmt getBody() { result.getParent() = this }
/** get the source declaration of this callable
*
* for parameterized instances of generic methods, this will be the
* generic methods;
* for non-parameterized callables occuring inside a parameterized
* instance of a generic type, this will be the corresponding callable
* in the generic type;
* for all other callables, it is the method itself
*/
Callable getSourceDeclaration() { result = this }
/** is this callable its own source declaration? */
predicate isSourceDeclaration() { this.getSourceDeclaration() = this }
/** get the metrics delegate of this callable */
MetricCallable getMetrics() { result = this }
}
/** does callable 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 parameter 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,_,_,_,_)
}
/** does callable B return a value of type T? */
predicate returnsType(@callable B, @type T) {
methods(B,_,_,T,_,_,_) or
constrs(B,_,_,T,_,_,_)
}
/** 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))
}
/** is method M accessible from type T, where T is an ancestor of the type
where M is declared? */
predicate accessibleFrom(@method M, @reftype T) {
hasStrModifier(M, "public")
or
hasStrModifier(M, "protected")
or
hasStrModifier(M, "private") and inSameTopLevelType(M, T)
or
isPackageProtected(M) and inSamePackage(M, T)
}
/** does method M1 override method M2? */
predicate overrides(@method M1, @method M2) {
exists(string Sig | hasSignature(M1, Sig) and hasSignature(M2, Sig)) and
inheritableMethod(M2) and
exists (@reftype T1, @reftype T2 |
declaresMethod(T1,M1) and
declaresMethod(T2,M2) and
hasSubtype+(T2,T1) and
(hasStrModifier(M2, "public")
or hasStrModifier(M2, "protected")
or (hasStrModifier(M2, "private")
and exists (@reftype Out | outerType(Out) and
isInType(M2, Out) and
isInType(T1, Out)))
or (isPackageProtected(M2)
and exists (@package P | isInPackage(M2, P) and
isInPackage(T1, P)))))
}
/** 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) }
/** get this method's signatore */
string getSignature() { hasSignature(this, result) }
/** are this method and m declared in the same type and have the same
parameter types? */
predicate sameParamTypes(Method m) {
this != m and
this.getDeclaringType() = m.getDeclaringType() and
this.getNumberOfParameters() = m.getNumberOfParameters() and
not exists(Type T, int POS | hasParam(this, T, POS) and
not hasParam(m, T, POS))
}
/** 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
(this.isPackageProtected() and result = "icons/method.png")
}
/** get this method's source declaration;
* for details, see the discussion for Callable.getSourceDeclaration() */
Method getSourceDeclaration() { methods(this,_,_,_,_,result,_) }
}
/** a setter method */
class SetterMethod extends Method {
SetterMethod() {
this.getNumberOfParameters() = 1 and
exists(Stmt s, Assignment a |
s.getEnclosingCallable() = this and
a.getParent() = s and
((Field)((VarAccess)a.getDest()).getVariable()).getDeclaringType()
= this.getDeclaringType() and
((VarAccess)a.getSource()).getVariable() = this.getAParameter()) and
count(Stmt s | s.getEnclosingCallable() = this) = 2
}
Field getField() {
exists(Assignment a |
a.getEnclosingCallable() = this and
result = ((VarAccess)a.getDest()).getVariable())
}
}
/** a getter method */
class GetterMethod extends Method {
GetterMethod() {
this.getNumberOfParameters() = 0 and
exists(ReturnStmt s |
s.getEnclosingCallable() = this and
((VarAccess)s.getResult()).getVariable() instanceof Field) and
count(Stmt s | s.getEnclosingCallable() = this) = 2
}
Field getField() {
exists(ReturnStmt r |
r.getEnclosingCallable() = this and
result = ((VarAccess)r.getResult()).getVariable())
}
}
/** A finalizer */
class FinalizeMethod extends Method {
FinalizeMethod() {
this.hasName("finalize") and
this.getType().hasName("void") and
this.hasModifier("protected")
}
}
/** 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" }
/** get this constructor's source declaration;
* for details, see the discussion for Callable.getSourceDeclaration() */
Constructor getSourceDeclaration() { constrs(this,_,_,_,_,result,_) }
}
/** is accessor the callable that accesses the field in fieldAccess? */
predicate hasAccessor(@fieldAccessExpr fieldAccess, @callable accessor) {
readsField(fieldAccess,accessor,_,_) or
writesField(fieldAccess,accessor,_,_)
}
/** is accessee the field in fieldAccess? */
predicate hasAccessee(@fieldAccessExpr fieldAccess, @field accessee) {
readsField(fieldAccess,_,accessee,_) or
writesField(fieldAccess,_,accessee,_)
}
/** 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,_)
}
/** A class or instance field */
class Field extends Member, ExprParent, @field, Variable {
/** printable representation */
string toString() { result = Member.super.toString() }
/** 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" }
/** get this field's source declaration; this will be the same as
* the declaration itself, except for fields which are members of
* parameterized instances of generic types, where the source
* declaration is the original field in the generic type */
Field getSourceDeclaration() { fields(this,_,_,_,result,_) }
/** is this field the same as its own source declaration? */
predicate isSourceDeclaration() { this.getSourceDeclaration() = this }
/** get the metrics delegate of this field */
MetricField getMetrics() { result = this }
}
/** An instance field */
class InstanceField extends Field {
InstanceField() {
not this.hasModifier("static")
}
}
|