diff options
5 files changed, 1386 insertions, 1269 deletions
diff --git a/weaver/src/org/aspectj/weaver/ConcreteTypeMunger.java b/weaver/src/org/aspectj/weaver/ConcreteTypeMunger.java index e51e40a14..75faa5194 100644 --- a/weaver/src/org/aspectj/weaver/ConcreteTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/ConcreteTypeMunger.java @@ -81,5 +81,29 @@ public abstract class ConcreteTypeMunger implements PartialOrder.PartialComparab // ConcreteTypeMunger o = (ConcreteTypeMunger) other; return 0; } + + /** + * ITDs can be made on generic types and 'share' type variables with + * the generic type. In this case we may need to 'tailor' the munger + * for addition to a particulra type. For eaxmple: + * interface I<T> {} + * + * aspect X implements I<String> { + * List<T> I<T>.foo { return null; } + * } + * + * In this case the munger matches X but it matches with the form + * List<String> foo() { return null; } + */ + public boolean isTargetTypeParameterized() { + if (munger==null) return false; + return munger.sharesTypeVariablesWithGenericType(); + } + /** + * For an ITD made on a generic type that shares type variables with + * that target type, this method will tailor the ITD for a particular usage + * of the generic type - either in its raw or parameterized form. + */ + public abstract ConcreteTypeMunger parameterizedFor(ResolvedType targetType); } diff --git a/weaver/src/org/aspectj/weaver/NewMethodTypeMunger.java b/weaver/src/org/aspectj/weaver/NewMethodTypeMunger.java index 1e6a286aa..33e43a605 100644 --- a/weaver/src/org/aspectj/weaver/NewMethodTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/NewMethodTypeMunger.java @@ -64,4 +64,15 @@ public class NewMethodTypeMunger extends ResolvedTypeMunger { if (ResolvedType.matches(ret, member)) return getSignature(); return super.getMatchingSyntheticMember(member, aspectType); } + + /** + * ResolvedTypeMunger.parameterizedFor(ResolvedType) + */ + public ResolvedTypeMunger parameterizedFor(ResolvedType target) { + ResolvedType genericType = target; + if (target.isRawType() || target.isParameterizedType()) genericType = genericType.getGenericType(); + ResolvedMember parameterizedSignature = getSignature().parameterizedWith(target.getTypeParameters(),genericType,target.isParameterizedType()); + return new NewMethodTypeMunger(parameterizedSignature,getSuperMethodsCalled(),typeVariableAliases); + } + } diff --git a/weaver/src/org/aspectj/weaver/ResolvedType.java b/weaver/src/org/aspectj/weaver/ResolvedType.java index 3eacaabe8..ae18931b2 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedType.java +++ b/weaver/src/org/aspectj/weaver/ResolvedType.java @@ -7,22 +7,13 @@ * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: - * PARC initial implementation + * PARC initial implementation * Alexandre Vasseur @AspectJ ITDs * ******************************************************************/ package org.aspectj.weaver; -import org.aspectj.bridge.IMessage; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.bridge.Message; -import org.aspectj.bridge.MessageUtil; -import org.aspectj.util.FuzzyBoolean; -import org.aspectj.weaver.bcel.BcelTypeMunger; -import org.aspectj.weaver.patterns.Declare; -import org.aspectj.weaver.patterns.PerClause; - import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; @@ -35,22 +26,30 @@ import java.util.List; import java.util.Map; import java.util.Set; -public abstract class ResolvedType extends UnresolvedType implements AnnotatedElement { - - private static final ResolvedType[] EMPTY_RESOLVED_TYPE_ARRAY = new ResolvedType[0]; - public static final String PARAMETERIZED_TYPE_IDENTIFIER = "P"; +import org.aspectj.bridge.IMessage; +import org.aspectj.bridge.ISourceLocation; +import org.aspectj.bridge.Message; +import org.aspectj.bridge.MessageUtil; +import org.aspectj.util.FuzzyBoolean; +import org.aspectj.weaver.patterns.Declare; +import org.aspectj.weaver.patterns.PerClause; - private ResolvedType[] resolvedTypeParams; +public abstract class ResolvedType extends UnresolvedType implements AnnotatedElement { + private static final ResolvedType[] EMPTY_RESOLVED_TYPE_ARRAY = new ResolvedType[0]; + public static final String PARAMETERIZED_TYPE_IDENTIFIER = "P"; + + private ResolvedType[] resolvedTypeParams; + protected World world; - + protected ResolvedType(String signature, World world) { super(signature); this.world = world; } - + protected ResolvedType(String signature, String signatureErasure, World world) { - super(signature, signatureErasure); + super(signature,signatureErasure); this.world = world; } @@ -72,29 +71,25 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } public abstract ResolvedMember[] getDeclaredFields(); - public abstract ResolvedMember[] getDeclaredMethods(); - public abstract ResolvedType[] getDeclaredInterfaces(); - public abstract ResolvedMember[] getDeclaredPointcuts(); - /** * Returns a ResolvedType object representing the superclass of this type, or null. * If this represents a java.lang.Object, a primitive type, or void, this - * method returns null. + * method returns null. */ public abstract ResolvedType getSuperclass(); /** - * Returns the modifiers for this type. + * Returns the modifiers for this type. * <p/> * See {@link Class#getModifiers()} for a description * of the weirdness of this methods on primitives and arrays. * * @param world the {@link World} in which the lookup is made. * @return an int representing the modifiers for this type - * @see java.lang.reflect.Modifier + * @see java.lang.reflect.Modifier */ public abstract int getModifiers(); @@ -102,49 +97,50 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl public boolean isMissing() { return false; } - + public ResolvedType[] getAnnotationTypes() { - return EMPTY_RESOLVED_TYPE_ARRAY; + return EMPTY_RESOLVED_TYPE_ARRAY; } - + public final UnresolvedType getSuperclass(World world) { return getSuperclass(); } - + // This set contains pairs of types whose signatures are concatenated // together, this means with a fast lookup we can tell if two types // are equivalent. static Set validBoxing = new HashSet(); - + static { - validBoxing.add("Ljava/lang/Byte;B"); - validBoxing.add("Ljava/lang/Character;C"); - validBoxing.add("Ljava/lang/Double;D"); - validBoxing.add("Ljava/lang/Float;F"); - validBoxing.add("Ljava/lang/Integer;I"); - validBoxing.add("Ljava/lang/Long;J"); - validBoxing.add("Ljava/lang/Short;S"); - validBoxing.add("Ljava/lang/Boolean;Z"); - validBoxing.add("BLjava/lang/Byte;"); - validBoxing.add("CLjava/lang/Character;"); - validBoxing.add("DLjava/lang/Double;"); - validBoxing.add("FLjava/lang/Float;"); - validBoxing.add("ILjava/lang/Integer;"); - validBoxing.add("JLjava/lang/Long;"); - validBoxing.add("SLjava/lang/Short;"); - validBoxing.add("ZLjava/lang/Boolean;"); - } - - - // utilities + validBoxing.add("Ljava/lang/Byte;B"); + validBoxing.add("Ljava/lang/Character;C"); + validBoxing.add("Ljava/lang/Double;D"); + validBoxing.add("Ljava/lang/Float;F"); + validBoxing.add("Ljava/lang/Integer;I"); + validBoxing.add("Ljava/lang/Long;J"); + validBoxing.add("Ljava/lang/Short;S"); + validBoxing.add("Ljava/lang/Boolean;Z"); + validBoxing.add("BLjava/lang/Byte;"); + validBoxing.add("CLjava/lang/Character;"); + validBoxing.add("DLjava/lang/Double;"); + validBoxing.add("FLjava/lang/Float;"); + validBoxing.add("ILjava/lang/Integer;"); + validBoxing.add("JLjava/lang/Long;"); + validBoxing.add("SLjava/lang/Short;"); + validBoxing.add("ZLjava/lang/Boolean;"); + } + + + + // utilities public ResolvedType getResolvedComponentType() { - return null; + return null; } - public World getWorld() { - return world; - } + public World getWorld() { + return world; + } // ---- things from object @@ -155,16 +151,16 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl return super.equals(other); } } - + // ---- difficult things - + /** * returns an iterator through all of the fields of this type, in order * for checking from JVM spec 2ed 5.4.3.2. This means that the order is * <p/> * <ul><li> fields from current class </li> - * <li> recur into direct superinterfaces </li> - * <li> recur into superclass </li> + * <li> recur into direct superinterfaces </li> + * <li> recur into superclass </li> * </ul> * <p/> * We keep a hashSet of interfaces that we've visited so we don't spiral @@ -174,20 +170,20 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl final Iterators.Filter dupFilter = Iterators.dupFilter(); Iterators.Getter typeGetter = new Iterators.Getter() { public Iterator get(Object o) { - return - dupFilter.filter( - ((ResolvedType) o).getDirectSupertypes()); + return + dupFilter.filter( + ((ResolvedType)o).getDirectSupertypes()); } }; Iterators.Getter fieldGetter = new Iterators.Getter() { public Iterator get(Object o) { - return Iterators.array(((ResolvedType) o).getDeclaredFields()); + return Iterators.array(((ResolvedType)o).getDeclaredFields()); } }; - return - Iterators.mapOver( - Iterators.recur(this, typeGetter), - fieldGetter); + return + Iterators.mapOver( + Iterators.recur(this, typeGetter), + fieldGetter); } /** @@ -195,8 +191,8 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl * for checking from JVM spec 2ed 5.4.3.3. This means that the order is * <p/> * <ul><li> methods from current class </li> - * <li> recur into superclass, all the way up, not touching interfaces </li> - * <li> recur into all superinterfaces, in some unspecified order </li> + * <li> recur into superclass, all the way up, not touching interfaces </li> + * <li> recur into all superinterfaces, in some unspecified order </li> * </ul> * <p/> * We keep a hashSet of interfaces that we've visited so we don't spiral @@ -208,41 +204,38 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl final Iterators.Filter dupFilter = Iterators.dupFilter(); Iterators.Getter ifaceGetter = new Iterators.Getter() { public Iterator get(Object o) { - return - dupFilter.filter( - Iterators.array(((ResolvedType) o).getDeclaredInterfaces()) - ); + return + dupFilter.filter( + Iterators.array(((ResolvedType)o).getDeclaredInterfaces()) + ); } }; Iterators.Getter methodGetter = new Iterators.Getter() { public Iterator get(Object o) { - return Iterators.array(((ResolvedType) o).getDeclaredMethods()); + return Iterators.array(((ResolvedType)o).getDeclaredMethods()); } }; - return - Iterators.mapOver( - Iterators.append( - new Iterator() { - ResolvedType curr = ResolvedType.this; - - public boolean hasNext() { - return curr != null; - } - - public Object next() { - ResolvedType ret = curr; - curr = curr.getSuperclass(); - return ret; - } - - public void remove() { - throw new UnsupportedOperationException(); - } - }, - Iterators.recur(this, ifaceGetter)), - methodGetter); + return + Iterators.mapOver( + Iterators.append( + new Iterator() { + ResolvedType curr = ResolvedType.this; + public boolean hasNext() { + return curr != null; + } + public Object next() { + ResolvedType ret = curr; + curr = curr.getSuperclass(); + return ret; + } + public void remove() { + throw new UnsupportedOperationException(); + } + }, + Iterators.recur(this, ifaceGetter)), + methodGetter); } - + /** * Return a list of methods, first those declared on this class, then those declared on the superclass (recurse) and then those declared * on the superinterfaces. The getMethods() call above doesn't quite work the same as it will (through the iterator) return methods @@ -251,31 +244,31 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl public List getMethodsWithoutIterator(boolean includeITDs, boolean allowMissing) { List methods = new ArrayList(); Set knowninterfaces = new HashSet(); - addAndRecurse(knowninterfaces, methods, this, includeITDs, allowMissing); + addAndRecurse(knowninterfaces,methods,this,includeITDs,allowMissing); return methods; } - - private void addAndRecurse(Set knowninterfaces, List collector, ResolvedType rtx, boolean includeITDs, boolean allowMissing) { - collector.addAll(Arrays.asList(rtx.getDeclaredMethods())); // Add the methods declared on this type - // now add all the inter-typed members too - if (includeITDs && rtx.interTypeMungers != null) { - for (Iterator i = interTypeMungers.iterator(); i.hasNext();) { - ConcreteTypeMunger tm = (ConcreteTypeMunger) i.next(); - ResolvedMember rm = tm.getSignature(); - if (rm != null) { // new parent type munger can have null signature... - collector.add(tm.getSignature()); - } - } - } - if (!rtx.equals(ResolvedType.OBJECT)) { - ResolvedType superType = rtx.getSuperclass(); - if (superType != null && !superType.isMissing()) { - addAndRecurse(knowninterfaces, collector, superType, includeITDs, allowMissing); // Recurse if we aren't at the top - } - } - ResolvedType[] interfaces = rtx.getDeclaredInterfaces(); // Go through the interfaces on the way back down - for (int i = 0; i < interfaces.length; i++) { - ResolvedType iface = interfaces[i]; + + private void addAndRecurse(Set knowninterfaces,List collector, ResolvedType rtx, boolean includeITDs, boolean allowMissing) { + collector.addAll(Arrays.asList(rtx.getDeclaredMethods())); // Add the methods declared on this type + // now add all the inter-typed members too + if (includeITDs && rtx.interTypeMungers != null) { + for (Iterator i = interTypeMungers.iterator(); i.hasNext();) { + ConcreteTypeMunger tm = (ConcreteTypeMunger) i.next(); + ResolvedMember rm = tm.getSignature(); + if (rm != null) { // new parent type munger can have null signature... + collector.add(tm.getSignature()); + } + } + } + if (!rtx.equals(ResolvedType.OBJECT)) { + ResolvedType superType = rtx.getSuperclass(); + if (superType != null && !superType.isMissing()) { + addAndRecurse(knowninterfaces,collector,superType,includeITDs,allowMissing); // Recurse if we aren't at the top + } + } + ResolvedType[] interfaces = rtx.getDeclaredInterfaces(); // Go through the interfaces on the way back down + for (int i = 0; i < interfaces.length; i++) { + ResolvedType iface = interfaces[i]; // we need to know if it is an interface from Parent kind munger // as those are used for @AJ ITD and we precisely want to skip those @@ -289,26 +282,26 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } if (!shouldSkip && !knowninterfaces.contains(iface)) { // Dont do interfaces more than once - knowninterfaces.add(iface); - if (allowMissing && iface.isMissing()) { - if (iface instanceof MissingResolvedTypeWithKnownSignature) { - ((MissingResolvedTypeWithKnownSignature) iface).raiseWarningOnMissingInterfaceWhilstFindingMethods(); - } - } else { - addAndRecurse(knowninterfaces, collector, iface, includeITDs, allowMissing); - } - } + knowninterfaces.add(iface); + if (allowMissing && iface.isMissing()) { + if (iface instanceof MissingResolvedTypeWithKnownSignature) { + ((MissingResolvedTypeWithKnownSignature)iface).raiseWarningOnMissingInterfaceWhilstFindingMethods(); + } + } else { + addAndRecurse(knowninterfaces,collector,iface,includeITDs,allowMissing); + } } + } } public ResolvedType[] getResolvedTypeParameters() { - if (resolvedTypeParams == null) { - resolvedTypeParams = world.resolve(typeParameters); - } - return resolvedTypeParams; + if (resolvedTypeParams == null) { + resolvedTypeParams = world.resolve(typeParameters); + } + return resolvedTypeParams; } - - /** + + /** * described in JVM spec 2ed 5.4.3.2 */ public ResolvedMember lookupField(Member m) { @@ -322,19 +315,19 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl public ResolvedMember lookupMethod(Member m) { return lookupMember(m, getMethods()); } - + public ResolvedMember lookupMethodInITDs(Member m) { - if (interTypeMungers != null) { - for (Iterator i = interTypeMungers.iterator(); i.hasNext();) { - ConcreteTypeMunger tm = (ConcreteTypeMunger) i.next(); - if (matches(tm.getSignature(), m)) { - return tm.getSignature(); - } - } - } - return null; - } - + if (interTypeMungers != null) { + for (Iterator i = interTypeMungers.iterator(); i.hasNext();) { + ConcreteTypeMunger tm = (ConcreteTypeMunger) i.next(); + if (matches(tm.getSignature(), m)) { + return tm.getSignature(); + } + } + } + return null; + } + /** * return null if not found */ @@ -345,55 +338,55 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } return null; //ResolvedMember.Missing; //throw new BCException("can't find " + m); - } - + } + /** * return null if not found */ private ResolvedMember lookupMember(Member m, ResolvedMember[] a) { - for (int i = 0; i < a.length; i++) { - ResolvedMember f = a[i]; - if (matches(f, m)) return f; - } - return null; - } - - + for (int i = 0; i < a.length; i++) { + ResolvedMember f = a[i]; + if (matches(f, m)) return f; + } + return null; + } + + /** * Looks for the first member in the hierarchy matching aMember. This method * differs from lookupMember(Member) in that it takes into account parameters * which are type variables - which clearly an unresolved Member cannot do since - * it does not know anything about type variables. + * it does not know anything about type variables. */ - public ResolvedMember lookupResolvedMember(ResolvedMember aMember, boolean allowMissing) { - Iterator toSearch = null; - ResolvedMember found = null; - if ((aMember.getKind() == Member.METHOD) || (aMember.getKind() == Member.CONSTRUCTOR)) { - toSearch = getMethodsWithoutIterator(true, allowMissing).iterator(); - } else { - if (aMember.getKind() != Member.FIELD) - throw new IllegalStateException("I didn't know you would look for members of kind " + aMember.getKind()); - toSearch = getFields(); - } - while (toSearch.hasNext()) { - ResolvedMemberImpl candidate = (ResolvedMemberImpl) toSearch.next(); - if (candidate.matches(aMember)) { - found = candidate; - break; - } - } - - return found; - } - + public ResolvedMember lookupResolvedMember(ResolvedMember aMember,boolean allowMissing) { + Iterator toSearch = null; + ResolvedMember found = null; + if ((aMember.getKind() == Member.METHOD) || (aMember.getKind() == Member.CONSTRUCTOR)) { + toSearch = getMethodsWithoutIterator(true,allowMissing).iterator(); + } else { + if (aMember.getKind() != Member.FIELD) + throw new IllegalStateException("I didn't know you would look for members of kind " + aMember.getKind()); + toSearch = getFields(); + } + while(toSearch.hasNext()) { + ResolvedMemberImpl candidate = (ResolvedMemberImpl) toSearch.next(); + if (candidate.matches(aMember)) { + found = candidate; + break; + } + } + + return found; + } + public static boolean matches(Member m1, Member m2) { if (m1 == null) return m2 == null; if (m2 == null) return false; - + // Check the names boolean equalNames = m1.getName().equals(m2.getName()); if (!equalNames) return false; - + // Check the signatures boolean equalSignatures = m1.getSignature().equals(m2.getSignature()); if (equalSignatures) return true; @@ -402,45 +395,45 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl // the subsig might be ()LFastCar; - where FastCar is a subclass of Car boolean equalCovariantSignatures = m1.getParameterSignature().equals(m2.getParameterSignature()); if (equalCovariantSignatures) return true; - + return false; } - + public static boolean conflictingSignature(Member m1, Member m2) { - if (m1 == null || m2 == null) return false; - + if (m1 == null || m2 == null) return false; + if (!m1.getName().equals(m2.getName())) { return false; } if (m1.getKind() != m2.getKind()) { return false; } - - if (m1.getKind() == Member.FIELD) { - return m1.getDeclaringType().equals(m2.getDeclaringType()); - } else if (m1.getKind() == Member.POINTCUT) { - return true; - } - - UnresolvedType[] p1 = m1.getParameterTypes(); - UnresolvedType[] p2 = m2.getParameterTypes(); - int n = p1.length; - if (n != p2.length) return false; - - for (int i = 0; i < n; i++) { - if (!p1[i].equals(p2[i])) return false; - } - return true; - } - - + + if (m1.getKind() == Member.FIELD) { + return m1.getDeclaringType().equals(m2.getDeclaringType()); + } else if (m1.getKind() == Member.POINTCUT) { + return true; + } + + UnresolvedType[] p1 = m1.getParameterTypes(); + UnresolvedType[] p2 = m2.getParameterTypes(); + int n = p1.length; + if (n != p2.length) return false; + + for (int i=0; i < n; i++) { + if (!p1[i].equals(p2[i])) return false; + } + return true; + } + + /** * returns an iterator through all of the pointcuts of this type, in order * for checking from JVM spec 2ed 5.4.3.2 (as for fields). This means that the order is * <p/> * <ul><li> pointcuts from current class </li> - * <li> recur into direct superinterfaces </li> - * <li> recur into superclass </li> + * <li> recur into direct superinterfaces </li> + * <li> recur into superclass </li> * </ul> * <p/> * We keep a hashSet of interfaces that we've visited so we don't spiral @@ -451,26 +444,26 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl // same order as fields Iterators.Getter typeGetter = new Iterators.Getter() { public Iterator get(Object o) { - return - dupFilter.filter( - ((ResolvedType) o).getDirectSupertypes()); + return + dupFilter.filter( + ((ResolvedType)o).getDirectSupertypes()); } }; Iterators.Getter pointcutGetter = new Iterators.Getter() { public Iterator get(Object o) { //System.err.println("getting for " + o); - return Iterators.array(((ResolvedType) o).getDeclaredPointcuts()); + return Iterators.array(((ResolvedType)o).getDeclaredPointcuts()); } }; - return - Iterators.mapOver( - Iterators.recur(this, typeGetter), - pointcutGetter); + return + Iterators.mapOver( + Iterators.recur(this, typeGetter), + pointcutGetter); } - + public ResolvedPointcutDefinition findPointcut(String name) { //System.err.println("looking for pointcuts " + this); - for (Iterator i = getPointcuts(); i.hasNext();) { + for (Iterator i = getPointcuts(); i.hasNext(); ) { ResolvedPointcutDefinition f = (ResolvedPointcutDefinition) i.next(); //System.err.println(f); if (name.equals(f.getName())) { @@ -479,320 +472,316 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } return null; // should we throw an exception here? } - + + // all about collecting CrosscuttingMembers - //??? collecting data-structure, shouldn't really be a field + //??? collecting data-structure, shouldn't really be a field public CrosscuttingMembers crosscuttingMembers; - public CrosscuttingMembers collectCrosscuttingMembers() { - crosscuttingMembers = new CrosscuttingMembers(this); - crosscuttingMembers.setPerClause(getPerClause()); - crosscuttingMembers.addShadowMungers(collectShadowMungers()); - crosscuttingMembers.addTypeMungers(getTypeMungers()); + public CrosscuttingMembers collectCrosscuttingMembers() { + crosscuttingMembers = new CrosscuttingMembers(this); + crosscuttingMembers.setPerClause(getPerClause()); + crosscuttingMembers.addShadowMungers(collectShadowMungers()); + crosscuttingMembers.addTypeMungers(getTypeMungers()); //FIXME AV - skip but needed ?? or ?? crosscuttingMembers.addLateTypeMungers(getLateTypeMungers()); - crosscuttingMembers.addDeclares(collectDeclares(!this.doesNotExposeShadowMungers())); - crosscuttingMembers.addPrivilegedAccesses(getPrivilegedAccesses()); - - //System.err.println("collected cc members: " + this + ", " + collectDeclares()); - return crosscuttingMembers; - } - - public final Collection collectDeclares(boolean includeAdviceLike) { - if (! this.isAspect()) return Collections.EMPTY_LIST; - - ArrayList ret = new ArrayList(); - //if (this.isAbstract()) { + crosscuttingMembers.addDeclares(collectDeclares(!this.doesNotExposeShadowMungers())); + crosscuttingMembers.addPrivilegedAccesses(getPrivilegedAccesses()); + + //System.err.println("collected cc members: " + this + ", " + collectDeclares()); + return crosscuttingMembers; + } + + public final Collection collectDeclares(boolean includeAdviceLike) { + if (! this.isAspect() ) return Collections.EMPTY_LIST; + + ArrayList ret = new ArrayList(); + //if (this.isAbstract()) { // for (Iterator i = getDeclares().iterator(); i.hasNext();) { // Declare dec = (Declare) i.next(); // if (!dec.isAdviceLike()) ret.add(dec); // } // // if (!includeAdviceLike) return ret; - - if (!this.isAbstract()) { - //ret.addAll(getDeclares()); - final Iterators.Filter dupFilter = Iterators.dupFilter(); - Iterators.Getter typeGetter = new Iterators.Getter() { - public Iterator get(Object o) { - return - dupFilter.filter( - ((ResolvedType) o).getDirectSupertypes()); - } - }; - Iterator typeIterator = Iterators.recur(this, typeGetter); - - while (typeIterator.hasNext()) { - ResolvedType ty = (ResolvedType) typeIterator.next(); - //System.out.println("super: " + ty + ", " + ); - for (Iterator i = ty.getDeclares().iterator(); i.hasNext();) { - Declare dec = (Declare) i.next(); - if (dec.isAdviceLike()) { - if (includeAdviceLike) ret.add(dec); - } else { - ret.add(dec); - } - } - } - } - - return ret; - } - - + + if (!this.isAbstract()) { + //ret.addAll(getDeclares()); + final Iterators.Filter dupFilter = Iterators.dupFilter(); + Iterators.Getter typeGetter = new Iterators.Getter() { + public Iterator get(Object o) { + return + dupFilter.filter( + ((ResolvedType)o).getDirectSupertypes()); + } + }; + Iterator typeIterator = Iterators.recur(this, typeGetter); + + while (typeIterator.hasNext()) { + ResolvedType ty = (ResolvedType) typeIterator.next(); + //System.out.println("super: " + ty + ", " + ); + for (Iterator i = ty.getDeclares().iterator(); i.hasNext();) { + Declare dec = (Declare) i.next(); + if (dec.isAdviceLike()) { + if (includeAdviceLike) ret.add(dec); + } else { + ret.add(dec); + } + } + } + } + + return ret; + } + + + + private final Collection collectShadowMungers() { if (! this.isAspect() || this.isAbstract() || this.doesNotExposeShadowMungers()) return Collections.EMPTY_LIST; - ArrayList acc = new ArrayList(); + ArrayList acc = new ArrayList(); final Iterators.Filter dupFilter = Iterators.dupFilter(); Iterators.Getter typeGetter = new Iterators.Getter() { public Iterator get(Object o) { - return - dupFilter.filter( - ((ResolvedType) o).getDirectSupertypes()); + return + dupFilter.filter( + ((ResolvedType)o).getDirectSupertypes()); } }; Iterator typeIterator = Iterators.recur(this, typeGetter); while (typeIterator.hasNext()) { ResolvedType ty = (ResolvedType) typeIterator.next(); - acc.addAll(ty.getDeclaredShadowMungers()); + acc.addAll(ty.getDeclaredShadowMungers()); } - + return acc; } - - protected boolean doesNotExposeShadowMungers() { - return false; - } + + protected boolean doesNotExposeShadowMungers() { + return false; + } public PerClause getPerClause() { return null; } - protected Collection getDeclares() { - return Collections.EMPTY_LIST; - } - + protected Collection getDeclares() { + return Collections.EMPTY_LIST; + } + protected Collection getTypeMungers() { return Collections.EMPTY_LIST; } - + protected Collection getPrivilegedAccesses() { return Collections.EMPTY_LIST; } + // ---- useful things - - public final boolean isInterface() { + + public final boolean isInterface() { return Modifier.isInterface(getModifiers()); } - - public final boolean isAbstract() { + + public final boolean isAbstract() { return Modifier.isAbstract(getModifiers()); } - + public boolean isClass() { - return false; + return false; } - + public boolean isAspect() { - return false; + return false; } public boolean isAnnotationStyleAspect() { - return false; + return false; } /** * Note: Only overridden by Name subtype. */ public boolean isEnum() { - return false; + return false; } - + /** * Note: Only overridden by Name subtype. */ public boolean isAnnotation() { - return false; + return false; } - - /** - * Note: Only overridden by Name subtype - */ - public void addAnnotation(AnnotationX annotationX) { - throw new RuntimeException("ResolvedType.addAnnotation() should never be called"); - } - + /** * Note: Only overridden by Name subtype */ - public AnnotationX[] getAnnotations() { - throw new RuntimeException("ResolvedType.getAnnotations() should never be called"); - } - - + public void addAnnotation(AnnotationX annotationX) { + throw new RuntimeException("ResolvedType.addAnnotation() should never be called"); + } + + /** + * Note: Only overridden by Name subtype + */ + public AnnotationX[] getAnnotations() { + throw new RuntimeException("ResolvedType.getAnnotations() should never be called"); + } + + /** * Note: Only overridden by Name subtype. */ public boolean isAnnotationWithRuntimeRetention() { return false; } - + public boolean isSynthetic() { - return signature.indexOf("$ajc") != -1; + return signature.indexOf("$ajc") != -1; } - + public final boolean isFinal() { return Modifier.isFinal(getModifiers()); } - protected Map /*Type variable name -> UnresolvedType*/ getMemberParameterizationMap() { - if (!isParameterizedType()) return Collections.EMPTY_MAP; - TypeVariable[] tvs = getGenericType().getTypeVariables(); - Map parameterizationMap = new HashMap(); - for (int i = 0; i < tvs.length; i++) { - parameterizationMap.put(tvs[i].getName(), typeParameters[i]); - } - return parameterizationMap; - } + protected Map /*Type variable name -> UnresolvedType*/ getMemberParameterizationMap() { + if (!isParameterizedType()) return Collections.EMPTY_MAP; + TypeVariable[] tvs = getGenericType().getTypeVariables(); + Map parameterizationMap = new HashMap(); + for (int i = 0; i < tvs.length; i++) { + parameterizationMap.put(tvs[i].getName(), typeParameters[i]); + } + return parameterizationMap; + } + + + public Collection getDeclaredAdvice() { + List l = new ArrayList(); + ResolvedMember[] methods = getDeclaredMethods(); + if (isParameterizedType()) methods = getGenericType().getDeclaredMethods(); + Map typeVariableMap = getMemberParameterizationMap(); + for (int i=0, len = methods.length; i < len; i++) { + ShadowMunger munger = methods[i].getAssociatedShadowMunger(); + if (munger != null) { + if (this.isParameterizedType()) { + //munger.setPointcut(munger.getPointcut().parameterizeWith(typeVariableMap)); + munger = munger.parameterizeWith(typeVariableMap); + if (munger instanceof Advice) { + Advice advice = (Advice) munger; + // update to use the parameterized signature... + UnresolvedType[] ptypes = methods[i].getGenericParameterTypes() ; + UnresolvedType[] newPTypes = new UnresolvedType[ptypes.length]; + for (int j = 0; j < ptypes.length; j++) { + if (ptypes[j] instanceof TypeVariableReferenceType) { + TypeVariableReferenceType tvrt = (TypeVariableReferenceType) ptypes[j]; + if (typeVariableMap.containsKey(tvrt.getTypeVariable().getName())) { + newPTypes[j] = (UnresolvedType) typeVariableMap.get(tvrt.getTypeVariable().getName()); + } else { + newPTypes[j] = ptypes[j]; + } + } else { + newPTypes[j] = ptypes[j]; + } + } + advice.setBindingParameterTypes(newPTypes); + } + } + munger.setDeclaringType(this); + l.add(munger); + } + } + return l; + } + + public Collection getDeclaredShadowMungers() { + Collection c = getDeclaredAdvice(); + return c; + } + + // ---- only for testing! + + + public ResolvedMember[] getDeclaredJavaFields() { + return filterInJavaVisible(getDeclaredFields()); + } + public ResolvedMember[] getDeclaredJavaMethods() { + return filterInJavaVisible(getDeclaredMethods()); + } + public ShadowMunger[] getDeclaredShadowMungersArray() { + List l = (List) getDeclaredShadowMungers(); + return (ShadowMunger[]) l.toArray(new ShadowMunger[l.size()]); + } + private ResolvedMember[] filterInJavaVisible(ResolvedMember[] ms) { + List l = new ArrayList(); + for (int i=0, len = ms.length; i < len; i++) { + if (! ms[i].isAjSynthetic() && ms[i].getAssociatedShadowMunger() == null) { + l.add(ms[i]); + } + } + return (ResolvedMember[]) l.toArray(new ResolvedMember[l.size()]); + } + + public abstract ISourceContext getSourceContext(); - public Collection getDeclaredAdvice() { - List l = new ArrayList(); - ResolvedMember[] methods = getDeclaredMethods(); - if (isParameterizedType()) methods = getGenericType().getDeclaredMethods(); - Map typeVariableMap = getMemberParameterizationMap(); - for (int i = 0, len = methods.length; i < len; i++) { - ShadowMunger munger = methods[i].getAssociatedShadowMunger(); - if (munger != null) { - if (this.isParameterizedType()) { - //munger.setPointcut(munger.getPointcut().parameterizeWith(typeVariableMap)); - munger = munger.parameterizeWith(typeVariableMap); - if (munger instanceof Advice) { - Advice advice = (Advice) munger; - // update to use the parameterized signature... - UnresolvedType[] ptypes = methods[i].getGenericParameterTypes(); - UnresolvedType[] newPTypes = new UnresolvedType[ptypes.length]; - for (int j = 0; j < ptypes.length; j++) { - if (ptypes[j] instanceof TypeVariableReferenceType) { - TypeVariableReferenceType tvrt = (TypeVariableReferenceType) ptypes[j]; - if (typeVariableMap.containsKey(tvrt.getTypeVariable().getName())) { - newPTypes[j] = (UnresolvedType) typeVariableMap.get(tvrt.getTypeVariable().getName()); - } else { - newPTypes[j] = ptypes[j]; - } - } else { - newPTypes[j] = ptypes[j]; - } - } - advice.setBindingParameterTypes(newPTypes); - } - } - munger.setDeclaringType(this); - l.add(munger); - } - } - return l; - } - - public Collection getDeclaredShadowMungers() { - Collection c = getDeclaredAdvice(); - return c; - } - - // ---- only for testing! - - - public ResolvedMember[] getDeclaredJavaFields() { - return filterInJavaVisible(getDeclaredFields()); - } - - public ResolvedMember[] getDeclaredJavaMethods() { - return filterInJavaVisible(getDeclaredMethods()); - } - - public ShadowMunger[] getDeclaredShadowMungersArray() { - List l = (List) getDeclaredShadowMungers(); - return (ShadowMunger[]) l.toArray(new ShadowMunger[l.size()]); - } - - private ResolvedMember[] filterInJavaVisible(ResolvedMember[] ms) { - List l = new ArrayList(); - for (int i = 0, len = ms.length; i < len; i++) { - if (! ms[i].isAjSynthetic() && ms[i].getAssociatedShadowMunger() == null) { - l.add(ms[i]); - } - } - return (ResolvedMember[]) l.toArray(new ResolvedMember[l.size()]); - } - - public abstract ISourceContext getSourceContext(); - // ---- fields - + public static final ResolvedType[] NONE = new ResolvedType[0]; - public static final Primitive BYTE = new Primitive("B", 1, 0); - public static final Primitive CHAR = new Primitive("C", 1, 1); - public static final Primitive DOUBLE = new Primitive("D", 2, 2); - public static final Primitive FLOAT = new Primitive("F", 1, 3); - public static final Primitive INT = new Primitive("I", 1, 4); - public static final Primitive LONG = new Primitive("J", 2, 5); - public static final Primitive SHORT = new Primitive("S", 1, 6); - public static final Primitive VOID = new Primitive("V", 0, 8); + public static final Primitive BYTE = new Primitive("B", 1, 0); + public static final Primitive CHAR = new Primitive("C", 1, 1); + public static final Primitive DOUBLE = new Primitive("D", 2, 2); + public static final Primitive FLOAT = new Primitive("F", 1, 3); + public static final Primitive INT = new Primitive("I", 1, 4); + public static final Primitive LONG = new Primitive("J", 2, 5); + public static final Primitive SHORT = new Primitive("S", 1, 6); + public static final Primitive VOID = new Primitive("V", 0, 8); public static final Primitive BOOLEAN = new Primitive("Z", 1, 7); - public static final Missing MISSING = new Missing(); - + public static final Missing MISSING = new Missing(); + // ---- types public static ResolvedType makeArray(ResolvedType type, int dim) { - if (dim == 0) return type; - ResolvedType array = new Array("[" + type.getSignature(), type.getWorld(), type); - return makeArray(array, dim - 1); + if (dim == 0) return type; + ResolvedType array = new Array("[" + type.getSignature(),type.getWorld(),type); + return makeArray(array,dim-1); } - + static class Array extends ResolvedType { ResolvedType componentType; - Array(String s, World world, ResolvedType componentType) { super(s, world); this.componentType = componentType; } - public final ResolvedMember[] getDeclaredFields() { return ResolvedMember.NONE; } - public final ResolvedMember[] getDeclaredMethods() { // ??? should this return clone? Probably not... // If it ever does, here is the code: // ResolvedMember cloneMethod = // new ResolvedMember(Member.METHOD,this,Modifier.PUBLIC,UnresolvedType.OBJECT,"clone",new UnresolvedType[]{}); // return new ResolvedMember[]{cloneMethod}; - return ResolvedMember.NONE; + return ResolvedMember.NONE; } - public final ResolvedType[] getDeclaredInterfaces() { return - new ResolvedType[]{ - world.getCoreType(CLONEABLE), - world.getCoreType(SERIALIZABLE) - }; + new ResolvedType[] { + world.getCoreType(CLONEABLE), + world.getCoreType(SERIALIZABLE) + }; } - public final ResolvedMember[] getDeclaredPointcuts() { return ResolvedMember.NONE; } - + public boolean hasAnnotation(UnresolvedType ofType) { - return false; + return false; } - + public final ResolvedType getSuperclass() { return world.getCoreType(OBJECT); } - public final boolean isAssignableFrom(ResolvedType o) { if (! o.isArray()) return false; if (o.getComponentType().isPrimitiveType()) { @@ -801,13 +790,13 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl return getComponentType().resolve(world).isAssignableFrom(o.getComponentType().resolve(world)); } } - + public boolean isAssignableFrom(ResolvedType o, boolean allowMissing) { - return isAssignableFrom(o); + return isAssignableFrom(o); } - + public final boolean isCoerceableFrom(ResolvedType o) { - if (o.equals(UnresolvedType.OBJECT) || + if (o.equals(UnresolvedType.OBJECT) || o.equals(UnresolvedType.SERIALIZABLE) || o.equals(UnresolvedType.CLONEABLE)) { return true; @@ -819,119 +808,101 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl return getComponentType().resolve(world).isCoerceableFrom(o.getComponentType().resolve(world)); } } - public final int getModifiers() { int mask = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED; return (componentType.getModifiers() & mask) | Modifier.FINAL; } - public UnresolvedType getComponentType() { return componentType; } - public ResolvedType getResolvedComponentType() { return componentType; } - public ISourceContext getSourceContext() { - return getResolvedComponentType().getSourceContext(); + return getResolvedComponentType().getSourceContext(); } } - + static class Primitive extends ResolvedType { private int size; private int index; - Primitive(String signature, int size, int index) { super(signature, null); this.size = size; this.index = index; } - public final int getSize() { return size; } - public final int getModifiers() { return Modifier.PUBLIC | Modifier.FINAL; } - public final boolean isPrimitiveType() { return true; } - public boolean hasAnnotation(UnresolvedType ofType) { - return false; + return false; } - public final boolean isAssignableFrom(ResolvedType other) { if (!other.isPrimitiveType()) { - if (!world.isInJava5Mode()) return false; - return validBoxing.contains(this.getSignature() + other.getSignature()); + if (!world.isInJava5Mode()) return false; + return validBoxing.contains(this.getSignature()+other.getSignature()); } - return assignTable[((Primitive) other).index][index]; + return assignTable[((Primitive)other).index][index]; } - public final boolean isAssignableFrom(ResolvedType other, boolean allowMissing) { - return isAssignableFrom(other); - } - + return isAssignableFrom(other); + } public final boolean isCoerceableFrom(ResolvedType other) { if (this == other) return true; if (! other.isPrimitiveType()) return false; - if (index > 6 || ((Primitive) other).index > 6) return false; + if (index > 6 || ((Primitive)other).index > 6) return false; return true; } - public ResolvedType resolve(World world) { this.world = world; return super.resolve(world); } - public final boolean needsNoConversionFrom(ResolvedType other) { if (! other.isPrimitiveType()) return false; - return noConvertTable[((Primitive) other).index][index]; - } - - private static final boolean[][] assignTable = - {// to: B C D F I J S V Z from - {true, true, true, true, true, true, true, false, false}, // B - {false, true, true, true, true, true, false, false, false}, // C - {false, false, true, false, false, false, false, false, false}, // D - {false, false, true, true, false, false, false, false, false}, // F - {false, false, true, true, true, true, false, false, false}, // I - {false, false, true, true, false, true, false, false, false}, // J - {false, false, true, true, true, true, true, false, false}, // S - {false, false, false, false, false, false, false, true, false}, // V - {false, false, false, false, false, false, false, false, true}, // Z - }; - private static final boolean[][] noConvertTable = - {// to: B C D F I J S V Z from - {true, true, false, false, true, false, true, false, false}, // B - {false, true, false, false, true, false, false, false, false}, // C - {false, false, true, false, false, false, false, false, false}, // D - {false, false, false, true, false, false, false, false, false}, // F - {false, false, false, false, true, false, false, false, false}, // I - {false, false, false, false, false, true, false, false, false}, // J - {false, false, false, false, true, false, true, false, false}, // S - {false, false, false, false, false, false, false, true, false}, // V - {false, false, false, false, false, false, false, false, true}, // Z - }; - + return noConvertTable[((Primitive)other).index][index]; + } + private static final boolean[][] assignTable = + {// to: B C D F I J S V Z from + { true , true , true , true , true , true , true , false, false }, // B + { false, true , true , true , true , true , false, false, false }, // C + { false, false, true , false, false, false, false, false, false }, // D + { false, false, true , true , false, false, false, false, false }, // F + { false, false, true , true , true , true , false, false, false }, // I + { false, false, true , true , false, true , false, false, false }, // J + { false, false, true , true , true , true , true , false, false }, // S + { false, false, false, false, false, false, false, true , false }, // V + { false, false, false, false, false, false, false, false, true }, // Z + }; + private static final boolean[][] noConvertTable = + {// to: B C D F I J S V Z from + { true , true , false, false, true , false, true , false, false }, // B + { false, true , false, false, true , false, false, false, false }, // C + { false, false, true , false, false, false, false, false, false }, // D + { false, false, false, true , false, false, false, false, false }, // F + { false, false, false, false, true , false, false, false, false }, // I + { false, false, false, false, false, true , false, false, false }, // J + { false, false, false, false, true , false, true , false, false }, // S + { false, false, false, false, false, false, false, true , false }, // V + { false, false, false, false, false, false, false, false, true }, // Z + }; + // ---- - + public final ResolvedMember[] getDeclaredFields() { return ResolvedMember.NONE; } - public final ResolvedMember[] getDeclaredMethods() { return ResolvedMember.NONE; } - public final ResolvedType[] getDeclaredInterfaces() { return ResolvedType.NONE; } - public final ResolvedMember[] getDeclaredPointcuts() { return ResolvedMember.NONE; } @@ -939,41 +910,37 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl public final ResolvedType getSuperclass() { return null; } - + public ISourceContext getSourceContext() { - return null; + return null; } - + } static class Missing extends ResolvedType { Missing() { super(MISSING_NAME, null); - } + } // public final String toString() { // return "<missing>"; // } - public final String getName() { - return MISSING_NAME; + return MISSING_NAME; } - + public final boolean isMissing() { return true; } - + public boolean hasAnnotation(UnresolvedType ofType) { - return false; + return false; } - public final ResolvedMember[] getDeclaredFields() { return ResolvedMember.NONE; } - public final ResolvedMember[] getDeclaredMethods() { return ResolvedMember.NONE; } - public final ResolvedType[] getDeclaredInterfaces() { return ResolvedType.NONE; } @@ -981,148 +948,141 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl public final ResolvedMember[] getDeclaredPointcuts() { return ResolvedMember.NONE; } - public final ResolvedType getSuperclass() { return null; } - public final int getModifiers() { return 0; } - public final boolean isAssignableFrom(ResolvedType other) { return false; - } - + } public final boolean isAssignableFrom(ResolvedType other, boolean allowMissing) { return false; - } - + } public final boolean isCoerceableFrom(ResolvedType other) { return false; - } - + } public boolean needsNoConversionFrom(ResolvedType other) { return false; } - public ISourceContext getSourceContext() { - return null; + return null; } } - /** + /** * Look up a member, takes into account any ITDs on this type. * return null if not found */ - public ResolvedMember lookupMemberNoSupers(Member member) { - ResolvedMember ret = lookupDirectlyDeclaredMemberNoSupers(member); - if (ret == null && interTypeMungers != null) { - for (Iterator i = interTypeMungers.iterator(); i.hasNext();) { - ConcreteTypeMunger tm = (ConcreteTypeMunger) i.next(); - if (matches(tm.getSignature(), member)) { - return tm.getSignature(); - } - } - } - return ret; - } - - public ResolvedMember lookupMemberWithSupersAndITDs(Member member) { - ResolvedMember ret = lookupMemberNoSupers(member); - if (ret != null) return ret; - - ResolvedType supert = getSuperclass(); - if (supert != null) { - ret = supert.lookupMemberNoSupers(member); - } - - return ret; - } - - /** - * as lookupMemberNoSupers, but does not include ITDs + public ResolvedMember lookupMemberNoSupers(Member member) { + ResolvedMember ret = lookupDirectlyDeclaredMemberNoSupers(member); + if (ret == null && interTypeMungers != null) { + for (Iterator i = interTypeMungers.iterator(); i.hasNext();) { + ConcreteTypeMunger tm = (ConcreteTypeMunger) i.next(); + if (matches(tm.getSignature(), member)) { + return tm.getSignature(); + } + } + } + return ret; + } + + public ResolvedMember lookupMemberWithSupersAndITDs(Member member) { + ResolvedMember ret = lookupMemberNoSupers(member); + if (ret != null) return ret; + + ResolvedType supert = getSuperclass(); + if (supert != null) { + ret = supert.lookupMemberNoSupers(member); + } + + return ret; + } + + /** + * as lookupMemberNoSupers, but does not include ITDs * - * @param member - * @return - */ - public ResolvedMember lookupDirectlyDeclaredMemberNoSupers(Member member) { - ResolvedMember ret; - if (member.getKind() == Member.FIELD) { - ret = lookupMember(member, getDeclaredFields()); - } else { - // assert member.getKind() == Member.METHOD || member.getKind() == Member.CONSTRUCTOR - ret = lookupMember(member, getDeclaredMethods()); - } - return ret; - } - - /** - * This lookup has specialized behaviour - a null result tells the - * EclipseTypeMunger that it should make a default implementation of a - * method on this type. + * @param member + * @return + */ + public ResolvedMember lookupDirectlyDeclaredMemberNoSupers(Member member) { + ResolvedMember ret; + if (member.getKind() == Member.FIELD) { + ret = lookupMember(member, getDeclaredFields()); + } else { + // assert member.getKind() == Member.METHOD || member.getKind() == Member.CONSTRUCTOR + ret = lookupMember(member, getDeclaredMethods()); + } + return ret; + } + + /** + * This lookup has specialized behaviour - a null result tells the + * EclipseTypeMunger that it should make a default implementation of a + * method on this type. * - * @param member - * @return - */ - public ResolvedMember lookupMemberIncludingITDsOnInterfaces(Member member) { - return lookupMemberIncludingITDsOnInterfaces(member, this); - } - - private ResolvedMember lookupMemberIncludingITDsOnInterfaces(Member member, ResolvedType onType) { - ResolvedMember ret = onType.lookupMemberNoSupers(member); - if (ret != null) { - return ret; - } else { - ResolvedType superType = onType.getSuperclass(); - if (superType != null) { - ret = lookupMemberIncludingITDsOnInterfaces(member, superType); - } - if (ret == null) { - // try interfaces then, but only ITDs now... - ResolvedType[] superInterfaces = onType.getDeclaredInterfaces(); - for (int i = 0; i < superInterfaces.length; i++) { - ret = superInterfaces[i].lookupMethodInITDs(member); - if (ret != null) return ret; - } - } - } - return ret; - } - - protected List interTypeMungers = new ArrayList(0); - - public List getInterTypeMungers() { - return interTypeMungers; - } - + * @param member + * @return + */ + public ResolvedMember lookupMemberIncludingITDsOnInterfaces(Member member) { + return lookupMemberIncludingITDsOnInterfaces(member, this); + } + + private ResolvedMember lookupMemberIncludingITDsOnInterfaces(Member member, ResolvedType onType) { + ResolvedMember ret = onType.lookupMemberNoSupers(member); + if (ret != null) { + return ret; + } else { + ResolvedType superType = onType.getSuperclass(); + if (superType != null) { + ret = lookupMemberIncludingITDsOnInterfaces(member,superType); + } + if (ret == null) { + // try interfaces then, but only ITDs now... + ResolvedType[] superInterfaces = onType.getDeclaredInterfaces(); + for (int i = 0; i < superInterfaces.length; i++) { + ret = superInterfaces[i].lookupMethodInITDs(member); + if (ret != null) return ret; + } + } + } + return ret; + } + + protected List interTypeMungers = new ArrayList(0); + + public List getInterTypeMungers() { + return interTypeMungers; + } + public List getInterTypeParentMungers() { - List l = new ArrayList(); - for (Iterator iter = interTypeMungers.iterator(); iter.hasNext();) { - ConcreteTypeMunger element = (ConcreteTypeMunger) iter.next(); - if (element.getMunger() instanceof NewParentTypeMunger) l.add(element); - } - return l; - } - - /** - * ??? This method is O(N*M) where N = number of methods and M is number of - * inter-type declarations in my super - */ - public List getInterTypeMungersIncludingSupers() { + List l = new ArrayList(); + for (Iterator iter = interTypeMungers.iterator(); iter.hasNext();) { + ConcreteTypeMunger element = (ConcreteTypeMunger) iter.next(); + if (element.getMunger() instanceof NewParentTypeMunger) l.add(element); + } + return l; + } + + /** + * ??? This method is O(N*M) where N = number of methods and M is number of + * inter-type declarations in my super + */ + public List getInterTypeMungersIncludingSupers() { ArrayList ret = new ArrayList(); collectInterTypeMungers(ret); return ret; } - + public List getInterTypeParentMungersIncludingSupers() { - ArrayList ret = new ArrayList(); - collectInterTypeParentMungers(ret); - return ret; + ArrayList ret = new ArrayList(); + collectInterTypeParentMungers(ret); + return ret; } - + private void collectInterTypeParentMungers(List collector) { for (Iterator iter = getDirectSupertypes(); iter.hasNext();) { ResolvedType superType = (ResolvedType) iter.next(); @@ -1130,44 +1090,45 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } collector.addAll(getInterTypeParentMungers()); } - - + + protected void collectInterTypeMungers(List collector) { for (Iterator iter = getDirectSupertypes(); iter.hasNext();) { - ResolvedType superType = (ResolvedType) iter.next(); + ResolvedType superType = (ResolvedType) iter.next(); superType.collectInterTypeMungers(collector); - } - + } + outer: for (Iterator iter1 = collector.iterator(); iter1.hasNext();) { ConcreteTypeMunger superMunger = (ConcreteTypeMunger) iter1.next(); - if (superMunger.getSignature() == null) continue; - - if (!superMunger.getSignature().isAbstract()) continue; - + if ( superMunger.getSignature() == null) continue; + + if ( !superMunger.getSignature().isAbstract()) continue; + for (Iterator iter = getInterTypeMungers().iterator(); iter.hasNext();) { - ConcreteTypeMunger myMunger = (ConcreteTypeMunger) iter.next(); + ConcreteTypeMunger myMunger = (ConcreteTypeMunger) iter.next(); if (conflictingSignature(myMunger.getSignature(), superMunger.getSignature())) { iter1.remove(); continue outer; } } - + if (!superMunger.getSignature().isPublic()) continue; - - for (Iterator iter = getMethods(); iter.hasNext();) { - ResolvedMember method = (ResolvedMember) iter.next(); + + for (Iterator iter = getMethods(); iter.hasNext(); ) { + ResolvedMember method = (ResolvedMember)iter.next(); if (conflictingSignature(method, superMunger.getSignature())) { iter1.remove(); continue outer; } } } - + collector.addAll(getInterTypeMungers()); } - - + + + /** * Check: * 1) That we don't have any abstract type mungers unless this type is abstract. @@ -1175,56 +1136,56 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl */ public void checkInterTypeMungers() { if (isAbstract()) return; - + boolean itdProblem = false; - + for (Iterator iter = getInterTypeMungersIncludingSupers().iterator(); iter.hasNext();) { - ConcreteTypeMunger munger = (ConcreteTypeMunger) iter.next(); - itdProblem = checkAbstractDeclaration(munger) || itdProblem; // Rule 2 + ConcreteTypeMunger munger = (ConcreteTypeMunger) iter.next(); + itdProblem = checkAbstractDeclaration(munger) || itdProblem; // Rule 2 } - + if (itdProblem) return; // If the rules above are broken, return right now - - for (Iterator iter = getInterTypeMungersIncludingSupers().iterator(); iter.hasNext();) { - ConcreteTypeMunger munger = (ConcreteTypeMunger) iter.next(); + + for (Iterator iter = getInterTypeMungersIncludingSupers().iterator(); iter.hasNext();) { + ConcreteTypeMunger munger = (ConcreteTypeMunger) iter.next(); if (munger.getSignature() != null && munger.getSignature().isAbstract()) { // Rule 1 if (munger.getMunger().getKind() == ResolvedTypeMunger.MethodDelegate) { ;//ignore for @AJ ITD as munger.getSingature() is the interface method hence abstract } else { - world.getMessageHandler().handleMessage( - new Message("must implement abstract inter-type declaration: " + munger.getSignature(), - "", IMessage.ERROR, getSourceLocation(), null, - new ISourceLocation[]{getMungerLocation(munger)})); - } + world.getMessageHandler().handleMessage( + new Message("must implement abstract inter-type declaration: " + munger.getSignature(), + "", IMessage.ERROR, getSourceLocation(), null, + new ISourceLocation[] { getMungerLocation(munger) })); } - } + } } - + } + /** * See PR70794. This method checks that if an abstract inter-type method declaration is made on * an interface then it must also be public. * This is a compiler limitation that could be made to work in the future (if someone * provides a worthwhile usecase) - * + * * @return indicates if the munger failed the check */ private boolean checkAbstractDeclaration(ConcreteTypeMunger munger) { - if (munger.getMunger() != null && (munger.getMunger() instanceof NewMethodTypeMunger)) { - ResolvedMember itdMember = munger.getSignature(); - ResolvedType onType = itdMember.getDeclaringType().resolve(world); - if (onType.isInterface() && itdMember.isAbstract() && !itdMember.isPublic()) { - world.getMessageHandler().handleMessage( - new Message(WeaverMessages.format(WeaverMessages.ITD_ABSTRACT_MUST_BE_PUBLIC_ON_INTERFACE, munger.getSignature(), onType), "", - Message.ERROR, getSourceLocation(), null, - new ISourceLocation[]{getMungerLocation(munger)}) - ); - return true; - } - } - return false; - } - + if (munger.getMunger()!=null && (munger.getMunger() instanceof NewMethodTypeMunger)) { + ResolvedMember itdMember = munger.getSignature(); + ResolvedType onType = itdMember.getDeclaringType().resolve(world); + if (onType.isInterface() && itdMember.isAbstract() && !itdMember.isPublic()) { + world.getMessageHandler().handleMessage( + new Message(WeaverMessages.format(WeaverMessages.ITD_ABSTRACT_MUST_BE_PUBLIC_ON_INTERFACE,munger.getSignature(),onType),"", + Message.ERROR,getSourceLocation(),null, + new ISourceLocation[]{getMungerLocation(munger)}) + ); + return true; + } + } + return false; + } + /** * Get a source location for the munger. * Until intertype mungers remember where they came from, the source location @@ -1232,13 +1193,13 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl * source location for the aspect containing the ITD. */ private ISourceLocation getMungerLocation(ConcreteTypeMunger munger) { - ISourceLocation sloc = munger.getSourceLocation(); - if (sloc == null) { - sloc = munger.getAspectType().getSourceLocation(); - } - return sloc; + ISourceLocation sloc = munger.getSourceLocation(); + if (sloc == null) { + sloc = munger.getAspectType().getSourceLocation(); + } + return sloc; } - + /** * Returns a ResolvedType object representing the declaring type of this type, or * null if this type does not represent a non-package-level-type. @@ -1251,424 +1212,524 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl * @return the declaring UnresolvedType object, or null. */ public ResolvedType getDeclaringType() { - if (isArray()) return null; - String name = getName(); - int lastDollar = name.lastIndexOf('$'); - while (lastDollar != -1) { - ResolvedType ret = world.resolve(UnresolvedType.forName(name.substring(0, lastDollar)), true); - if (ret != ResolvedType.MISSING) return ret; - lastDollar = name.lastIndexOf('$', lastDollar - 1); - } - return null; - } - - - public static boolean isVisible(int modifiers, ResolvedType targetType, ResolvedType fromType) { - //System.err.println("mod: " + modifiers + ", " + targetType + " and " + fromType); - - if (Modifier.isPublic(modifiers)) { - return true; - } else if (Modifier.isPrivate(modifiers)) { - return targetType.getOutermostType().equals(fromType.getOutermostType()); - } else if (Modifier.isProtected(modifiers)) { - return samePackage(targetType, fromType) || targetType.isAssignableFrom(fromType); - } else { // package-visible - return samePackage(targetType, fromType); - } - } - - public static boolean hasBridgeModifier(int modifiers) { - return (modifiers & Constants.ACC_BRIDGE) != 0; - } - - private static boolean samePackage( - ResolvedType targetType, + if (isArray()) return null; + String name = getName(); + int lastDollar = name.lastIndexOf('$'); + while (lastDollar != -1) { + ResolvedType ret = world.resolve(UnresolvedType.forName(name.substring(0, lastDollar)), true); + if (ret != ResolvedType.MISSING) return ret; + lastDollar = name.lastIndexOf('$', lastDollar-1); + } + return null; + } + + + public static boolean isVisible(int modifiers, ResolvedType targetType, ResolvedType fromType) { + //System.err.println("mod: " + modifiers + ", " + targetType + " and " + fromType); + + if (Modifier.isPublic(modifiers)) { + return true; + } else if (Modifier.isPrivate(modifiers)) { + return targetType.getOutermostType().equals(fromType.getOutermostType()); + } else if (Modifier.isProtected(modifiers)) { + return samePackage(targetType, fromType) || targetType.isAssignableFrom(fromType); + } else { // package-visible + return samePackage(targetType, fromType); + } + } + + public static boolean hasBridgeModifier(int modifiers) { + return (modifiers & Constants.ACC_BRIDGE)!=0; + } + + private static boolean samePackage( + ResolvedType targetType, ResolvedType fromType) { - String p1 = targetType.getPackageName(); - String p2 = fromType.getPackageName(); - if (p1 == null) return p2 == null; - if (p2 == null) return false; - return p1.equals(p2); + String p1 = targetType.getPackageName(); + String p2 = fromType.getPackageName(); + if (p1 == null) return p2 == null; + if (p2 == null) return false; + return p1.equals(p2); + } + + /** + * Checks if the generic type for 'this' and the generic type for 'other' are the same - + * it can be passed raw or parameterized versions and will just compare the underlying + * generic type. + */ + private boolean genericTypeEquals(ResolvedType other) { + ResolvedType rt = other; + if (rt.isParameterizedType() || rt.isRawType()) rt.getGenericType(); + if (( (isParameterizedType() || isRawType()) && getGenericType().equals(rt)) || + (this.equals(other))) return true; + return false; } + + /** + * Look up the actual occurence of a particular type in the hierarchy for + * 'this' type. The input is going to be a generic type, and the caller + * wants to know if it was used in its RAW or a PARAMETERIZED form in this + * hierarchy. + * + * returns null if it can't be found. + */ + public ResolvedType discoverActualOccurenceOfTypeInHierarchy(ResolvedType lookingFor) { + if (!lookingFor.isGenericType()) + throw new BCException("assertion failed: method should only be called with generic type, but "+lookingFor+" is "+lookingFor.typeKind); - public void addInterTypeMunger(ConcreteTypeMunger munger) { - ResolvedMember sig = munger.getSignature(); - if (sig == null || munger.getMunger() == null || - munger.getMunger().getKind() == ResolvedTypeMunger.PrivilegedAccess) { - interTypeMungers.add(munger); - return; - } + if (this.equals(ResolvedType.OBJECT)) return null; - //System.err.println("add: " + munger + " to " + this.getClassName() + " with " + interTypeMungers); - if (sig.getKind() == Member.METHOD) { - if (!compareToExistingMembers(munger, getMethodsWithoutIterator(false, true) /*getMethods()*/)) return; - if (this.isInterface()) { - if (!compareToExistingMembers(munger, - Arrays.asList(world.getCoreType(OBJECT).getDeclaredMethods()).iterator())) return; - } - } else if (sig.getKind() == Member.FIELD) { - if (!compareToExistingMembers(munger, Arrays.asList(getDeclaredFields()).iterator())) return; - } else { - if (!compareToExistingMembers(munger, Arrays.asList(getDeclaredMethods()).iterator())) return; - } + if (genericTypeEquals(lookingFor)) return this; - // now compare to existingMungers - for (Iterator i = interTypeMungers.iterator(); i.hasNext();) { - ConcreteTypeMunger existingMunger = (ConcreteTypeMunger) i.next(); - if (conflictingSignature(existingMunger.getSignature(), munger.getSignature())) { - //System.err.println("match " + munger + " with " + existingMunger); - if (isVisible(munger.getSignature().getModifiers(), - munger.getAspectType(), existingMunger.getAspectType())) { - //System.err.println(" is visible"); - int c = compareMemberPrecedence(sig, existingMunger.getSignature()); - if (c == 0) { - c = getWorld().compareByPrecedenceAndHierarchy(munger.getAspectType(), existingMunger.getAspectType()); - } - //System.err.println(" compare: " + c); - if (c < 0) { - // the existing munger dominates the new munger - checkLegalOverride(munger.getSignature(), existingMunger.getSignature()); - return; - } else if (c > 0) { - // the new munger dominates the existing one - checkLegalOverride(existingMunger.getSignature(), munger.getSignature()); - i.remove(); - break; - } else { - interTypeConflictError(munger, existingMunger); - interTypeConflictError(existingMunger, munger); - return; - } - } - } - } - //System.err.println("adding: " + munger + " to " + this); - interTypeMungers.add(munger); - } + ResolvedType superT = getSuperclass(); + if (superT.genericTypeEquals(lookingFor)) return superT; - private boolean compareToExistingMembers(ConcreteTypeMunger munger, List existingMembersList) { - return compareToExistingMembers(munger, existingMembersList.iterator()); - } - - //??? returning too soon - private boolean compareToExistingMembers(ConcreteTypeMunger munger, Iterator existingMembers) { - ResolvedMember sig = munger.getSignature(); - while (existingMembers.hasNext()) { - ResolvedMember existingMember = (ResolvedMember) existingMembers.next(); - //System.err.println("Comparing munger: "+sig+" with member "+existingMember); - if (conflictingSignature(existingMember, munger.getSignature())) { - //System.err.println("conflict: existingMember=" + existingMember + " typeMunger=" + munger); - //System.err.println(munger.getSourceLocation() + ", " + munger.getSignature() + ", " + munger.getSignature().getSourceLocation()); - - if (isVisible(existingMember.getModifiers(), this, munger.getAspectType())) { - int c = compareMemberPrecedence(sig, existingMember); - //System.err.println(" c: " + c); - if (c < 0) { - // existingMember dominates munger - checkLegalOverride(munger.getSignature(), existingMember); - return false; - } else if (c > 0) { - // munger dominates existingMember - checkLegalOverride(existingMember, munger.getSignature()); - //interTypeMungers.add(munger); - //??? might need list of these overridden abstracts - continue; - } else { - // bridge methods can differ solely in return type. - // FIXME this whole method seems very hokey - unaware of covariance/varargs/bridging - it - // could do with a rewrite ! - boolean sameReturnTypes = (existingMember.getReturnType().equals(sig.getReturnType())); - if (sameReturnTypes) - getWorld().getMessageHandler().handleMessage( - MessageUtil.error(WeaverMessages.format(WeaverMessages.ITD_MEMBER_CONFLICT, munger.getAspectType().getName(), - existingMember), - munger.getSourceLocation()) - ); - } - } else if (isDuplicateMemberWithinTargetType(existingMember, this, sig)) { - getWorld().getMessageHandler().handleMessage( - MessageUtil.error(WeaverMessages.format(WeaverMessages.ITD_MEMBER_CONFLICT, munger.getAspectType().getName(), - existingMember), - munger.getSourceLocation()) - ); - ; - } - //return; + ResolvedType[] superIs = getDeclaredInterfaces(); + for (int i = 0; i < superIs.length; i++) { + ResolvedType superI = superIs[i]; + if (superI.genericTypeEquals(lookingFor)) return superI; + ResolvedType checkTheSuperI = discoverActualOccurenceOfTypeInHierarchy(lookingFor); + if (checkTheSuperI!=null) return checkTheSuperI; } - } - return true; - } - - // we know that the member signature matches, but that the member in the target type is not visible to the aspect. - // this may still be disallowed if it would result in two members within the same declaring type with the same - // signature AND more than one of them is concrete AND they are both visible within the target type. - private boolean isDuplicateMemberWithinTargetType(ResolvedMember existingMember, ResolvedType targetType, ResolvedMember itdMember) { - if ((existingMember.isAbstract() || itdMember.isAbstract())) return false; - UnresolvedType declaringType = existingMember.getDeclaringType(); - if (!targetType.equals(declaringType)) return false; - // now have to test that itdMember is visible from targetType - if (itdMember.isPrivate()) return false; - if (itdMember.isPublic()) return true; - // must be in same package to be visible then... - if (!targetType.getPackageName().equals(itdMember.getDeclaringType().getPackageName())) return false; - - // trying to put two members with the same signature into the exact same type..., and both visible in that type. - return true; + return discoverActualOccurenceOfTypeInHierarchy(superT); } /** - * @return true if the override is legal - * note: calling showMessage with two locations issues TWO messages, not ONE message - * with an additional source location. + * Called for all type mungers but only does something if they share type variables + * with a generic type which they target. When this happens this routine will check + * for the target type in the target hierarchy and 'bind' any type parameters as + * appropriate. For example, for the ITD "List<T> I<T>.x" against a type like this: + * "class A implements I<String>" this routine will return a parameterized form of + * the ITD "List<String> I.x" */ - public boolean checkLegalOverride(ResolvedMember parent, ResolvedMember child) { - //System.err.println("check: " + child.getDeclaringType() + " overrides " + parent.getDeclaringType()); - if (Modifier.isFinal(parent.getModifiers())) { - world.showMessage(Message.ERROR, - WeaverMessages.format(WeaverMessages.CANT_OVERRIDE_FINAL_MEMBER, parent), - child.getSourceLocation(), null); - return false; - } - - boolean incompatibleReturnTypes = false; - - // In 1.5 mode, allow for covariance on return type - if (world.isInJava5Mode() && parent.getKind() == Member.METHOD) { - ResolvedType rtParentReturnType = parent.getReturnType().resolve(world); - ResolvedType rtChildReturnType = child.getReturnType().resolve(world); - incompatibleReturnTypes = !rtParentReturnType.isAssignableFrom(rtChildReturnType); - } else { - incompatibleReturnTypes = !parent.getReturnType().equals(child.getReturnType()); - } - - if (incompatibleReturnTypes) { - world.showMessage(IMessage.ERROR, - WeaverMessages.format(WeaverMessages.ITD_RETURN_TYPE_MISMATCH, parent, child), - child.getSourceLocation(), parent.getSourceLocation()); - return false; - } - if (parent.getKind() == Member.POINTCUT) { - UnresolvedType[] pTypes = parent.getParameterTypes(); - UnresolvedType[] cTypes = child.getParameterTypes(); - if (!Arrays.equals(pTypes, cTypes)) { - world.showMessage(IMessage.ERROR, - WeaverMessages.format(WeaverMessages.ITD_PARAM_TYPE_MISMATCH, parent, child), - child.getSourceLocation(), parent.getSourceLocation()); - return false; - } - } - //System.err.println("check: " + child.getModifiers() + " more visible " + parent.getModifiers()); - if (isMoreVisible(parent.getModifiers(), child.getModifiers())) { - world.showMessage(IMessage.ERROR, - WeaverMessages.format(WeaverMessages.ITD_VISIBILITY_REDUCTION, parent, child), - child.getSourceLocation(), parent.getSourceLocation()); - return false; - } - - // check declared exceptions - ResolvedType[] childExceptions = world.resolve(child.getExceptions()); - ResolvedType[] parentExceptions = world.resolve(parent.getExceptions()); - ResolvedType runtimeException = world.resolve("java.lang.RuntimeException"); - ResolvedType error = world.resolve("java.lang.Error"); - + public ConcreteTypeMunger fillInAnyTypeParameters(ConcreteTypeMunger munger) { + boolean debug = false; + ResolvedMember member = munger.getSignature(); + if (munger.isTargetTypeParameterized()) { + if (debug) System.err.println("Processing attempted parameterization of "+munger+" targetting type "+this); + if (debug) System.err.println(" This type is "+this+" ("+typeKind+")"); + // need to tailor this munger instance for the particular target... + if (debug) System.err.println(" Signature that needs parameterizing: "+member); + // Retrieve the generic type + ResolvedType onType = world.resolve(member.getDeclaringType()).getGenericType(); + member.resolve(world); // Ensure all parts of the member are resolved + if (debug) System.err.println(" Actual target ontype: "+onType+" ("+onType.typeKind+")"); + // quickly find the targettype in the type hierarchy for this type (it will be either RAW or PARAMETERIZED) + ResolvedType actualTarget = discoverActualOccurenceOfTypeInHierarchy(onType); + if (actualTarget==null) + throw new BCException("assertion failed: asked "+this+" for occurrence of "+onType+" in its hierarchy??"); + + // only bind the tvars if its a parameterized type or the raw type (in which case they collapse to bounds) - don't do it for generic types ;) + if (!actualTarget.isGenericType()) { + if (debug) System.err.println("Occurence in "+this+" is actually "+actualTarget+" ("+actualTarget.typeKind+")"); + // parameterize the signature + ResolvedMember newOne = member.parameterizedWith(actualTarget.getTypeParameters(),onType,actualTarget.isParameterizedType()); + munger = munger.parameterizedFor(actualTarget); + if (debug) System.err.println("New sig: "+newOne); + + } + if (debug) System.err.println("====================================="); + } + return munger; + } + + + + public void addInterTypeMunger(ConcreteTypeMunger munger) { + ResolvedMember sig = munger.getSignature(); + if (sig == null || munger.getMunger() == null || + munger.getMunger().getKind() == ResolvedTypeMunger.PrivilegedAccess) + { + interTypeMungers.add(munger); + return; + } + + ConcreteTypeMunger originalMunger = munger; + // we will use the 'parameterized' ITD for all the comparisons but we say the original + // one passed in actually matched as it will be added to the intertype member finder + // for the target type. It is possible we only want to do this if a generic type + // is discovered and the tvar is collapsed to a bound? + munger = fillInAnyTypeParameters(munger); + sig = munger.getSignature(); // possibly changed when type parms filled in + + + //System.err.println("add: " + munger + " to " + this.getClassName() + " with " + interTypeMungers); + if (sig.getKind() == Member.METHOD) { + if (!compareToExistingMembers(munger, getMethodsWithoutIterator(false,true) /*getMethods()*/)) return; + if (this.isInterface()) { + if (!compareToExistingMembers(munger, + Arrays.asList(world.getCoreType(OBJECT).getDeclaredMethods()).iterator())) return; + } + } else if (sig.getKind() == Member.FIELD) { + if (!compareToExistingMembers(munger, Arrays.asList(getDeclaredFields()).iterator())) return; + } else { + if (!compareToExistingMembers(munger, Arrays.asList(getDeclaredMethods()).iterator())) return; + } + + + // now compare to existingMungers + for (Iterator i = interTypeMungers.iterator(); i.hasNext(); ) { + ConcreteTypeMunger existingMunger = (ConcreteTypeMunger)i.next(); + if (conflictingSignature(existingMunger.getSignature(), munger.getSignature())) { + //System.err.println("match " + munger + " with " + existingMunger); + if (isVisible(munger.getSignature().getModifiers(), + munger.getAspectType(), existingMunger.getAspectType())) + { + //System.err.println(" is visible"); + int c = compareMemberPrecedence(sig, existingMunger.getSignature()); + if (c == 0) { + c = getWorld().compareByPrecedenceAndHierarchy(munger.getAspectType(), existingMunger.getAspectType()); + } + //System.err.println(" compare: " + c); + if (c < 0) { + // the existing munger dominates the new munger + checkLegalOverride(munger.getSignature(), existingMunger.getSignature()); + return; + } else if (c > 0) { + // the new munger dominates the existing one + checkLegalOverride(existingMunger.getSignature(), munger.getSignature()); + i.remove(); + break; + } else { + interTypeConflictError(munger, existingMunger); + interTypeConflictError(existingMunger, munger); + return; + } + } + } + } + //System.err.println("adding: " + munger + " to " + this); + // we used the 'parameterized' ITD for all the comparisons but we say the original + // one passed in actually matched as it will be added to the intertype member finder + // for the target type. + interTypeMungers.add(originalMunger); + } + + private boolean compareToExistingMembers(ConcreteTypeMunger munger, List existingMembersList) { + return compareToExistingMembers(munger,existingMembersList.iterator()); + } + + //??? returning too soon + private boolean compareToExistingMembers(ConcreteTypeMunger munger, Iterator existingMembers) { + ResolvedMember sig = munger.getSignature(); + while (existingMembers.hasNext()) { + ResolvedMember existingMember = (ResolvedMember)existingMembers.next(); + //System.err.println("Comparing munger: "+sig+" with member "+existingMember); + if (conflictingSignature(existingMember, munger.getSignature())) { + //System.err.println("conflict: existingMember=" + existingMember + " typeMunger=" + munger); + //System.err.println(munger.getSourceLocation() + ", " + munger.getSignature() + ", " + munger.getSignature().getSourceLocation()); + + if (isVisible(existingMember.getModifiers(), this, munger.getAspectType())) { + int c = compareMemberPrecedence(sig, existingMember); + //System.err.println(" c: " + c); + if (c < 0) { + // existingMember dominates munger + checkLegalOverride(munger.getSignature(), existingMember); + return false; + } else if (c > 0) { + // munger dominates existingMember + checkLegalOverride(existingMember, munger.getSignature()); + //interTypeMungers.add(munger); + //??? might need list of these overridden abstracts + continue; + } else { + // bridge methods can differ solely in return type. + // FIXME this whole method seems very hokey - unaware of covariance/varargs/bridging - it + // could do with a rewrite ! + boolean sameReturnTypes = (existingMember.getReturnType().equals(sig.getReturnType())); + if (sameReturnTypes) + getWorld().getMessageHandler().handleMessage( + MessageUtil.error(WeaverMessages.format(WeaverMessages.ITD_MEMBER_CONFLICT,munger.getAspectType().getName(), + existingMember), + munger.getSourceLocation()) + ); + } + } else if (isDuplicateMemberWithinTargetType(existingMember,this,sig)) { + getWorld().getMessageHandler().handleMessage( + MessageUtil.error(WeaverMessages.format(WeaverMessages.ITD_MEMBER_CONFLICT,munger.getAspectType().getName(), + existingMember), + munger.getSourceLocation()) + ); + ; + } + //return; + } + } + return true; + } + + // we know that the member signature matches, but that the member in the target type is not visible to the aspect. + // this may still be disallowed if it would result in two members within the same declaring type with the same + // signature AND more than one of them is concrete AND they are both visible within the target type. + private boolean isDuplicateMemberWithinTargetType(ResolvedMember existingMember, ResolvedType targetType,ResolvedMember itdMember) { + if ( (existingMember.isAbstract() || itdMember.isAbstract())) return false; + UnresolvedType declaringType = existingMember.getDeclaringType(); + if (!targetType.equals(declaringType)) return false; + // now have to test that itdMember is visible from targetType + if (itdMember.isPrivate()) return false; + if (itdMember.isPublic()) return true; + // must be in same package to be visible then... + if (!targetType.getPackageName().equals(itdMember.getDeclaringType().getPackageName())) return false; + + // trying to put two members with the same signature into the exact same type..., and both visible in that type. + return true; + } + + /** + * @return true if the override is legal + * note: calling showMessage with two locations issues TWO messages, not ONE message + * with an additional source location. + */ + public boolean checkLegalOverride(ResolvedMember parent, ResolvedMember child) { + //System.err.println("check: " + child.getDeclaringType() + " overrides " + parent.getDeclaringType()); + if (Modifier.isFinal(parent.getModifiers())) { + world.showMessage(Message.ERROR, + WeaverMessages.format(WeaverMessages.CANT_OVERRIDE_FINAL_MEMBER,parent), + child.getSourceLocation(),null); + return false; + } + + boolean incompatibleReturnTypes = false; + + // In 1.5 mode, allow for covariance on return type + if (world.isInJava5Mode() && parent.getKind()==Member.METHOD) { + + // Look at the generic types when doing this comparison + ResolvedType rtParentReturnType = parent.getGenericReturnType().resolve(world); + ResolvedType rtChildReturnType = child.getGenericReturnType().resolve(world); + incompatibleReturnTypes = !rtParentReturnType.isAssignableFrom(rtChildReturnType); + } else { + incompatibleReturnTypes =!parent.getReturnType().equals(child.getReturnType()); + } + + if (incompatibleReturnTypes) { + world.showMessage(IMessage.ERROR, + WeaverMessages.format(WeaverMessages.ITD_RETURN_TYPE_MISMATCH,parent,child), + child.getSourceLocation(), parent.getSourceLocation()); + return false; + } + if (parent.getKind() == Member.POINTCUT) { + UnresolvedType[] pTypes = parent.getParameterTypes(); + UnresolvedType[] cTypes = child.getParameterTypes(); + if (!Arrays.equals(pTypes, cTypes)) { + world.showMessage(IMessage.ERROR, + WeaverMessages.format(WeaverMessages.ITD_PARAM_TYPE_MISMATCH,parent,child), + child.getSourceLocation(), parent.getSourceLocation()); + return false; + } + } + //System.err.println("check: " + child.getModifiers() + " more visible " + parent.getModifiers()); + if (isMoreVisible(parent.getModifiers(), child.getModifiers())) { + world.showMessage(IMessage.ERROR, + WeaverMessages.format(WeaverMessages.ITD_VISIBILITY_REDUCTION,parent,child), + child.getSourceLocation(), parent.getSourceLocation()); + return false; + } + + // check declared exceptions + ResolvedType[] childExceptions = world.resolve(child.getExceptions()); + ResolvedType[] parentExceptions = world.resolve(parent.getExceptions()); + ResolvedType runtimeException = world.resolve("java.lang.RuntimeException"); + ResolvedType error = world.resolve("java.lang.Error"); + outer: for (int i = 0, leni = childExceptions.length; i < leni; i++) { - //System.err.println("checking: " + childExceptions[i]); - if (runtimeException.isAssignableFrom(childExceptions[i])) continue; - if (error.isAssignableFrom(childExceptions[i])) continue; - - for (int j = 0, lenj = parentExceptions.length; j < lenj; j++) { - if (parentExceptions[j].isAssignableFrom(childExceptions[i])) continue outer; - } - - // this message is now better handled my MethodVerifier in JDT core. + //System.err.println("checking: " + childExceptions[i]); + if (runtimeException.isAssignableFrom(childExceptions[i])) continue; + if (error.isAssignableFrom(childExceptions[i])) continue; + + for (int j = 0, lenj = parentExceptions.length; j < lenj; j++) { + if (parentExceptions[j].isAssignableFrom(childExceptions[i])) continue outer; + } + + // this message is now better handled my MethodVerifier in JDT core. // world.showMessage(IMessage.ERROR, // WeaverMessages.format(WeaverMessages.ITD_DOESNT_THROW,childExceptions[i].getName()), // child.getSourceLocation(), null); - - return false; - } - if (parent.isStatic() && !child.isStatic()) { - world.showMessage(IMessage.ERROR, - WeaverMessages.format(WeaverMessages.ITD_OVERRIDDEN_STATIC, child, parent), - child.getSourceLocation(), null); - return false; - } else if (child.isStatic() && !parent.isStatic()) { - world.showMessage(IMessage.ERROR, - WeaverMessages.format(WeaverMessages.ITD_OVERIDDING_STATIC, child, parent), - child.getSourceLocation(), null); - return false; - } - return true; - - } - - private int compareMemberPrecedence(ResolvedMember m1, ResolvedMember m2) { - //if (!m1.getReturnType().equals(m2.getReturnType())) return 0; - - // need to allow for the special case of 'clone' - which is like abstract but is - // not marked abstract. The code below this next line seems to make assumptions - // about what will have gotten through the compiler based on the normal - // java rules. clone goes against these... - if (m2.isProtected() && m2.isNative() && m2.getName().equals("clone")) return +1; - - if (Modifier.isAbstract(m1.getModifiers())) return -1; - if (Modifier.isAbstract(m2.getModifiers())) return +1; - - if (m1.getDeclaringType().equals(m2.getDeclaringType())) return 0; - - ResolvedType t1 = m1.getDeclaringType().resolve(world); - ResolvedType t2 = m2.getDeclaringType().resolve(world); - if (t1.isAssignableFrom(t2)) { - return -1; - } - if (t2.isAssignableFrom(t1)) { - return +1; - } - return 0; - } - - - public static boolean isMoreVisible(int m1, int m2) { - if (Modifier.isPrivate(m1)) return false; - if (isPackage(m1)) return Modifier.isPrivate(m2); - if (Modifier.isProtected(m1)) return /* private package */ (Modifier.isPrivate(m2) || isPackage(m2)); - if (Modifier.isPublic(m1)) return /* private package protected */ ! Modifier.isPublic(m2); - throw new RuntimeException("bad modifier: " + m1); - } - - private static boolean isPackage(int i) { - return (0 == (i & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED))); - } - - private void interTypeConflictError( - ConcreteTypeMunger m1, + + return false; + } + if (parent.isStatic() && !child.isStatic()) { + world.showMessage(IMessage.ERROR, + WeaverMessages.format(WeaverMessages.ITD_OVERRIDDEN_STATIC,child,parent), + child.getSourceLocation(),null); + return false; + } else if (child.isStatic() && !parent.isStatic()) { + world.showMessage(IMessage.ERROR, + WeaverMessages.format(WeaverMessages.ITD_OVERIDDING_STATIC,child,parent), + child.getSourceLocation(),null); + return false; + } + return true; + + } + + private int compareMemberPrecedence(ResolvedMember m1, ResolvedMember m2) { + //if (!m1.getReturnType().equals(m2.getReturnType())) return 0; + + // need to allow for the special case of 'clone' - which is like abstract but is + // not marked abstract. The code below this next line seems to make assumptions + // about what will have gotten through the compiler based on the normal + // java rules. clone goes against these... + if (m2.isProtected() && m2.isNative() && m2.getName().equals("clone")) return +1; + + if (Modifier.isAbstract(m1.getModifiers())) return -1; + if (Modifier.isAbstract(m2.getModifiers())) return +1; + + if (m1.getDeclaringType().equals(m2.getDeclaringType())) return 0; + + ResolvedType t1 = m1.getDeclaringType().resolve(world); + ResolvedType t2 = m2.getDeclaringType().resolve(world); + if (t1.isAssignableFrom(t2)) { + return -1; + } + if (t2.isAssignableFrom(t1)) { + return +1; + } + return 0; + } + + + public static boolean isMoreVisible(int m1, int m2) { + if (Modifier.isPrivate(m1)) return false; + if (isPackage(m1)) return Modifier.isPrivate(m2); + if (Modifier.isProtected(m1)) return /* private package */ (Modifier.isPrivate(m2) || isPackage(m2)); + if (Modifier.isPublic(m1)) return /* private package protected */ ! Modifier.isPublic(m2); + throw new RuntimeException("bad modifier: " + m1); + } + + private static boolean isPackage(int i) { + return (0 == (i & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED))); + } + + private void interTypeConflictError( + ConcreteTypeMunger m1, ConcreteTypeMunger m2) { - //XXX this works only if we ignore separate compilation issues - //XXX dual errors possible if (this instanceof BcelObjectType) return; - - //System.err.println("conflict at " + m2.getSourceLocation()); - getWorld().showMessage(IMessage.ERROR, - WeaverMessages.format(WeaverMessages.ITD_CONFLICT, m1.getAspectType().getName(), - m2.getSignature(), m2.getAspectType().getName()), - m2.getSourceLocation(), getSourceLocation()); - } - - - public ResolvedMember lookupSyntheticMember(Member member) { - //??? horribly inefficient - //for (Iterator i = - //System.err.println("lookup " + member + " in " + interTypeMungers); - for (Iterator i = interTypeMungers.iterator(); i.hasNext();) { - ConcreteTypeMunger m = (ConcreteTypeMunger) i.next(); - ResolvedMember ret = m.getMatchingSyntheticMember(member); - if (ret != null) { - //System.err.println(" found: " + ret); - return ret; - } - } - + //XXX this works only if we ignore separate compilation issues + //XXX dual errors possible if (this instanceof BcelObjectType) return; + + //System.err.println("conflict at " + m2.getSourceLocation()); + getWorld().showMessage(IMessage.ERROR, + WeaverMessages.format(WeaverMessages.ITD_CONFLICT,m1.getAspectType().getName(), + m2.getSignature(),m2.getAspectType().getName()), + m2.getSourceLocation(), getSourceLocation()); + } + + + public ResolvedMember lookupSyntheticMember(Member member) { + //??? horribly inefficient + //for (Iterator i = + //System.err.println("lookup " + member + " in " + interTypeMungers); + for (Iterator i = interTypeMungers.iterator(); i.hasNext(); ) { + ConcreteTypeMunger m = (ConcreteTypeMunger)i.next(); + ResolvedMember ret = m.getMatchingSyntheticMember(member); + if (ret != null) { + //System.err.println(" found: " + ret); + return ret; + } + } + // if (this.getSuperclass() != ResolvedType.OBJECT && this.getSuperclass() != null) { // return getSuperclass().lookupSyntheticMember(member); // } - - return null; - } - - public void clearInterTypeMungers() { - if (isRawType()) getGenericType().clearInterTypeMungers(); - interTypeMungers = new ArrayList(); - } - - - public boolean isTopmostImplementor(ResolvedType interfaceType) { - if (isInterface()) return false; - if (!interfaceType.isAssignableFrom(this, true)) return false; - // check that I'm truly the topmost implementor - if (this.getSuperclass().isMissing()) return true; // we don't know anything about supertype, and it can't be exposed to weaver - if (interfaceType.isAssignableFrom(this.getSuperclass(), true)) { - return false; - } - return true; - } - - public ResolvedType getTopmostImplementor(ResolvedType interfaceType) { - if (isInterface()) return null; - if (!interfaceType.isAssignableFrom(this)) return null; - // Check if my super class is an implementor? - ResolvedType higherType = this.getSuperclass().getTopmostImplementor(interfaceType); - if (higherType != null) return higherType; - return this; - } - - private ResolvedType findHigher(ResolvedType other) { - if (this == other) return this; - for (Iterator i = other.getDirectSupertypes(); i.hasNext();) { - ResolvedType rtx = (ResolvedType) i.next(); - boolean b = this.isAssignableFrom(rtx); - if (b) return rtx; - } - return null; - } - - public List getExposedPointcuts() { - List ret = new ArrayList(); - if (getSuperclass() != null) ret.addAll(getSuperclass().getExposedPointcuts()); - - for (Iterator i = Arrays.asList(getDeclaredInterfaces()).iterator(); i.hasNext();) { - ResolvedType t = (ResolvedType) i.next(); - addPointcutsResolvingConflicts(ret, Arrays.asList(t.getDeclaredPointcuts()), false); - } - addPointcutsResolvingConflicts(ret, Arrays.asList(getDeclaredPointcuts()), true); - for (Iterator i = ret.iterator(); i.hasNext();) { - ResolvedPointcutDefinition inherited = (ResolvedPointcutDefinition) i.next(); + + return null; + } + + public void clearInterTypeMungers() { + if (isRawType()) getGenericType().clearInterTypeMungers(); + interTypeMungers = new ArrayList(); + } + + + public boolean isTopmostImplementor(ResolvedType interfaceType) { + if (isInterface()) return false; + if (!interfaceType.isAssignableFrom(this,true)) return false; + // check that I'm truly the topmost implementor + if (this.getSuperclass().isMissing()) return true; // we don't know anything about supertype, and it can't be exposed to weaver + if (interfaceType.isAssignableFrom(this.getSuperclass(),true)) { + return false; + } + return true; + } + + public ResolvedType getTopmostImplementor(ResolvedType interfaceType) { + if (isInterface()) return null; + if (!interfaceType.isAssignableFrom(this)) return null; + // Check if my super class is an implementor? + ResolvedType higherType = this.getSuperclass().getTopmostImplementor(interfaceType); + if (higherType!=null) return higherType; + return this; + } + + private ResolvedType findHigher(ResolvedType other) { + if (this == other) return this; + for(Iterator i = other.getDirectSupertypes(); i.hasNext(); ) { + ResolvedType rtx = (ResolvedType)i.next(); + boolean b = this.isAssignableFrom(rtx); + if (b) return rtx; + } + return null; + } + + public List getExposedPointcuts() { + List ret = new ArrayList(); + if (getSuperclass() != null) ret.addAll(getSuperclass().getExposedPointcuts()); + + for (Iterator i = Arrays.asList(getDeclaredInterfaces()).iterator(); i.hasNext(); ) { + ResolvedType t = (ResolvedType)i.next(); + addPointcutsResolvingConflicts(ret, Arrays.asList(t.getDeclaredPointcuts()), false); + } + addPointcutsResolvingConflicts(ret, Arrays.asList(getDeclaredPointcuts()), true); + for (Iterator i = ret.iterator(); i.hasNext(); ) { + ResolvedPointcutDefinition inherited = (ResolvedPointcutDefinition)i.next(); // System.err.println("looking at: " + inherited + " in " + this); // System.err.println(" " + inherited.isAbstract() + " in " + this.isAbstract()); - if (inherited.isAbstract()) { - if (!this.isAbstract()) { - getWorld().showMessage(IMessage.ERROR, - WeaverMessages.format(WeaverMessages.POINCUT_NOT_CONCRETE, inherited, this.getName()), - inherited.getSourceLocation(), this.getSourceLocation()); - } - } - } - - - return ret; - } - - private void addPointcutsResolvingConflicts(List acc, List added, boolean isOverriding) { - for (Iterator i = added.iterator(); i.hasNext();) { - ResolvedPointcutDefinition toAdd = - (ResolvedPointcutDefinition) i.next(); - //System.err.println("adding: " + toAdd); - for (Iterator j = acc.iterator(); j.hasNext();) { - ResolvedPointcutDefinition existing = - (ResolvedPointcutDefinition) j.next(); - if (existing == toAdd) continue; - if (!isVisible(existing.getModifiers(), - existing.getDeclaringType().resolve(getWorld()), - this)) { - continue; - } - if (conflictingSignature(existing, toAdd)) { - if (isOverriding) { - checkLegalOverride(existing, toAdd); - j.remove(); - } else { - getWorld().showMessage( - IMessage.ERROR, - WeaverMessages.format(WeaverMessages.CONFLICTING_INHERITED_POINTCUTS, this.getName() + toAdd.getSignature()), - existing.getSourceLocation(), - toAdd.getSourceLocation()); - j.remove(); - } - } - } - acc.add(toAdd); - } - } - + if (inherited.isAbstract()) { + if (!this.isAbstract()) { + getWorld().showMessage(IMessage.ERROR, + WeaverMessages.format(WeaverMessages.POINCUT_NOT_CONCRETE,inherited,this.getName()), + inherited.getSourceLocation(), this.getSourceLocation()); + } + } + } + + + return ret; + } + + private void addPointcutsResolvingConflicts(List acc, List added, boolean isOverriding) { + for (Iterator i = added.iterator(); i.hasNext();) { + ResolvedPointcutDefinition toAdd = + (ResolvedPointcutDefinition) i.next(); + //System.err.println("adding: " + toAdd); + for (Iterator j = acc.iterator(); j.hasNext();) { + ResolvedPointcutDefinition existing = + (ResolvedPointcutDefinition) j.next(); + if (existing == toAdd) continue; + if (!isVisible(existing.getModifiers(), + existing.getDeclaringType().resolve(getWorld()), + this)) { + continue; + } + if (conflictingSignature(existing, toAdd)) { + if (isOverriding) { + checkLegalOverride(existing, toAdd); + j.remove(); + } else { + getWorld().showMessage( + IMessage.ERROR, + WeaverMessages.format(WeaverMessages.CONFLICTING_INHERITED_POINTCUTS,this.getName() + toAdd.getSignature()), + existing.getSourceLocation(), + toAdd.getSourceLocation()); + j.remove(); + } + } + } + acc.add(toAdd); + } + } + public ISourceLocation getSourceLocation() { return null; } @@ -1677,240 +1738,239 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl return false; } - public WeaverStateInfo getWeaverState() { - return null; - } - - /** - * Overridden by ReferenceType to return a sensible answer for parameterized and raw types. + public WeaverStateInfo getWeaverState() { + return null; + } + + /** + * Overridden by ReferenceType to return a sensible answer for parameterized and raw types. * - * @return - */ - public ResolvedType getGenericType() { - if (!(isParameterizedType() || isRawType())) - throw new BCException("The type " + getBaseName() + " is not parameterized or raw - it has no generic type"); - return null; - } - - public ResolvedType parameterizedWith(UnresolvedType[] typeParameters) { - if (!(isGenericType() || isParameterizedType())) return this; - return TypeFactory.createParameterizedType(this.getGenericType(), typeParameters, getWorld()); - } - - /** - * Iff I am a parameterized type, and any of my parameters are type variable - * references, return a version with those type parameters replaced in accordance - * with the passed bindings. - */ - public UnresolvedType parameterize(Map typeBindings) { - if (!isParameterizedType()) throw new IllegalStateException("Can't parameterize a type that is not a parameterized type"); - boolean workToDo = false; - for (int i = 0; i < typeParameters.length; i++) { - if (typeParameters[i].isTypeVariableReference()) { - workToDo = true; - } - } - if (!workToDo) { - return this; - } else { - UnresolvedType[] newTypeParams = new UnresolvedType[typeParameters.length]; - for (int i = 0; i < newTypeParams.length; i++) { - newTypeParams[i] = typeParameters[i]; - if (newTypeParams[i].isTypeVariableReference()) { - TypeVariableReferenceType tvrt = (TypeVariableReferenceType) newTypeParams[i]; - UnresolvedType binding = (UnresolvedType) typeBindings.get(tvrt.getTypeVariable().getName()); - if (binding != null) newTypeParams[i] = binding; - } - } - return TypeFactory.createParameterizedType(getGenericType(), newTypeParams, getWorld()); - } - } - - public boolean hasParameterizedSuperType() { - getParameterizedSuperTypes(); - return parameterizedSuperTypes.length > 0; - } - - public boolean hasGenericSuperType() { - ResolvedType[] superTypes = getDeclaredInterfaces(); - for (int i = 0; i < superTypes.length; i++) { - if (superTypes[i].isGenericType()) return true; - } - return false; - } - - private ResolvedType[] parameterizedSuperTypes = null; - - /** - * Similar to the above method, but accumulates the super types - * - * @return - */ - public ResolvedType[] getParameterizedSuperTypes() { - if (parameterizedSuperTypes != null) return parameterizedSuperTypes; - List accumulatedTypes = new ArrayList(); - accumulateParameterizedSuperTypes(this, accumulatedTypes); - ResolvedType[] ret = new ResolvedType[accumulatedTypes.size()]; - parameterizedSuperTypes = (ResolvedType[]) accumulatedTypes.toArray(ret); - return parameterizedSuperTypes; - } - - private void accumulateParameterizedSuperTypes(ResolvedType forType, List parameterizedTypeList) { - if (forType.isParameterizedType()) { - parameterizedTypeList.add(forType); - } - if (forType.getSuperclass() != null) { - accumulateParameterizedSuperTypes(forType.getSuperclass(), parameterizedTypeList); - } - ResolvedType[] interfaces = forType.getDeclaredInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - accumulateParameterizedSuperTypes(interfaces[i], parameterizedTypeList); - } - } - - /** - * Types may have pointcuts just as they have methods and fields. - */ - public ResolvedPointcutDefinition findPointcut(String name, World world) { - throw new UnsupportedOperationException("Not yet implemenented"); - } - - /** - * Determines if variables of this type could be assigned values of another - * with lots of help. - * java.lang.Object is convertable from all types. - * A primitive type is convertable from X iff it's assignable from X. - * A reference type is convertable from X iff it's coerceable from X. - * In other words, X isConvertableFrom Y iff the compiler thinks that _some_ value of Y - * could be assignable to a variable of type X without loss of precision. + * @return + */ + public ResolvedType getGenericType() { + if (!(isParameterizedType() || isRawType())) + throw new BCException("The type "+getBaseName()+" is not parameterized or raw - it has no generic type"); + return null; + } + + public ResolvedType parameterizedWith(UnresolvedType[] typeParameters) { + if (!(isGenericType() || isParameterizedType())) return this; + return TypeFactory.createParameterizedType(this.getGenericType(), typeParameters, getWorld()); + } + + /** + * Iff I am a parameterized type, and any of my parameters are type variable + * references, return a version with those type parameters replaced in accordance + * with the passed bindings. + */ + public UnresolvedType parameterize(Map typeBindings) { + if (!isParameterizedType()) throw new IllegalStateException("Can't parameterize a type that is not a parameterized type"); + boolean workToDo = false; + for (int i = 0; i < typeParameters.length; i++) { + if (typeParameters[i].isTypeVariableReference()) { + workToDo = true; + } + } + if (!workToDo) { + return this; + } else { + UnresolvedType[] newTypeParams = new UnresolvedType[typeParameters.length]; + for (int i = 0; i < newTypeParams.length; i++) { + newTypeParams[i] = typeParameters[i]; + if (newTypeParams[i].isTypeVariableReference()) { + TypeVariableReferenceType tvrt = (TypeVariableReferenceType) newTypeParams[i]; + UnresolvedType binding = (UnresolvedType) typeBindings.get(tvrt.getTypeVariable().getName()); + if (binding != null) newTypeParams[i] = binding; + } + } + return TypeFactory.createParameterizedType(getGenericType(), newTypeParams, getWorld()); + } + } + + public boolean hasParameterizedSuperType() { + getParameterizedSuperTypes(); + return parameterizedSuperTypes.length > 0; + } + + public boolean hasGenericSuperType() { + ResolvedType[] superTypes = getDeclaredInterfaces(); + for (int i = 0; i < superTypes.length; i++) { + if (superTypes[i].isGenericType()) return true; + } + return false; + } + + private ResolvedType[] parameterizedSuperTypes = null; + /** + * Similar to the above method, but accumulates the super types * - * @param other the other type - * @param world the {@link World} in which the possible assignment should be checked. - * @return true iff variables of this type could be assigned values of other with possible conversion - */ - public final boolean isConvertableFrom(ResolvedType other) { + * @return + */ + public ResolvedType[] getParameterizedSuperTypes() { + if (parameterizedSuperTypes != null) return parameterizedSuperTypes; + List accumulatedTypes = new ArrayList(); + accumulateParameterizedSuperTypes(this,accumulatedTypes); + ResolvedType[] ret = new ResolvedType[accumulatedTypes.size()]; + parameterizedSuperTypes = (ResolvedType[]) accumulatedTypes.toArray(ret); + return parameterizedSuperTypes; + } + + private void accumulateParameterizedSuperTypes(ResolvedType forType, List parameterizedTypeList) { + if (forType.isParameterizedType()) { + parameterizedTypeList.add(forType); + } + if (forType.getSuperclass() != null) { + accumulateParameterizedSuperTypes(forType.getSuperclass(), parameterizedTypeList); + } + ResolvedType[] interfaces = forType.getDeclaredInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + accumulateParameterizedSuperTypes(interfaces[i], parameterizedTypeList); + } + } + + /** + * Types may have pointcuts just as they have methods and fields. + */ + public ResolvedPointcutDefinition findPointcut(String name, World world) { + throw new UnsupportedOperationException("Not yet implemenented"); + } + + /** + * Determines if variables of this type could be assigned values of another + * with lots of help. + * java.lang.Object is convertable from all types. + * A primitive type is convertable from X iff it's assignable from X. + * A reference type is convertable from X iff it's coerceable from X. + * In other words, X isConvertableFrom Y iff the compiler thinks that _some_ value of Y + * could be assignable to a variable of type X without loss of precision. + * + * @param other the other type + * @param world the {@link World} in which the possible assignment should be checked. + * @return true iff variables of this type could be assigned values of other with possible conversion + */ + public final boolean isConvertableFrom(ResolvedType other) { // // version from TypeX // if (this.equals(OBJECT)) return true; // if (this.isPrimitiveType() || other.isPrimitiveType()) return this.isAssignableFrom(other); // return this.isCoerceableFrom(other); // - - // version from ResolvedTypeX - if (this.equals(OBJECT)) return true; - if (world.isInJava5Mode()) { - if (this.isPrimitiveType() ^ other.isPrimitiveType()) { // If one is primitive and the other isnt - if (validBoxing.contains(this.getSignature() + other.getSignature())) return true; - } - } - if (this.isPrimitiveType() || other.isPrimitiveType()) return this.isAssignableFrom(other); - return this.isCoerceableFrom(other); - } - - /** - * Determines if the variables of this type could be assigned values - * of another type without casting. This still allows for assignment conversion - * as per JLS 2ed 5.2. For object types, this means supertypeOrEqual(THIS, OTHER). - * - * @param other the other type - * @param world the {@link World} in which the possible assignment should be checked. - * @return true iff variables of this type could be assigned values of other without casting + + // version from ResolvedTypeX + if (this.equals(OBJECT)) return true; + if (world.isInJava5Mode()) { + if (this.isPrimitiveType()^other.isPrimitiveType()) { // If one is primitive and the other isnt + if (validBoxing.contains(this.getSignature()+other.getSignature())) return true; + } + } + if (this.isPrimitiveType() || other.isPrimitiveType()) return this.isAssignableFrom(other); + return this.isCoerceableFrom(other); + } + + /** + * Determines if the variables of this type could be assigned values + * of another type without casting. This still allows for assignment conversion + * as per JLS 2ed 5.2. For object types, this means supertypeOrEqual(THIS, OTHER). + * + * @param other the other type + * @param world the {@link World} in which the possible assignment should be checked. + * @return true iff variables of this type could be assigned values of other without casting * @throws NullPointerException if other is null - */ - public abstract boolean isAssignableFrom(ResolvedType other); - - public abstract boolean isAssignableFrom(ResolvedType other, boolean allowMissing); - - /** - * Determines if values of another type could possibly be cast to - * this type. The rules followed are from JLS 2ed 5.5, "Casting Conversion". + */ + public abstract boolean isAssignableFrom(ResolvedType other); + + public abstract boolean isAssignableFrom(ResolvedType other, boolean allowMissing); + + /** + * Determines if values of another type could possibly be cast to + * this type. The rules followed are from JLS 2ed 5.5, "Casting Conversion". * <p/> - * <p> This method should be commutative, i.e., for all UnresolvedType a, b and all World w: + * <p> This method should be commutative, i.e., for all UnresolvedType a, b and all World w: * <p/> - * <blockquote><pre> - * a.isCoerceableFrom(b, w) == b.isCoerceableFrom(a, w) - * </pre></blockquote> - * - * @param other the other type - * @param world the {@link World} in which the possible coersion should be checked. - * @return true iff values of other could possibly be cast to this type. + * <blockquote><pre> + * a.isCoerceableFrom(b, w) == b.isCoerceableFrom(a, w) + * </pre></blockquote> + * + * @param other the other type + * @param world the {@link World} in which the possible coersion should be checked. + * @return true iff values of other could possibly be cast to this type. * @throws NullPointerException if other is null. - */ - public abstract boolean isCoerceableFrom(ResolvedType other); - - public boolean needsNoConversionFrom(ResolvedType o) { - return isAssignableFrom(o); - } - - /** + */ + public abstract boolean isCoerceableFrom(ResolvedType other); + + public boolean needsNoConversionFrom(ResolvedType o) { + return isAssignableFrom(o); + } + + /** * Implemented by ReferenceTypes */ - public String getSignatureForAttribute() { - throw new RuntimeException("Cannot ask this type " + this + " for a generic sig attribute"); - } - - private FuzzyBoolean parameterizedWithAMemberTypeVariable = FuzzyBoolean.MAYBE; - - /** - * return true if the parameterization of this type includes a member type variable. Member - * type variables occur in generic methods/ctors. - */ - public boolean isParameterizedWithAMemberTypeVariable() { - // MAYBE means we haven't worked it out yet... - if (parameterizedWithAMemberTypeVariable == FuzzyBoolean.MAYBE) { - - // if there are no type parameters then we cant be... - if (typeParameters == null || typeParameters.length == 0) { - parameterizedWithAMemberTypeVariable = FuzzyBoolean.NO; - return false; - } - - for (int i = 0; i < typeParameters.length; i++) { - UnresolvedType aType = (ResolvedType) typeParameters[i]; - if (aType.isTypeVariableReference() && ((TypeVariableReference) aType).getTypeVariable().getDeclaringElementKind() == TypeVariable.METHOD) { - parameterizedWithAMemberTypeVariable = FuzzyBoolean.YES; - return true; - } - if (aType.isParameterizedType()) { - boolean b = aType.isParameterizedWithAMemberTypeVariable(); - if (b) { - parameterizedWithAMemberTypeVariable = FuzzyBoolean.YES; - return true; - } - } - if (aType.isGenericWildcard()) { - if (aType.isExtends()) { - boolean b = false; - UnresolvedType upperBound = aType.getUpperBound(); - if (upperBound.isParameterizedType()) { - b = upperBound.isParameterizedWithAMemberTypeVariable(); - } else if (upperBound.isTypeVariableReference() && ((TypeVariableReference) upperBound).getTypeVariable().getDeclaringElementKind() == TypeVariable.METHOD) { - b = true; - } - if (b) { - parameterizedWithAMemberTypeVariable = FuzzyBoolean.YES; - return true; - } - // FIXME asc need to check additional interface bounds - } - if (aType.isSuper()) { - boolean b = false; - UnresolvedType lowerBound = aType.getLowerBound(); - if (lowerBound.isParameterizedType()) { - b = lowerBound.isParameterizedWithAMemberTypeVariable(); - } else if (lowerBound.isTypeVariableReference() && ((TypeVariableReference) lowerBound).getTypeVariable().getDeclaringElementKind() == TypeVariable.METHOD) { - b = true; - } - if (b) { - parameterizedWithAMemberTypeVariable = FuzzyBoolean.YES; - return true; - } - } - } - } - parameterizedWithAMemberTypeVariable = FuzzyBoolean.NO; - } - return parameterizedWithAMemberTypeVariable.alwaysTrue(); - } - + public String getSignatureForAttribute() { + throw new RuntimeException("Cannot ask this type "+this+" for a generic sig attribute"); + } + + private FuzzyBoolean parameterizedWithAMemberTypeVariable = FuzzyBoolean.MAYBE; + + /** + * return true if the parameterization of this type includes a member type variable. Member + * type variables occur in generic methods/ctors. + */ + public boolean isParameterizedWithAMemberTypeVariable() { + // MAYBE means we haven't worked it out yet... + if (parameterizedWithAMemberTypeVariable==FuzzyBoolean.MAYBE) { + + // if there are no type parameters then we cant be... + if (typeParameters==null || typeParameters.length==0) { + parameterizedWithAMemberTypeVariable = FuzzyBoolean.NO; + return false; + } + + for (int i = 0; i < typeParameters.length; i++) { + UnresolvedType aType = (ResolvedType)typeParameters[i]; + if (aType.isTypeVariableReference() && ((TypeVariableReference)aType).getTypeVariable().getDeclaringElementKind()==TypeVariable.METHOD) { + parameterizedWithAMemberTypeVariable = FuzzyBoolean.YES; + return true; + } + if (aType.isParameterizedType()) { + boolean b = aType.isParameterizedWithAMemberTypeVariable(); + if (b) { + parameterizedWithAMemberTypeVariable = FuzzyBoolean.YES; + return true; + } + } + if (aType.isGenericWildcard()) { + if (aType.isExtends()) { + boolean b = false; + UnresolvedType upperBound = aType.getUpperBound(); + if (upperBound.isParameterizedType()) { + b = upperBound.isParameterizedWithAMemberTypeVariable(); + } else if (upperBound.isTypeVariableReference() && ((TypeVariableReference)upperBound).getTypeVariable().getDeclaringElementKind()==TypeVariable.METHOD) { + b = true; + } + if (b) { + parameterizedWithAMemberTypeVariable = FuzzyBoolean.YES; + return true; + } + // FIXME asc need to check additional interface bounds + } + if (aType.isSuper()) { + boolean b = false; + UnresolvedType lowerBound = aType.getLowerBound(); + if (lowerBound.isParameterizedType()) { + b = lowerBound.isParameterizedWithAMemberTypeVariable(); + } else if (lowerBound.isTypeVariableReference() && ((TypeVariableReference)lowerBound).getTypeVariable().getDeclaringElementKind()==TypeVariable.METHOD) { + b = true; + } + if (b) { + parameterizedWithAMemberTypeVariable = FuzzyBoolean.YES; + return true; + } + } + } + } + parameterizedWithAMemberTypeVariable=FuzzyBoolean.NO; + } + return parameterizedWithAMemberTypeVariable.alwaysTrue(); + } + } diff --git a/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java b/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java index 48af493b5..06ae53554 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java @@ -321,4 +321,22 @@ public abstract class ResolvedTypeMunger { public boolean hasTypeVariableAliases() { return (typeVariableAliases!=null && typeVariableAliases.size()>0); } + + /** + * return true if type variables are specified with the target type for + * this ITD. e.g. this would return true: "int I<A,B>.m() { return 42; }" + */ + public boolean sharesTypeVariablesWithGenericType() { + return (typeVariableAliases!=null && typeVariableAliases.size()>0); + } + + /** + * Parameterizes a resolved type munger for a particular usage of + * its target type (this is used when the target type is generic + * and the ITD shares type variables with the target) + * see ConcreteTypeMunger.parameterizedFor + */ + public ResolvedTypeMunger parameterizedFor(ResolvedType target) { + throw new BCException("Should *NOT* be called for this kind of munger: "+this); + } } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java b/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java index a53078312..2ed9e71fe 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java @@ -1376,5 +1376,9 @@ public class BcelTypeMunger extends ConcreteTypeMunger { return false; } } + + public ConcreteTypeMunger parameterizedFor(ResolvedType target) { + return new BcelTypeMunger(munger.parameterizedFor(target),aspectType); + } }
\ No newline at end of file |