Additional check in ParameterAccessor

getThisAs tests for supertype now
This commit is contained in:
Tobias Blaschke 2014-03-25 12:04:18 +01:00 committed by Juergen Graf
parent 5f51dac201
commit cc2ffec023
1 changed files with 105 additions and 13 deletions

View File

@ -287,11 +287,13 @@ public class ParameterAccessor { // extends Param-Manager
* *
* Do _not_ use ParameterAceesor(IMethod.getReference()), but ParameterAceesor(IMehod)! * Do _not_ use ParameterAceesor(IMethod.getReference()), but ParameterAceesor(IMehod)!
* *
* Using this Constructor influences the SSA-Values returned later. * Using this Constructor influences the SSA-Values returned later. The cha is needed to
* determine whether mRef is static. If this is already known one should prefer the faster
* {@link #ParameterAccessor(ParameterAccessor, boolean)}.
* *
* @param mRef The method to read the parameters from. * @param mRef The method to read the parameters from.
*/ */
public ParameterAccessor(final MethodReference mRef, final IClassHierarchy cha) { // TODO :document public ParameterAccessor(final MethodReference mRef, final IClassHierarchy cha) {
if (mRef == null) { if (mRef == null) {
throw new IllegalArgumentException("Can't read the arguments from null."); throw new IllegalArgumentException("Can't read the arguments from null.");
} }
@ -373,7 +375,7 @@ public class ParameterAccessor { // extends Param-Manager
if (hasImplicitThis) { if (hasImplicitThis) {
logger.info("The method {} has an implicit this pointer", mRef); logger.info("The method {} has an implicit this pointer", mRef);
this.implicitThis = 1; this.implicitThis = 1;
this.descriptorOffset = -1; // TODO: verify this.descriptorOffset = -1;
} else { } else {
logger.info("The method {} has no implicit this pointer", mRef); logger.info("The method {} has no implicit this pointer", mRef);
this.implicitThis = -1; this.implicitThis = -1;
@ -381,8 +383,16 @@ public class ParameterAccessor { // extends Param-Manager
} }
} }
/**
public ParameterAccessor(final MethodReference mRef, final boolean hasImplicitThis) { // TODO :document * Reads the parameters of a MethodReference CAUTION:.
*
* Do _not_ use ParameterAceesor(IMethod.getReference()), but ParameterAceesor(IMehod)!
*
* This constructor is faster than {@link #ParameterAccessor(MethodReference, IClassHierarchy}.
*
* @param mRef The method to read the parameters from.
*/
public ParameterAccessor(final MethodReference mRef, final boolean hasImplicitThis) {
if (mRef == null) { if (mRef == null) {
throw new IllegalArgumentException("Can't read the arguments from null."); throw new IllegalArgumentException("Can't read the arguments from null.");
} }
@ -395,7 +405,7 @@ public class ParameterAccessor { // extends Param-Manager
if (hasImplicitThis) { if (hasImplicitThis) {
logger.info("The method {} has an implicit this pointer", mRef); logger.info("The method {} has an implicit this pointer", mRef);
this.implicitThis = 1; this.implicitThis = 1;
this.descriptorOffset = -1; // TODO: verify this.descriptorOffset = -1;
} else { } else {
logger.info("The method {} has no implicit this pointer", mRef); logger.info("The method {} has no implicit this pointer", mRef);
this.implicitThis = -1; this.implicitThis = -1;
@ -449,8 +459,6 @@ public class ParameterAccessor { // extends Param-Manager
// no is checked by getParameterNo(int) // no is checked by getParameterNo(int)
final int newNo = getParameterNo(no); final int newNo = getParameterNo(no);
//assert(false):"DEFECT!";
switch (this.base) { switch (this.base) {
case IMETHOD: // TODO: Try reading parameter name case IMETHOD: // TODO: Try reading parameter name
return new Parameter(newNo, null, this.method.getParameterType(no), ParamerterDisposition.PARAM, return new Parameter(newNo, null, this.method.getParameterType(no), ParamerterDisposition.PARAM,
@ -582,22 +590,35 @@ public class ParameterAccessor { // extends Param-Manager
return getThisAs(selfType); return getThisAs(selfType);
} }
/**
* Return the implicit this-pointer as a supertype.
*
* @param asType A type of a super-class of this
*/
public Parameter getThisAs(final TypeReference asType) { public Parameter getThisAs(final TypeReference asType) {
// TODO assert asType is a subtype of self.type
final int self = getThisNo(); final int self = getThisNo();
switch (this.base) { switch (this.base) {
case IMETHOD: case IMETHOD:
final IClassHierarchy cha = this.method.getClassHierarchy();
try {
if (! isSubclassOf(this.method.getParameterType(self), asType, cha) ) {
throw new IllegalArgumentException("Class " + asType + " is not a super-class of " +
this.method.getParameterType(self));
}
} catch (ClassLookupException e) {
// Cant't test assume all fitts
}
return new Parameter(self, "self", asType, ParamerterDisposition.THIS, return new Parameter(self, "self", asType, ParamerterDisposition.THIS,
this.base, this.method.getReference(), this.descriptorOffset); this.base, this.method.getReference(), this.descriptorOffset);
case METHOD_REFERENCE: case METHOD_REFERENCE:
// TODO assert asType is a subtype of self.type - we need cha to do that :(
return new Parameter(self, "self", asType, ParamerterDisposition.THIS, return new Parameter(self, "self", asType, ParamerterDisposition.THIS,
this.base, this.mRef, this.descriptorOffset); this.base, this.mRef, this.descriptorOffset);
default: default:
throw new UnsupportedOperationException("No implementation of getThis() for base " + this.base); throw new UnsupportedOperationException("No implementation of getThis() for base " + this.base);
} }
} }
/** /**
@ -1257,7 +1278,6 @@ public class ParameterAccessor { // extends Param-Manager
if (callee.getNumberOfParameters() == 0) { if (callee.getNumberOfParameters() == 0) {
return new ArrayList<SSAValue>(0); return new ArrayList<SSAValue>(0);
} }
//final Logger logger = LoggerFactory.getLogger(ParameterAccessor.class); // XXX
final List<SSAValue> assigned = new ArrayList<SSAValue>(); // TODO: Set initial size final List<SSAValue> assigned = new ArrayList<SSAValue>(); // TODO: Set initial size
final List<Parameter> calleeParams = callee.all(); final List<Parameter> calleeParams = callee.all();
@ -1480,6 +1500,62 @@ public class ParameterAccessor { // extends Param-Manager
return cha.isAssignableFrom(toClass, fromClass); return cha.isAssignableFrom(toClass, fromClass);
} }
/**
* Is sub a subclass of superC (or the same).
*/
public static boolean isSubclassOf(final TypeReference sub, final TypeReference superC, final IClassHierarchy cha)
throws ClassLookupException {
if (cha == null) {
throw new IllegalArgumentException("ClassHierarchy may not be null");
}
if (sub.getName().equals(superC.getName())) return true;
if (sub.isPrimitiveType() || superC.isPrimitiveType()) {
return false;
}
IClass subClass = cha.lookupClass(sub);
IClass superClass = cha.lookupClass(superC);
if (subClass == null) {
logger.debug("Unable to look up the type of from=" + sub + " in the ClassHierarchy - tying other loaders...");
for (final IClassLoader loader: cha.getLoaders()) {
final IClass cand = loader.lookupClass(sub.getName());
if (cand != null) {
logger.debug("Using alternative for from: {}", cand);
subClass = cand;
break;
}
}
if (subClass == null) {
throw new ClassLookupException("Unable to look up the type of from=" + sub +
" in the ClassHierarchy");
}
}
if (superClass == null) {
logger.debug("Unable to look up the type of to=" + superC + " in the ClassHierarchy - tying other loaders...");
for (final IClassLoader loader: cha.getLoaders()) {
final IClass cand = loader.lookupClass(superC.getName());
if (cand != null) {
logger.debug("Using alternative for to: {}", cand);
superClass = cand;
break;
}
}
if (superClass == null) {
logger.error("Unable to look up the type of to={} in the ClassHierarchy", superC);
throw new ClassLookupException("Unable to look up the type of to=" + superC +
" in the ClassHierarchy");
}
}
return cha.isSubclassOf(subClass, superClass);
}
/** /**
* The method this accessor reads the parameters from. * The method this accessor reads the parameters from.
*/ */
@ -1528,7 +1604,17 @@ public class ParameterAccessor { // extends Param-Manager
return (getReturnType() != TypeReference.Void); return (getReturnType() != TypeReference.Void);
} }
/**
* Assign parameters to a call based on their type.
*
* this variant of connectThrough cannot create new instances if needed.
*
* @param callee The function to generate the parameter-list for
* @param overrides If a parameter occurs here, it is preferred over the ones present in this
* @param defaults If a parameter is not present in this or the overrides, defaults are searched. If the parameter is not present there null is assigned.
* @param cha Optional class hierarchy for testing assignability
* @return the parameter-list for the call of toMethod
*/
public List<SSAValue> connectThrough(final ParameterAccessor callee, Set<? extends SSAValue> overrides, Set<? extends SSAValue> defaults, public List<SSAValue> connectThrough(final ParameterAccessor callee, Set<? extends SSAValue> overrides, Set<? extends SSAValue> defaults,
final IClassHierarchy cha) { final IClassHierarchy cha) {
return connectThrough(callee, overrides, defaults, cha, null); return connectThrough(callee, overrides, defaults, cha, null);
@ -1551,10 +1637,16 @@ public class ParameterAccessor { // extends Param-Manager
} }
} }
/**
* Number of parameters _excluding_ implicit this
*/
public int getNumberOfParameters() { public int getNumberOfParameters() {
return this.numberOfParameters; return this.numberOfParameters;
} }
/**
* Extensive output for debugging purposes.
*/
public String dump() { public String dump() {
String ret = "Parameter Accessor for " + ((this.mRef!=null)?"mRef:" + this.mRef.toString():"IMethod: " + this.method.toString()) + String ret = "Parameter Accessor for " + ((this.mRef!=null)?"mRef:" + this.mRef.toString():"IMethod: " + this.method.toString()) +
"\nContains " + this.numberOfParameters + " Parameters " + this.base + "\n"; "\nContains " + this.numberOfParameters + " Parameters " + this.base + "\n";