b |= walkUp(acc, (ResolvedTypeX)i.next());
}
+ if (!b && curr.isParameterized()) {
+ b = walkUp(acc,curr.getGenericType());
+ }
+
if (!b) {
b = curr.lookupMemberNoSupers(this) != null;
}
for (Iterator i = curr.getDirectSupertypes(); i.hasNext(); ) {
b |= walkUpStatic(acc, (ResolvedTypeX)i.next());
}
+ if (!b && curr.isParameterized()) {
+ b = walkUpStatic(acc,curr.getGenericType());
+ }
if (b) acc.add(curr);
return b;
}
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
public String[] parameterNames = null;
protected TypeX[] checkedExceptions = TypeX.NONE;
+ /**
+ * if this member is a parameterized version of a member in a generic type,
+ * then this field holds a reference to the member we parameterize.
+ */
+ protected ResolvedMember backingGenericMember = null;
private Set annotationTypes = null;
// Some members are 'created' to represent other things (for example ITDs). These
// members have their annotations stored elsewhere, and this flag indicates that is
this.checkedExceptions = checkedExceptions;
}
+ public ResolvedMember(
+ Kind kind,
+ TypeX declaringType,
+ int modifiers,
+ TypeX returnType,
+ String name,
+ TypeX[] parameterTypes,
+ TypeX[] checkedExceptions,
+ ResolvedMember backingGenericMember)
+ {
+ this(kind, declaringType, modifiers, returnType, name, parameterTypes,checkedExceptions);
+ this.backingGenericMember = backingGenericMember;
+ }
+
public ResolvedMember(
Kind kind,
TypeX declaringType,
parameterizedReturnType,
getName(),
parameterizedParameterTypes,
- getExceptions()
+ getExceptions(),
+ this
);
}
return aType;
}
}
+
+
+ /**
+ * If this member is defined by a parameterized super-type, return the erasure
+ * of that member.
+ * For example:
+ * interface I<T> { T foo(T aTea); }
+ * class C implements I<String> {
+ * String foo(String aString) { return "something"; }
+ * }
+ * The resolved member for C.foo has signature String foo(String). The
+ * erasure of that member is Object foo(Object) -- use upper bound of type
+ * variable.
+ * A type is a supertype of itself.
+ */
+ public ResolvedMember getErasure() {
+ if (calculatedMyErasure) return myErasure;
+ calculatedMyErasure = true;
+ ResolvedTypeX resolvedDeclaringType = (ResolvedTypeX) getDeclaringType();
+ // this next test is fast, and the result is cached.
+ if (!resolvedDeclaringType.hasParameterizedSuperType()) {
+ return null;
+ } else {
+ // we have one or more parameterized super types.
+ // this member may be defined by one of them... we need to find out.
+ Collection declaringTypes = this.getDeclaringTypes(resolvedDeclaringType.getWorld());
+ for (Iterator iter = declaringTypes.iterator(); iter.hasNext();) {
+ ResolvedTypeX aDeclaringType = (ResolvedTypeX) iter.next();
+ if (aDeclaringType.isParameterized()) {
+ // we've found the (a?) parameterized type that defines this member.
+ // now get the erasure of it
+ ResolvedMember matchingMember = aDeclaringType.lookupMemberNoSupers(this);
+ if (matchingMember != null && matchingMember.backingGenericMember != null) {
+ myErasure = matchingMember.backingGenericMember;
+ return myErasure;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private ResolvedMember myErasure = null;
+ private boolean calculatedMyErasure = false;
}
boolean equalCovariantSignatures = m1.getParameterSignature().equals(m2.getParameterSignature());
if (equalCovariantSignatures) return true;
- // If they aren't the same, we need to allow for generics... where one sig might be a parameterization
- // of another sig.
- if (m1.canBeParameterized()) {
- boolean m2MatchesParameterizationOfm1 =
- matchesGenericMethod(m1,m2);
- if (m2MatchesParameterizationOfm1) return true;
- }
- if (m2.canBeParameterized()) {
- boolean m1MatchesParameterizationOfm2 =
- matchesGenericMethod(m2,m1);
- if (m1MatchesParameterizationOfm2) return true;
- }
return false;
}
- /**
- * This method is only called from matches(m1,m2)
- * We know that the names match, but that's it.
- */
- private static boolean matchesGenericMethod(Member aGenericMember, Member possibleParameterizationMember) {
- return false;
- }
-
public static boolean conflictingSignature(Member m1, Member m2) {
if (m1 == null || m2 == null) return false;
public ResolvedTypeX parameterizedWith(TypeX[] typeParameters) {
return this;
}
+
+ public boolean hasParameterizedSuperType() {
+ getParameterizedSuperTypes();
+ return parameterizedSuperTypes.length > 0;
+ }
+
+ private ResolvedTypeX[] parameterizedSuperTypes = null;
+ /**
+ * Similar to the above method, but accumulates the super types
+ * @return
+ */
+ public ResolvedTypeX[] getParameterizedSuperTypes() {
+ if (parameterizedSuperTypes != null) return parameterizedSuperTypes;
+ List accumulatedTypes = new ArrayList();
+ accumulateParameterizedSuperTypes(this,accumulatedTypes);
+ ResolvedTypeX[] ret = new ResolvedTypeX[accumulatedTypes.size()];
+ parameterizedSuperTypes = (ResolvedTypeX[]) accumulatedTypes.toArray(ret);
+ return parameterizedSuperTypes;
+ }
+
+ private void accumulateParameterizedSuperTypes(ResolvedTypeX forType, List parameterizedTypeList) {
+ if (forType.isParameterized()) {
+ parameterizedTypeList.add(forType);
+ }
+ if (forType.getSuperclass() != null) {
+ accumulateParameterizedSuperTypes(forType.getSuperclass(), parameterizedTypeList);
+ }
+ ResolvedTypeX[] interfaces = forType.getDeclaredInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ accumulateParameterizedSuperTypes(interfaces[i], parameterizedTypeList);
+ }
+ }
}
if (!name.matches(sig.getName())) return false;
// Check the parameters
- if (!parameterTypes.matches(world.resolve(sig.getParameterTypes()), TypePattern.STATIC).alwaysTrue()) {
- return false;
+ // AMC parameterized types make this more complex. Suppose I have a
+ // type that implements a parameterized interface. It might declare a method
+ // foo(Double). If foo is defined in I<T> and the type implements I<Double>,
+ // then the signature pattern I.foo(Object) (the erasure) *should* match.
+ // But [Object] does not match [Double] so we have some work to do...
+ ResolvedTypeX[] resolvedParameters = world.resolve(sig.getParameterTypes());
+ if (!parameterTypes.matches(resolvedParameters, TypePattern.STATIC).alwaysTrue()) {
+ // It could still be a match based on the erasure of a parameterized type
+ // method in our hierarchy.
+ // We need to find out as cheaply as possible.
+ ResolvedMember sigErasure = sig.getErasure();
+ if (sigErasure != null) {
+ ResolvedTypeX[] erasureParameters = world.resolve(sigErasure.getParameterTypes());
+ if (!parameterTypes.matches(erasureParameters,TypePattern.STATIC).alwaysTrue()) {
+ // fail if we don't match the erasure either
+ return false;
+ }
+ } else {
+ // fail if there is no erasure as the params don't match
+ return false;
+ }
}
// If we have matched on parameters, let's just check it isn't because the last parameter in the pattern