From 10255134e6f9e2aa5ab3bd78c6d40b0be52a5e89 Mon Sep 17 00:00:00 2001 From: acolyer Date: Tue, 12 Jul 2005 11:09:22 +0000 Subject: [PATCH] parameterized members remember their erasure and this is used in member matching so that a signature pattern based on the erasure of a signature can match parameterized member declarations. --- weaver/src/org/aspectj/weaver/Member.java | 7 ++ .../org/aspectj/weaver/ResolvedMember.java | 67 ++++++++++++++++++- .../src/org/aspectj/weaver/ResolvedTypeX.java | 52 ++++++++------ .../weaver/patterns/SignaturePattern.java | 23 ++++++- 4 files changed, 126 insertions(+), 23 deletions(-) diff --git a/weaver/src/org/aspectj/weaver/Member.java b/weaver/src/org/aspectj/weaver/Member.java index 20d9e6223..9fe5a35a7 100644 --- a/weaver/src/org/aspectj/weaver/Member.java +++ b/weaver/src/org/aspectj/weaver/Member.java @@ -607,6 +607,10 @@ public class Member implements Comparable, AnnotatedElement { b |= walkUp(acc, (ResolvedTypeX)i.next()); } + if (!b && curr.isParameterized()) { + b = walkUp(acc,curr.getGenericType()); + } + if (!b) { b = curr.lookupMemberNoSupers(this) != null; } @@ -623,6 +627,9 @@ public class Member implements Comparable, AnnotatedElement { 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; } diff --git a/weaver/src/org/aspectj/weaver/ResolvedMember.java b/weaver/src/org/aspectj/weaver/ResolvedMember.java index cd0334780..77bc6e933 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedMember.java +++ b/weaver/src/org/aspectj/weaver/ResolvedMember.java @@ -17,6 +17,7 @@ import java.io.DataInputStream; 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; @@ -33,6 +34,11 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle 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 @@ -72,6 +78,20 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle 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, @@ -338,7 +358,8 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle parameterizedReturnType, getName(), parameterizedParameterTypes, - getExceptions() + getExceptions(), + this ); } @@ -353,5 +374,49 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle return aType; } } + + + /** + * If this member is defined by a parameterized super-type, return the erasure + * of that member. + * For example: + * interface I { T foo(T aTea); } + * class C implements I { + * 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; } diff --git a/weaver/src/org/aspectj/weaver/ResolvedTypeX.java b/weaver/src/org/aspectj/weaver/ResolvedTypeX.java index b183a95ad..752cba7a2 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedTypeX.java +++ b/weaver/src/org/aspectj/weaver/ResolvedTypeX.java @@ -331,29 +331,9 @@ public abstract class ResolvedTypeX extends TypeX implements AnnotatedElement { 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; @@ -1446,4 +1426,36 @@ public abstract class ResolvedTypeX extends TypeX implements AnnotatedElement { 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); + } + } } diff --git a/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java b/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java index 012d7c99a..c981aa798 100644 --- a/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java +++ b/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java @@ -222,8 +222,27 @@ public class SignaturePattern extends PatternNode { 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 and the type implements I, + // 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 -- 2.39.5