diff options
author | aclement <aclement> | 2008-08-28 16:27:48 +0000 |
---|---|---|
committer | aclement <aclement> | 2008-08-28 16:27:48 +0000 |
commit | 1361ef2f8e345f0a6fc1f8d518d0c938228d8ad7 (patch) | |
tree | e6b7d126be7b05cc0e65f06e0db7c70c6e0f3b5e /weaver/src | |
parent | c778fc5e3ccec7fc253fc7be2fe2247684ab7930 (diff) | |
download | aspectj-1361ef2f8e345f0a6fc1f8d518d0c938228d8ad7.tar.gz aspectj-1361ef2f8e345f0a6fc1f8d518d0c938228d8ad7.zip |
removed unused code and chewed on by formatter
Diffstat (limited to 'weaver/src')
7 files changed, 4212 insertions, 4870 deletions
diff --git a/weaver/src/org/aspectj/weaver/ResolvedType.java b/weaver/src/org/aspectj/weaver/ResolvedType.java index 79ede540a..0e910c047 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedType.java +++ b/weaver/src/org/aspectj/weaver/ResolvedType.java @@ -11,7 +11,6 @@ * Alexandre Vasseur @AspectJ ITDs * ******************************************************************/ - package org.aspectj.weaver; import java.lang.reflect.Modifier; @@ -36,309 +35,290 @@ import org.aspectj.weaver.patterns.PerClause; public abstract class ResolvedType extends UnresolvedType implements AnnotatedElement { - public static final ResolvedType[] EMPTY_RESOLVED_TYPE_ARRAY = new ResolvedType[0]; + public static final ResolvedType[] EMPTY_RESOLVED_TYPE_ARRAY = new ResolvedType[0]; public static final String PARAMETERIZED_TYPE_IDENTIFIER = "P"; - // Set during a type pattern match call - this currently used to hold the annotations // that may be attached to a type when it used as a parameter public ResolvedType[] temporaryAnnotationTypes; private ResolvedType[] resolvedTypeParams; private String binaryPath; - - 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); - this.world = world; - } - - // ---- things that don't require a world - - /** - * Returns an iterator through ResolvedType objects representing all the direct - * supertypes of this type. That is, through the superclass, if any, and - * all declared interfaces. - */ - public final Iterator getDirectSupertypes() { - Iterator ifacesIterator = Iterators.array(getDeclaredInterfaces()); - ResolvedType superclass = getSuperclass(); - if (superclass == null) { - return ifacesIterator; - } else { - return Iterators.snoc(ifacesIterator, superclass); - } - } - - 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. - */ - public abstract ResolvedType getSuperclass(); - - /** - * 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 - */ - public abstract int getModifiers(); - - // return true if this resolved type couldn't be found (but we know it's name maybe) - public boolean isMissing() { - return false; - } - - // FIXME asc I wonder if in some circumstances MissingWithKnownSignature should not be considered - // 'really' missing as some code can continue based solely on the signature - public static boolean isMissing (UnresolvedType unresolved) { - if (unresolved instanceof ResolvedType) { - ResolvedType resolved = (ResolvedType)unresolved; - return resolved.isMissing(); - } - else return (unresolved == MISSING); - } - - public ResolvedType[] getAnnotationTypes() { - return EMPTY_RESOLVED_TYPE_ARRAY; - } - - public AnnotationX getAnnotationOfType(UnresolvedType ofType) { - return null; - } - - 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. - protected 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 - public ResolvedType getResolvedComponentType() { - return null; - } + + 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); + this.world = world; + } + + // ---- things that don't require a world + + /** + * Returns an iterator through ResolvedType objects representing all the direct supertypes of this type. That is, through the + * superclass, if any, and all declared interfaces. + */ + public final Iterator getDirectSupertypes() { + Iterator ifacesIterator = Iterators.array(getDeclaredInterfaces()); + ResolvedType superclass = getSuperclass(); + if (superclass == null) { + return ifacesIterator; + } else { + return Iterators.snoc(ifacesIterator, superclass); + } + } + + 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. + */ + public abstract ResolvedType getSuperclass(); + + /** + * 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 + */ + public abstract int getModifiers(); + + // return true if this resolved type couldn't be found (but we know it's name maybe) + public boolean isMissing() { + return false; + } + + // FIXME asc I wonder if in some circumstances MissingWithKnownSignature should not be considered + // 'really' missing as some code can continue based solely on the signature + public static boolean isMissing(UnresolvedType unresolved) { + if (unresolved instanceof ResolvedType) { + ResolvedType resolved = (ResolvedType) unresolved; + return resolved.isMissing(); + } else + return (unresolved == MISSING); + } + + public ResolvedType[] getAnnotationTypes() { + return EMPTY_RESOLVED_TYPE_ARRAY; + } + + public AnnotationX getAnnotationOfType(UnresolvedType ofType) { + return null; + } + + 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. + protected 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 + public ResolvedType getResolvedComponentType() { + return null; + } public World getWorld() { return world; } - // ---- things from object - - public final boolean equals(Object other) { - if (other instanceof ResolvedType) { - return this == other; - } else { - 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> - * </ul> - * <p/> - * We keep a hashSet of interfaces that we've visited so we don't spiral - * out into 2^n land. - */ - public Iterator getFields() { - final Iterators.Filter dupFilter = Iterators.dupFilter(); - Iterators.Getter typeGetter = new Iterators.Getter() { - public Iterator get(Object o) { - 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.mapOver( - Iterators.recur(this, typeGetter), - fieldGetter); - } - - /** - * returns an iterator through all of the methods of this type, in order - * 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> - * </ul> - * <p/> - * We keep a hashSet of interfaces that we've visited so we don't spiral - * out into 2^n land. - * NOTE: Take a look at the javadoc on getMethodsWithoutIterator() to see if - * you are sensitive to a quirk in getMethods() - */ - public Iterator getMethods() { - 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()) - ); - } - }; - Iterators.Getter methodGetter = new Iterators.Getter() { - public Iterator get(Object o) { - 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 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 - * declared on *this* class twice, once at the start and once at the end - I couldn't debug that problem, so created this alternative. - */ - public List getMethodsWithoutIterator(boolean includeITDs, boolean allowMissing) { - List methods = new ArrayList(); - Set knowninterfaces = new HashSet(); - 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(); + // ---- things from object + + public final boolean equals(Object other) { + if (other instanceof ResolvedType) { + return this == other; + } else { + 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> + * </ul> + * <p/> We keep a hashSet of interfaces that we've visited so we don't spiral out into 2^n land. + */ + public Iterator getFields() { + final Iterators.Filter dupFilter = Iterators.dupFilter(); + Iterators.Getter typeGetter = new Iterators.Getter() { + public Iterator get(Object o) { + 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.mapOver(Iterators.recur(this, typeGetter), fieldGetter); + } + + /** + * returns an iterator through all of the methods of this type, in order 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> + * </ul> + * <p/> We keep a hashSet of interfaces that we've visited so we don't spiral out into 2^n land. NOTE: Take a look at the + * javadoc on getMethodsWithoutIterator() to see if you are sensitive to a quirk in getMethods() + */ + public Iterator getMethods() { + 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())); + } + }; + Iterators.Getter methodGetter = new Iterators.Getter() { + public Iterator get(Object o) { + 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 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 declared on *this* class twice, once at the start and once at the end - I couldn't debug that problem, so + * created this alternative. + */ + public List getMethodsWithoutIterator(boolean includeITDs, boolean allowMissing) { + List methods = new ArrayList(); + Set knowninterfaces = new HashSet(); + 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... + 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 + boolean shouldSkip = false; + for (int j = 0; j < rtx.interTypeMungers.size(); j++) { + ConcreteTypeMunger munger = (ConcreteTypeMunger) rtx.interTypeMungers.get(j); + if (munger.getMunger() != null && munger.getMunger().getKind() == ResolvedTypeMunger.Parent + && ((NewParentTypeMunger) munger.getMunger()).getNewParent().equals(iface) // pr171953 + ) { + shouldSkip = true; + break; + } + } + + 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); + } } - } - 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 - boolean shouldSkip = false; - for (int j = 0; j < rtx.interTypeMungers.size(); j++) { - ConcreteTypeMunger munger = (ConcreteTypeMunger) rtx.interTypeMungers.get(j); - if (munger.getMunger()!=null && munger.getMunger().getKind() == ResolvedTypeMunger.Parent - && ((NewParentTypeMunger)munger.getMunger()).getNewParent().equals(iface) // pr171953 - ) { - shouldSkip = true; - break; - } - } - - 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); - } - } - } - } - - public ResolvedType[] getResolvedTypeParameters() { - if (resolvedTypeParams == null) { - resolvedTypeParams = world.resolve(typeParameters); - } - return resolvedTypeParams; - } - - /** - * described in JVM spec 2ed 5.4.3.2 - */ - public ResolvedMember lookupField(Member m) { - return lookupMember(m, getFields()); - } - - /** - * described in JVM spec 2ed 5.4.3.3. - * Doesnt check ITDs. - */ - public ResolvedMember lookupMethod(Member m) { - return lookupMember(m, getMethods()); - } - - public ResolvedMember lookupMethodInITDs(Member m) { - if (interTypeMungers != null) { + } + } + + public ResolvedType[] getResolvedTypeParameters() { + if (resolvedTypeParams == null) { + resolvedTypeParams = world.resolve(typeParameters); + } + return resolvedTypeParams; + } + + /** + * described in JVM spec 2ed 5.4.3.2 + */ + public ResolvedMember lookupField(Member m) { + return lookupMember(m, getFields()); + } + + /** + * described in JVM spec 2ed 5.4.3.3. Doesnt check ITDs. + */ + 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)) { @@ -346,394 +326,389 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } } } - return null; - } - - /** - * return null if not found - */ - private ResolvedMember lookupMember(Member m, Iterator i) { - while (i.hasNext()) { - ResolvedMember f = (ResolvedMember) i.next(); - if (matches(f, m)) return f; - if (f.hasBackingGenericMember() && m.getName().equals(f.getName())) { // might be worth checking the method behind the parameterized method (see pr137496) - if (matches(f.getBackingGenericMember(),m)) return f; - } - } - return null; //ResolvedMember.Missing; - //throw new BCException("can't find " + m); - } - - /** - * return null if not found - */ - private ResolvedMember lookupMember(Member m, ResolvedMember[] a) { + return null; + } + + /** + * return null if not found + */ + private ResolvedMember lookupMember(Member m, Iterator i) { + while (i.hasNext()) { + ResolvedMember f = (ResolvedMember) i.next(); + if (matches(f, m)) + return f; + if (f.hasBackingGenericMember() && m.getName().equals(f.getName())) { // might be worth checking the method behind the + // parameterized method (see pr137496) + if (matches(f.getBackingGenericMember(), m)) + return f; + } + } + 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; + 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. - */ - 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(); + } + + /** + * 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. + */ + 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; - - // If they aren't the same, we need to allow for covariance ... where one sig might be ()LCar; and - // 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.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.getGenericParameterTypes(); - UnresolvedType[] p2 = m2.getGenericParameterTypes(); - if (p1==null) p1 = m1.getParameterTypes(); - if (p2==null) 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> - * </ul> - * <p/> - * We keep a hashSet of interfaces that we've visited so we don't spiral - * out into 2^n land. - */ - public Iterator getPointcuts() { - final Iterators.Filter dupFilter = Iterators.dupFilter(); - // same order as fields - Iterators.Getter typeGetter = new Iterators.Getter() { - public Iterator get(Object o) { - 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.mapOver( - Iterators.recur(this, typeGetter), - pointcutGetter); - } - - public ResolvedPointcutDefinition findPointcut(String name) { - //System.err.println("looking for pointcuts " + this); - for (Iterator i = getPointcuts(); i.hasNext(); ) { - ResolvedPointcutDefinition f = (ResolvedPointcutDefinition) i.next(); - //System.err.println(f); - if (name.equals(f.getName())) { - return f; - } - } - // pr120521 - if (!getOutermostType().equals(this)) { - ResolvedType outerType = getOutermostType().resolve(world); - ResolvedPointcutDefinition rpd = outerType.findPointcut(name); - return rpd; - } - return null; // should we throw an exception here? - } - - - // all about collecting CrosscuttingMembers - - //??? collecting data-structure, shouldn't really be a field - public CrosscuttingMembers crosscuttingMembers; + } + } + + 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; + + // If they aren't the same, we need to allow for covariance ... where one sig might be ()LCar; and + // 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.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.getGenericParameterTypes(); + UnresolvedType[] p2 = m2.getGenericParameterTypes(); + if (p1 == null) + p1 = m1.getParameterTypes(); + if (p2 == null) + 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> + * </ul> + * <p/> We keep a hashSet of interfaces that we've visited so we don't spiral out into 2^n land. + */ + public Iterator getPointcuts() { + final Iterators.Filter dupFilter = Iterators.dupFilter(); + // same order as fields + Iterators.Getter typeGetter = new Iterators.Getter() { + public Iterator get(Object o) { + 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.mapOver(Iterators.recur(this, typeGetter), pointcutGetter); + } + + public ResolvedPointcutDefinition findPointcut(String name) { + // System.err.println("looking for pointcuts " + this); + for (Iterator i = getPointcuts(); i.hasNext();) { + ResolvedPointcutDefinition f = (ResolvedPointcutDefinition) i.next(); + // System.err.println(f); + if (name.equals(f.getName())) { + return f; + } + } + // pr120521 + if (!getOutermostType().equals(this)) { + ResolvedType outerType = getOutermostType().resolve(world); + ResolvedPointcutDefinition rpd = outerType.findPointcut(name); + return rpd; + } + return null; // should we throw an exception here? + } + + // all about collecting CrosscuttingMembers + + // ??? collecting data-structure, shouldn't really be a field + public CrosscuttingMembers crosscuttingMembers; public CrosscuttingMembers collectCrosscuttingMembers(boolean shouldConcretizeIfNeeded) { - crosscuttingMembers = new CrosscuttingMembers(this,shouldConcretizeIfNeeded); + crosscuttingMembers = new CrosscuttingMembers(this, shouldConcretizeIfNeeded); crosscuttingMembers.setPerClause(getPerClause()); crosscuttingMembers.addShadowMungers(collectShadowMungers()); // GENERICITDFIX -// crosscuttingMembers.addTypeMungers(collectTypeMungers()); - crosscuttingMembers.addTypeMungers(getTypeMungers()); - //FIXME AV - skip but needed ?? or ?? crosscuttingMembers.addLateTypeMungers(getLateTypeMungers()); + // crosscuttingMembers.addTypeMungers(collectTypeMungers()); + 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()); + + // System.err.println("collected cc members: " + this + ", " + collectDeclares()); return crosscuttingMembers; } - + public final Collection collectTypeMungers() { - if (! this.isAspect() ) return Collections.EMPTY_LIST; - + 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()) { + // 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()) { 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(); - for (Iterator i = ty.getTypeMungers().iterator(); i.hasNext();) { - ConcreteTypeMunger dec = (ConcreteTypeMunger) i.next(); + 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(); + for (Iterator i = ty.getTypeMungers().iterator(); i.hasNext();) { + ConcreteTypeMunger dec = (ConcreteTypeMunger) i.next(); ret.add(dec); } - } + } } - + return ret; - } - + } + public final Collection collectDeclares(boolean includeAdviceLike) { - if (! this.isAspect() ) return Collections.EMPTY_LIST; - + 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()) { + // 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()); + // 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();) { + 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); + 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; + } + + private final Collection collectShadowMungers() { + if (!this.isAspect() || this.isAbstract() || this.doesNotExposeShadowMungers()) + return Collections.EMPTY_LIST; 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()); - } - }; - Iterator typeIterator = Iterators.recur(this, typeGetter); - - while (typeIterator.hasNext()) { - ResolvedType ty = (ResolvedType) typeIterator.next(); - acc.addAll(ty.getDeclaredShadowMungers()); - } - - return acc; - } - + 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(); + acc.addAll(ty.getDeclaredShadowMungers()); + } + + return acc; + } + protected boolean doesNotExposeShadowMungers() { return false; } - public PerClause getPerClause() { - return null; - } + public PerClause getPerClause() { + return null; + } 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() { - return Modifier.isInterface(getModifiers()); - } - - public final boolean isAbstract() { - return Modifier.isAbstract(getModifiers()); - } - - public boolean isClass() { - return false; - } - - public boolean isAspect() { - return false; - } - - public boolean isAnnotationStyleAspect() { - return false; - } - - /** - * Note: Only overridden by Name subtype. - */ - public boolean isEnum() { - return false; - } - - /** - * Note: Only overridden by Name subtype. - */ - public boolean isAnnotation() { - return false; - } - - public boolean isAnonymous() { - return false; - } - - public boolean isNested() { - return false; - } - - - public void addAnnotation(AnnotationX annotationX) { - throw new RuntimeException("ResolvedType.addAnnotation() should never be called"); - } - + return Collections.EMPTY_LIST; + } + + protected Collection getTypeMungers() { + return Collections.EMPTY_LIST; + } + + protected Collection getPrivilegedAccesses() { + return Collections.EMPTY_LIST; + } + + // ---- useful things + + public final boolean isInterface() { + return Modifier.isInterface(getModifiers()); + } + + public final boolean isAbstract() { + return Modifier.isAbstract(getModifiers()); + } + + public boolean isClass() { + return false; + } + + public boolean isAspect() { + return false; + } + + public boolean isAnnotationStyleAspect() { + return false; + } + + /** + * Note: Only overridden by Name subtype. + */ + public boolean isEnum() { + return false; + } + + /** + * Note: Only overridden by Name subtype. + */ + public boolean isAnnotation() { + return false; + } + + public boolean isAnonymous() { + return false; + } + + public boolean isNested() { + return false; + } + + public void addAnnotation(AnnotationX annotationX) { + throw new RuntimeException("ResolvedType.addAnnotation() should never be called"); + } + public AnnotationX[] getAnnotations() { throw new RuntimeException("ResolvedType.getAnnotations() should never be called"); } - + /** * Note: Only overridden by ReferenceType subtype */ public boolean canAnnotationTargetType() { return false; } - + /** * Note: Only overridden by ReferenceType subtype - */ + */ public AnnotationTargetKind[] getAnnotationTargetKinds() { return null; } - - /** - * Note: Only overridden by Name subtype. - */ - public boolean isAnnotationWithRuntimeRetention() { - return false; - } - - public boolean isSynthetic() { - 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; + + /** + * Note: Only overridden by Name subtype. + */ + public boolean isAnnotationWithRuntimeRetention() { + return false; + } + + public boolean isSynthetic() { + 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++) { @@ -742,22 +717,22 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl return parameterizationMap; } - public Collection getDeclaredAdvice() { List l = new ArrayList(); ResolvedMember[] methods = getDeclaredMethods(); - if (isParameterizedType()) methods = getGenericType().getDeclaredMethods(); + if (isParameterizedType()) + methods = getGenericType().getDeclaredMethods(); Map typeVariableMap = getAjMemberParameterizationMap(); - for (int i=0, len = methods.length; i < len; i++) { + for (int i = 0, len = methods.length; i < len; i++) { ShadowMunger munger = methods[i].getAssociatedShadowMunger(); if (munger != null) { if (ajMembersNeedParameterization()) { - //munger.setPointcut(munger.getPointcut().parameterizeWith(typeVariableMap)); - munger = munger.parameterizeWith(this,typeVariableMap); + // munger.setPointcut(munger.getPointcut().parameterizeWith(typeVariableMap)); + munger = munger.parameterizeWith(this, typeVariableMap); if (munger instanceof Advice) { Advice advice = (Advice) munger; // update to use the parameterized signature... - UnresolvedType[] ptypes = methods[i].getGenericParameterTypes() ; + UnresolvedType[] ptypes = methods[i].getGenericParameterTypes(); UnresolvedType[] newPTypes = new UnresolvedType[ptypes.length]; for (int j = 0; j < ptypes.length; j++) { if (ptypes[j] instanceof TypeVariableReferenceType) { @@ -780,309 +755,259 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } return l; } - + public Collection getDeclaredShadowMungers() { Collection c = getDeclaredAdvice(); return c; } - - // ---- only for testing! + // ---- 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) { + 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 BOOLEAN = new Primitive("Z", 1, 7); + public static final Missing MISSING = new Missing(); + + /** Reset the static state in the primitive types */ + // OPTIMIZE I think we have a bug here because primitives are static and the world they use may vary (or may even be + // null) + public static void resetPrimitives() { + BYTE.world = null; + CHAR.world = null; + DOUBLE.world = null; + FLOAT.world = null; + INT.world = null; + LONG.world = null; + SHORT.world = null; + VOID.world = null; + BOOLEAN.world = null; + } + + // ---- types + public static ResolvedType makeArray(ResolvedType type, int dim) { + if (dim == 0) + return type; + ResolvedType array = new ArrayReferenceType("[" + type.getSignature(), "[" + type.getErasureSignature(), type.getWorld(), + type); + return makeArray(array, dim - 1); + } + + 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; + this.typeKind = TypeKind.PRIMITIVE; + } + + public final int getSize() { + return size; + } + + public final int getModifiers() { + return Modifier.PUBLIC | Modifier.FINAL; + } - // ---- 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 BOOLEAN = new Primitive("Z", 1, 7); - public static final Missing MISSING = new Missing(); - - /** Reset the static state in the primitive types */ - // OPTIMIZE I think we have a bug here because primitives are static and the world they use may vary (or may even be - // null) - public static void resetPrimitives() { - BYTE.world=null; - CHAR.world=null; - DOUBLE.world=null; - FLOAT.world=null; - INT.world=null; - LONG.world=null; - SHORT.world=null; - VOID.world=null; - BOOLEAN.world=null; - } - - - // ---- types - public static ResolvedType makeArray(ResolvedType type, int dim) { - if (dim == 0) return type; - ResolvedType array = new ArrayReferenceType("[" + type.getSignature(),"["+type.getErasureSignature(),type.getWorld(),type); - return makeArray(array,dim-1); - } - - static class Array extends ResolvedType { - ResolvedType componentType; - - - // Sometimes the erasure is different, eg. [TT; and [Ljava/lang/Object; - Array(String sig, String erasureSig,World world, ResolvedType componentType) { - super(sig,erasureSig, 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; - } - public final ResolvedType[] getDeclaredInterfaces() { - return - new ResolvedType[] { - world.getCoreType(CLONEABLE), - world.getCoreType(SERIALIZABLE) - }; - } - public final ResolvedMember[] getDeclaredPointcuts() { - return ResolvedMember.NONE; - } - - public boolean hasAnnotation(UnresolvedType ofType) { - 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()) { - return o.equals(this); - } else { - return getComponentType().resolve(world).isAssignableFrom(o.getComponentType().resolve(world)); - } - } - - public boolean isAssignableFrom(ResolvedType o, boolean allowMissing) { - return isAssignableFrom(o); - } - - public final boolean isCoerceableFrom(ResolvedType o) { - if (o.equals(UnresolvedType.OBJECT) || - o.equals(UnresolvedType.SERIALIZABLE) || - o.equals(UnresolvedType.CLONEABLE)) { - return true; - } - if (! o.isArray()) return false; - if (o.getComponentType().isPrimitiveType()) { - return o.equals(this); - } else { - 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(); - } - } - - 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; - this.typeKind=TypeKind.PRIMITIVE; - } - 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; - } - public final boolean isAssignableFrom(ResolvedType other) { - if (!other.isPrimitiveType()) { - if (!world.isInJava5Mode()) return false; - return validBoxing.contains(this.getSignature()+other.getSignature()); - } - return assignTable[((Primitive)other).index][index]; - } - public final boolean isAssignableFrom(ResolvedType other, boolean allowMissing) { - 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; - 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 - }; - - // ---- - - 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; - } - - public final ResolvedType getSuperclass() { - return null; - } - - public ISourceContext getSourceContext() { - 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; - } - - public final boolean isMissing() { - return true; - } - - public boolean hasAnnotation(UnresolvedType ofType) { - return false; - } - 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; - } - 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; - } - - } - - /** - * Look up a member, takes into account any ITDs on this type. - * return null if not found - */ + public final boolean isPrimitiveType() { + return true; + } + + public boolean hasAnnotation(UnresolvedType ofType) { + return false; + } + + public final boolean isAssignableFrom(ResolvedType other) { + if (!other.isPrimitiveType()) { + if (!world.isInJava5Mode()) + return false; + return validBoxing.contains(this.getSignature() + other.getSignature()); + } + return assignTable[((Primitive) other).index][index]; + } + + public final boolean isAssignableFrom(ResolvedType other, boolean allowMissing) { + 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; + 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 + }; + + // ---- + + 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; + } + + public final ResolvedType getSuperclass() { + return null; + } + + public ISourceContext getSourceContext() { + 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; + } + + public final boolean isMissing() { + return true; + } + + public boolean hasAnnotation(UnresolvedType ofType) { + return false; + } + + 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; + } + + 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; + } + + } + + /** + * 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) { @@ -1095,23 +1020,25 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } return ret; } - + public ResolvedMember lookupMemberWithSupersAndITDs(Member member) { ResolvedMember ret = lookupMemberNoSupers(member); - if (ret != null) return ret; - + if (ret != null) + return ret; + ResolvedType supert = getSuperclass(); - while (ret==null && supert!=null) { + while (ret == null && supert != null) { ret = supert.lookupMemberNoSupers(member); - if (ret==null) supert = supert.getSuperclass(); + if (ret == null) + supert = supert.getSuperclass(); } - + return ret; } - + /** * as lookupMemberNoSupers, but does not include ITDs - * + * * @param member * @return */ @@ -1125,19 +1052,18 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } 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. - * + * 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) { @@ -1145,199 +1071,193 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } else { ResolvedType superType = onType.getSuperclass(); if (superType != null) { - ret = lookupMemberIncludingITDsOnInterfaces(member,superType); + 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; + 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); + + 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; } - return l; - } - + /** - * ??? This method is O(N*M) where N = number of methods and M is number of - * inter-type declarations in my super + * ??? 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; - } - - private void collectInterTypeParentMungers(List collector) { - for (Iterator iter = getDirectSupertypes(); iter.hasNext();) { - ResolvedType superType = (ResolvedType) iter.next(); - superType.collectInterTypeParentMungers(collector); - } - collector.addAll(getInterTypeParentMungers()); - } - - - protected void collectInterTypeMungers(List collector) { - for (Iterator iter = getDirectSupertypes(); iter.hasNext();) { + public List getInterTypeMungersIncludingSupers() { + ArrayList ret = new ArrayList(); + collectInterTypeMungers(ret); + return ret; + } + + public List getInterTypeParentMungersIncludingSupers() { + ArrayList ret = new ArrayList(); + collectInterTypeParentMungers(ret); + return ret; + } + + private void collectInterTypeParentMungers(List collector) { + for (Iterator iter = getDirectSupertypes(); iter.hasNext();) { + ResolvedType superType = (ResolvedType) iter.next(); + superType.collectInterTypeParentMungers(collector); + } + collector.addAll(getInterTypeParentMungers()); + } + + protected void collectInterTypeMungers(List collector) { + for (Iterator iter = getDirectSupertypes(); iter.hasNext();) { ResolvedType superType = (ResolvedType) iter.next(); if (superType == null) { - throw new BCException("UnexpectedProblem: a supertype in the hierarchy for " + this.getName() + " is null"); - } - 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; - - for (Iterator iter = getInterTypeMungers().iterator(); iter.hasNext();) { - 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(); - 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. - * 2) That an abstract ITDM on an interface is declared public. (Compiler limitation) (PR70794) - */ - public void checkInterTypeMungers() { - if (isAbstract()) return; - - boolean itdProblem = false; - - for (Iterator iter = getInterTypeMungersIncludingSupers().iterator(); iter.hasNext();) { + throw new BCException("UnexpectedProblem: a supertype in the hierarchy for " + this.getName() + " is null"); + } + 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; + + for (Iterator iter = getInterTypeMungers().iterator(); iter.hasNext();) { + 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(); + 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. 2) That an abstract ITDM on an interface + * is declared public. (Compiler limitation) (PR70794) + */ + 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 - } - - if (itdProblem) return; // If the rules above are broken, return right now - + } + + if (itdProblem) + return; // If the rules above are broken, return right now + 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.getSignature() 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) })); - } - } - } - } - - /** - * 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)) { + if (munger.getSignature() != null && munger.getSignature().isAbstract()) { // Rule 1 + if (munger.getMunger().getKind() == ResolvedTypeMunger.MethodDelegate) { + // ignore for @AJ ITD as munger.getSignature() 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) })); + } + } + } + } + + /** + * 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; - } + 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 - * for the munger itself is null. In these cases use the - * 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; - } - - /** - * Returns a ResolvedType object representing the declaring type of this type, or - * null if this type does not represent a non-package-level-type. - * <p/> - * <strong>Warning</strong>: This is guaranteed to work for all member types. - * For anonymous/local types, the only guarantee is given in JLS 13.1, where - * it guarantees that if you call getDeclaringType() repeatedly, you will eventually - * get the top-level class, but it does not say anything about classes in between. - * - * @return the declaring UnresolvedType object, or null. - */ - public ResolvedType getDeclaringType() { - if (isArray()) return null; + } + + /** + * Get a source location for the munger. Until intertype mungers remember where they came from, the source location for the + * munger itself is null. In these cases use the 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; + } + + /** + * Returns a ResolvedType object representing the declaring type of this type, or null if this type does not represent a + * non-package-level-type. <p/> <strong>Warning</strong>: This is guaranteed to work for all member types. For anonymous/local + * types, the only guarantee is given in JLS 13.1, where it guarantees that if you call getDeclaringType() repeatedly, you will + * eventually get the top-level class, but it does not say anything about classes in between. + * + * @return the declaring UnresolvedType object, or null. + */ + public ResolvedType getDeclaringType() { + if (isArray()) + return null; String name = getName(); int lastDollar = name.lastIndexOf('$'); - while (lastDollar >0) { // allow for classes starting '$' (pr120474) + while (lastDollar > 0) { // allow for classes starting '$' (pr120474) ResolvedType ret = world.resolve(UnresolvedType.forName(name.substring(0, lastDollar)), true); - if (!ResolvedType.isMissing(ret)) return ret; - lastDollar = name.lastIndexOf('$', lastDollar-1); + if (!ResolvedType.isMissing(ret)) + 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); - + // System.err.println("mod: " + modifiers + ", " + targetType + " and " + fromType); + if (Modifier.isPublic(modifiers)) { return true; } else if (Modifier.isPrivate(modifiers)) { @@ -1346,154 +1266,160 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl 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; + return (modifiers & Constants.ACC_BRIDGE) != 0; } - private static boolean samePackage( - ResolvedType targetType, - ResolvedType fromType) { + 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; + 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. + * 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 discoverActualOccurrenceOfTypeInHierarchy(ResolvedType lookingFor) { - if (!lookingFor.isGenericType()) - throw new BCException("assertion failed: method should only be called with generic type, but "+lookingFor+" is "+lookingFor.typeKind); - - if (this.equals(ResolvedType.OBJECT)) return null; - - if (genericTypeEquals(lookingFor)) return this; - - ResolvedType superT = getSuperclass(); - if (superT.genericTypeEquals(lookingFor)) return superT; - - ResolvedType[] superIs = getDeclaredInterfaces(); - for (int i = 0; i < superIs.length; i++) { - ResolvedType superI = superIs[i]; - if (superI.genericTypeEquals(lookingFor)) return superI; - ResolvedType checkTheSuperI = superI.discoverActualOccurrenceOfTypeInHierarchy(lookingFor); - if (checkTheSuperI!=null) return checkTheSuperI; - } - return superT.discoverActualOccurrenceOfTypeInHierarchy(lookingFor); - } - - /** - * 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 ConcreteTypeMunger fillInAnyTypeParameters(ConcreteTypeMunger munger) { - boolean debug = false; + 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 discoverActualOccurrenceOfTypeInHierarchy(ResolvedType lookingFor) { + if (!lookingFor.isGenericType()) + throw new BCException("assertion failed: method should only be called with generic type, but " + lookingFor + " is " + + lookingFor.typeKind); + + if (this.equals(ResolvedType.OBJECT)) + return null; + + if (genericTypeEquals(lookingFor)) + return this; + + ResolvedType superT = getSuperclass(); + if (superT.genericTypeEquals(lookingFor)) + return superT; + + ResolvedType[] superIs = getDeclaredInterfaces(); + for (int i = 0; i < superIs.length; i++) { + ResolvedType superI = superIs[i]; + if (superI.genericTypeEquals(lookingFor)) + return superI; + ResolvedType checkTheSuperI = superI.discoverActualOccurrenceOfTypeInHierarchy(lookingFor); + if (checkTheSuperI != null) + return checkTheSuperI; + } + return superT.discoverActualOccurrenceOfTypeInHierarchy(lookingFor); + } + + /** + * 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 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 = discoverActualOccurrenceOfTypeInHierarchy(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("Occurrence in "+this+" is actually "+actualTarget+" ("+actualTarget.typeKind+")"); - // parameterize the signature - // ResolvedMember newOne = member.parameterizedWith(actualTarget.getTypeParameters(),onType,actualTarget.isParameterizedType()); - } - //if (!actualTarget.isRawType()) - munger = munger.parameterizedFor(actualTarget); - if (debug) System.err.println("New sig: "+munger.getSignature()); - - - if (debug) System.err.println("====================================="); + 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 = discoverActualOccurrenceOfTypeInHierarchy(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("Occurrence in " + this + " is actually " + actualTarget + " (" + actualTarget.typeKind + + ")"); + // parameterize the signature + // ResolvedMember newOne = + // member.parameterizedWith(actualTarget.getTypeParameters(),onType,actualTarget.isParameterizedType()); + } + // if (!actualTarget.isRawType()) + munger = munger.parameterizedFor(actualTarget); + if (debug) + System.err.println("New sig: " + munger.getSignature()); + + 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) - { + if (sig == null || munger.getMunger() == null || munger.getMunger().getKind() == ResolvedTypeMunger.PrivilegedAccess) { interTypeMungers.add(munger); return; } - -// ConcreteTypeMunger originalMunger = munger; + + // 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 + // 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); + // System.err.println("add: " + munger + " to " + this.getClassName() + " with " + interTypeMungers); if (sig.getKind() == Member.METHOD) { - if (!compareToExistingMembers(munger, getMethodsWithoutIterator(false,true) /*getMethods()*/)) return; + if (!compareToExistingMembers(munger, getMethodsWithoutIterator(false, true) /* getMethods() */)) + return; if (this.isInterface()) { - if (!compareToExistingMembers(munger, - Arrays.asList(world.getCoreType(OBJECT).getDeclaredMethods()).iterator())) return; + 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; + if (!compareToExistingMembers(munger, Arrays.asList(getDeclaredFields()).iterator())) + return; } else { - if (!compareToExistingMembers(munger, Arrays.asList(getDeclaredMethods()).iterator())) return; + if (!compareToExistingMembers(munger, Arrays.asList(getDeclaredMethods()).iterator())) + return; } - // now compare to existingMungers - for (Iterator i = interTypeMungers.iterator(); i.hasNext(); ) { - ConcreteTypeMunger existingMunger = (ConcreteTypeMunger)i.next(); + 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"); + // 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); + // System.err.println(" compare: " + c); if (c < 0) { // the existing munger dominates the new munger checkLegalOverride(munger.getSignature(), existingMunger.getSignature()); @@ -1507,53 +1433,55 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl interTypeConflictError(munger, existingMunger); interTypeConflictError(existingMunger, munger); return; - } + } } } } - //System.err.println("adding: " + munger + " to " + this); + // System.err.println("adding: " + munger + " to " + this); // we are adding the parameterized form of the ITD to the list of - // mungers. Within it, the munger knows the original declared + // mungers. Within it, the munger knows the original declared // signature for the ITD so it can be retrieved. interTypeMungers.add(munger); } - + private boolean compareToExistingMembers(ConcreteTypeMunger munger, List existingMembersList) { - return compareToExistingMembers(munger,existingMembersList.iterator()); + return compareToExistingMembers(munger, existingMembersList.iterator()); } - - //??? returning too soon + + // ??? returning too soon private boolean compareToExistingMembers(ConcreteTypeMunger munger, Iterator existingMembers) { ResolvedMember sig = munger.getSignature(); - -// ResolvedType declaringAspectType = munger.getAspectType(); -// if (declaringAspectType.isRawType()) declaringAspectType = declaringAspectType.getGenericType(); -// if (declaringAspectType.isGenericType()) { -// -// ResolvedType genericOnType = getWorld().resolve(sig.getDeclaringType()).getGenericType(); -// ConcreteTypeMunger ctm = munger.parameterizedFor(discoverActualOccurrenceOfTypeInHierarchy(genericOnType)); -// sig = ctm.getSignature(); // possible sig change when type -// } -// if (munger.getMunger().hasTypeVariableAliases()) { -// ResolvedType genericOnType = -// getWorld().resolve(sig.getDeclaringType()).getGenericType(); -// ConcreteTypeMunger ctm = -// munger.parameterizedFor(discoverActualOccurrenceOfTypeInHierarchy(genericOnType)); -// sig = ctm.getSignature(); // possible sig change when type parameters filled in -// } + + // ResolvedType declaringAspectType = munger.getAspectType(); + // if (declaringAspectType.isRawType()) declaringAspectType = declaringAspectType.getGenericType(); + // if (declaringAspectType.isGenericType()) { + // + // ResolvedType genericOnType = getWorld().resolve(sig.getDeclaringType()).getGenericType(); + // ConcreteTypeMunger ctm = munger.parameterizedFor(discoverActualOccurrenceOfTypeInHierarchy(genericOnType)); + // sig = ctm.getSignature(); // possible sig change when type + // } + // if (munger.getMunger().hasTypeVariableAliases()) { + // ResolvedType genericOnType = + // getWorld().resolve(sig.getDeclaringType()).getGenericType(); + // ConcreteTypeMunger ctm = + // munger.parameterizedFor(discoverActualOccurrenceOfTypeInHierarchy(genericOnType)); + // sig = ctm.getSignature(); // possible sig change when type parameters filled in + // } while (existingMembers.hasNext()) { - - ResolvedMember existingMember = (ResolvedMember)existingMembers.next(); + + ResolvedMember existingMember = (ResolvedMember) existingMembers.next(); // don't worry about clashing with bridge methods - if (existingMember.isBridgeMethod()) continue; - //System.err.println("Comparing munger: "+sig+" with member "+existingMember); + if (existingMember.isBridgeMethod()) + continue; + // 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()); - + // 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); + // System.err.println(" c: " + c); if (c < 0) { // existingMember dominates munger checkLegalOverride(munger.getSignature(), existingMember); @@ -1561,185 +1489,189 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } else if (c > 0) { // munger dominates existingMember checkLegalOverride(existingMember, munger.getSignature()); - //interTypeMungers.add(munger); - //??? might need list of these overridden abstracts + // 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) { - // pr206732 - if the existingMember is due to a previous application of this same ITD (which can - // happen if this is a binary type being brought in from the aspectpath). The 'better' fix is - // to recognize it is from the aspectpath at a higher level and dont do this, but that is rather - // more work. - boolean isDuplicateOfPreviousITD = false; - ResolvedType declaringRt = existingMember.getDeclaringType().resolve(world); - WeaverStateInfo wsi = declaringRt.getWeaverState(); - if (wsi!=null) { - List mungersAffectingThisType = wsi.getTypeMungers(declaringRt); - if (mungersAffectingThisType!=null) { - for (Iterator iterator = mungersAffectingThisType.iterator(); iterator.hasNext() && !isDuplicateOfPreviousITD;) { - ConcreteTypeMunger ctMunger = (ConcreteTypeMunger) iterator.next(); - // relatively crude check - is the ITD for the same as the existingmember and does it come from the same aspect - if (ctMunger.getSignature().equals(existingMember) && ctMunger.aspectType.equals(munger.getAspectType())) { - isDuplicateOfPreviousITD=true; + // 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) { + // pr206732 - if the existingMember is due to a previous application of this same ITD (which can + // happen if this is a binary type being brought in from the aspectpath). The 'better' fix is + // to recognize it is from the aspectpath at a higher level and dont do this, but that is rather + // more work. + boolean isDuplicateOfPreviousITD = false; + ResolvedType declaringRt = existingMember.getDeclaringType().resolve(world); + WeaverStateInfo wsi = declaringRt.getWeaverState(); + if (wsi != null) { + List mungersAffectingThisType = wsi.getTypeMungers(declaringRt); + if (mungersAffectingThisType != null) { + for (Iterator iterator = mungersAffectingThisType.iterator(); iterator.hasNext() + && !isDuplicateOfPreviousITD;) { + ConcreteTypeMunger ctMunger = (ConcreteTypeMunger) iterator.next(); + // relatively crude check - is the ITD for the same as the existingmember and does it come + // from the same aspect + if (ctMunger.getSignature().equals(existingMember) + && ctMunger.aspectType.equals(munger.getAspectType())) { + isDuplicateOfPreviousITD = true; + } } - } - } - } - if (!isDuplicateOfPreviousITD) { - getWorld().getMessageHandler().handleMessage( - MessageUtil.error(WeaverMessages.format(WeaverMessages.ITD_MEMBER_CONFLICT,munger.getAspectType().getName(), - existingMember), - munger.getSourceLocation()) - ); - } - } + } + } + if (!isDuplicateOfPreviousITD) { + 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()) - ); - + } 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; } } 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; - } - + 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. + * @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()); + // 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); + 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.resolve(world).getGenericReturnType().resolve(world); - ResolvedType rtChildReturnType = child.resolve(world).getGenericReturnType().resolve(world); - incompatibleReturnTypes = !rtParentReturnType.isAssignableFrom(rtChildReturnType); - // For debug, uncomment this bit and we'll repeat the check - stick a breakpoint on the call -// if (incompatibleReturnTypes) { -// incompatibleReturnTypes = !rtParentReturnType.isAssignableFrom(rtChildReturnType); -// } + if (world.isInJava5Mode() && parent.getKind() == Member.METHOD) { + + // Look at the generic types when doing this comparison + ResolvedType rtParentReturnType = parent.resolve(world).getGenericReturnType().resolve(world); + ResolvedType rtChildReturnType = child.resolve(world).getGenericReturnType().resolve(world); + incompatibleReturnTypes = !rtParentReturnType.isAssignableFrom(rtChildReturnType); + // For debug, uncomment this bit and we'll repeat the check - stick a breakpoint on the call + // if (incompatibleReturnTypes) { + // incompatibleReturnTypes = !rtParentReturnType.isAssignableFrom(rtChildReturnType); + // } } else { - incompatibleReturnTypes =!parent.getReturnType().equals(child.getReturnType()); + 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()); + 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), + 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()); + } + // 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()); + 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; - + + 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; + 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); - + // 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); + 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); + 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; - + // 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 + // 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.getName().charAt(0)=='c') { + // java rules. clone goes against these... + if (m2.isProtected() && m2.getName().charAt(0) == 'c') { UnresolvedType declaring = m2.getDeclaringType(); - if (declaring!=null) { - if (declaring.getName().equals("java.lang.Object") && m2.getName().equals("clone")) return +1; + if (declaring != null) { + if (declaring.getName().equals("java.lang.Object") && 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; - + 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)) { @@ -1750,13 +1682,16 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } 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); + 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); } @@ -1764,121 +1699,119 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl 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()); - } - - + 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(); + // ??? 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); + // System.err.println(" found: " + ret); return ret; } } - + // Handling members for the new array join point if (world.isJoinpointArrayConstructionEnabled() && this.isArray()) { - if (member.getKind()==Member.CONSTRUCTOR) { - ResolvedMemberImpl ret = - new ResolvedMemberImpl(Member.CONSTRUCTOR,this,Modifier.PUBLIC, - ResolvedType.VOID,"<init>",world.resolve(member.getParameterTypes())); + if (member.getKind() == Member.CONSTRUCTOR) { + ResolvedMemberImpl ret = new ResolvedMemberImpl(Member.CONSTRUCTOR, this, Modifier.PUBLIC, ResolvedType.VOID, + "<init>", world.resolve(member.getParameterTypes())); return ret; } } - -// if (this.getSuperclass() != ResolvedType.OBJECT && this.getSuperclass() != null) { -// return getSuperclass().lookupSyntheticMember(member); -// } - + + // if (this.getSuperclass() != ResolvedType.OBJECT && this.getSuperclass() != null) { + // return getSuperclass().lookupSyntheticMember(member); + // } + return null; } public void clearInterTypeMungers() { - if (isRawType()) getGenericType().clearInterTypeMungers(); + if (isRawType()) + getGenericType().clearInterTypeMungers(); interTypeMungers = new ArrayList(); } - public boolean isTopmostImplementor(ResolvedType interfaceType) { - if (isInterface()) return false; - if (!interfaceType.isAssignableFrom(this,true)) return false; + 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)) { + 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; + 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; + ResolvedType higherType = this.getSuperclass().getTopmostImplementor(interfaceType); + if (higherType != null) + return higherType; return this; } - + 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(); + 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()); + 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()), + 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); + 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)) { + ResolvedPointcutDefinition existing = (ResolvedPointcutDefinition) j.next(); + if (existing == toAdd) + continue; + if (!isVisible(existing.getModifiers(), existing.getDeclaringType().resolve(getWorld()), this)) { // if they intended to override it but it is not visible, give them a nicer message - if (existing.isAbstract() && conflictingSignature(existing,toAdd)) { + if (existing.isAbstract() && conflictingSignature(existing, toAdd)) { getWorld().showMessage( IMessage.ERROR, - WeaverMessages.format(WeaverMessages.POINTCUT_NOT_VISIBLE, - existing.getDeclaringType().getName() + "." + existing.getName()+"()", this.getName()), - toAdd.getSourceLocation(),null); + WeaverMessages.format(WeaverMessages.POINTCUT_NOT_VISIBLE, existing.getDeclaringType().getName() + + "." + existing.getName() + "()", this.getName()), toAdd.getSourceLocation(), null); j.remove(); } continue; @@ -1889,10 +1822,9 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl j.remove(); } else { getWorld().showMessage( - IMessage.ERROR, - WeaverMessages.format(WeaverMessages.CONFLICTING_INHERITED_POINTCUTS,this.getName() + toAdd.getSignature()), - existing.getSourceLocation(), - toAdd.getSourceLocation()); + IMessage.ERROR, + WeaverMessages.format(WeaverMessages.CONFLICTING_INHERITED_POINTCUTS, this.getName() + + toAdd.getSignature()), existing.getSourceLocation(), toAdd.getSourceLocation()); j.remove(); } } @@ -1900,106 +1832,110 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl acc.add(toAdd); } } - - public ISourceLocation getSourceLocation() { - return null; - } - public boolean isExposedToWeaver() { - return false; - } + public ISourceLocation getSourceLocation() { + return null; + } + + public boolean isExposedToWeaver() { + return false; + } 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"); + throw new BCException("The type " + getBaseName() + " is not parameterized or raw - it has no generic type"); return null; } - + /** * overriden by ReferenceType to return the gsig for a generic type + * * @return */ public String getGenericSignature() { return ""; } - - + public ResolvedType parameterizedWith(UnresolvedType[] typeParameters) { - if (!(isGenericType() || isParameterizedType())) return this; + 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. + * 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()) return this;//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() || - (typeParameters[i] instanceof BoundedReferenceType)) { + if (!isParameterizedType()) + return this;// 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() || (typeParameters[i] instanceof BoundedReferenceType)) { workToDo = true; } } - if (!workToDo) { - return this; - } else { - UnresolvedType[] newTypeParams = new UnresolvedType[typeParameters.length]; - for (int i = 0; i < newTypeParams.length; i++) { + 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; + if (binding != null) + newTypeParams[i] = binding; } else if (newTypeParams[i] instanceof BoundedReferenceType) { - BoundedReferenceType brType = (BoundedReferenceType)newTypeParams[i]; + BoundedReferenceType brType = (BoundedReferenceType) newTypeParams[i]; newTypeParams[i] = brType.parameterize(typeBindings); -// brType.parameterize(typeBindings) + // brType.parameterize(typeBindings) } } - return TypeFactory.createParameterizedType(getGenericType(), newTypeParams, getWorld()); - } - } - + 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; + 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; + if (parameterizedSuperTypes != null) + return parameterizedSuperTypes; List accumulatedTypes = new ArrayList(); - accumulateParameterizedSuperTypes(this,accumulatedTypes); + 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); @@ -2017,124 +1953,127 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl * Types may have pointcuts just as they have methods and fields. */ public ResolvedPointcutDefinition findPointcut(String name, World world) { - throw new UnsupportedOperationException("Not yet implemenented"); + throw new UnsupportedOperationException("Not yet implemenented"); } - + /** * @return true if assignable to java.lang.Exception */ public boolean isException() { return (world.getCoreType(UnresolvedType.JAVA_LANG_EXCEPTION).isAssignableFrom(this)); } - + /** * @return true if it is an exception and it is a checked one, false otherwise. */ public boolean isCheckedException() { - if (!isException()) return false; - if (world.getCoreType(UnresolvedType.RUNTIME_EXCEPTION).isAssignableFrom(this)) return false; + if (!isException()) + return false; + if (world.getCoreType(UnresolvedType.RUNTIME_EXCEPTION).isAssignableFrom(this)) + return false; return true; } /** - * 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. + * 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); - } + 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). + * 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 + * @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". - * <p/> - * <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> - * + * 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/> <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. + * @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); + return isAssignableFrom(o); } - + public String getSignatureForAttribute() { - return signature; // Assume if this is being called that it is for a simple type (eg. void, int, etc) + return signature; // Assume if this is being called that it is for a simple type (eg. void, int, etc) } - + private FuzzyBoolean parameterizedWithTypeVariable = FuzzyBoolean.MAYBE; - + /** - * return true if the parameterization of this type includes a member type variable. Member - * type variables occur in generic methods/ctors. + * return true if the parameterization of this type includes a member type variable. Member type variables occur in generic + * methods/ctors. */ public boolean isParameterizedWithTypeVariable() { // MAYBE means we haven't worked it out yet... - if (parameterizedWithTypeVariable==FuzzyBoolean.MAYBE) { - + if (parameterizedWithTypeVariable == FuzzyBoolean.MAYBE) { + // if there are no type parameters then we cant be... - if (typeParameters==null || typeParameters.length==0) { + if (typeParameters == null || typeParameters.length == 0) { parameterizedWithTypeVariable = FuzzyBoolean.NO; return false; } - + for (int i = 0; i < typeParameters.length; i++) { - ResolvedType aType = (ResolvedType)typeParameters[i]; - if (aType.isTypeVariableReference() - // Changed according to the problems covered in bug 222648 - // Don't care what kind of type variable - the fact that there is one - // at all means we can't risk caching it against we get confused later - // by another variation of the parameterization that just happens to - // use the same type variable name - - // assume the worst - if its definetly not a type declared one, it could be anything - // && ((TypeVariableReference)aType).getTypeVariable().getDeclaringElementKind()!=TypeVariable.TYPE - ) { + ResolvedType aType = (ResolvedType) typeParameters[i]; + if (aType.isTypeVariableReference() + // Changed according to the problems covered in bug 222648 + // Don't care what kind of type variable - the fact that there is one + // at all means we can't risk caching it against we get confused later + // by another variation of the parameterization that just happens to + // use the same type variable name + + // assume the worst - if its definetly not a type declared one, it could be anything + // && ((TypeVariableReference)aType).getTypeVariable().getDeclaringElementKind()!=TypeVariable.TYPE + ) { parameterizedWithTypeVariable = FuzzyBoolean.YES; return true; } @@ -2146,13 +2085,14 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } } if (aType.isGenericWildcard()) { - BoundedReferenceType boundedRT = (BoundedReferenceType) aType; + BoundedReferenceType boundedRT = (BoundedReferenceType) aType; if (boundedRT.isExtends()) { boolean b = false; UnresolvedType upperBound = boundedRT.getUpperBound(); if (upperBound.isParameterizedType()) { - b = ((ResolvedType)upperBound).isParameterizedWithTypeVariable(); - } else if (upperBound.isTypeVariableReference() && ((TypeVariableReference)upperBound).getTypeVariable().getDeclaringElementKind()==TypeVariable.METHOD) { + b = ((ResolvedType) upperBound).isParameterizedWithTypeVariable(); + } else if (upperBound.isTypeVariableReference() + && ((TypeVariableReference) upperBound).getTypeVariable().getDeclaringElementKind() == TypeVariable.METHOD) { b = true; } if (b) { @@ -2165,8 +2105,9 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl boolean b = false; UnresolvedType lowerBound = boundedRT.getLowerBound(); if (lowerBound.isParameterizedType()) { - b = ((ResolvedType)lowerBound).isParameterizedWithTypeVariable(); - } else if (lowerBound.isTypeVariableReference() && ((TypeVariableReference)lowerBound).getTypeVariable().getDeclaringElementKind()==TypeVariable.METHOD) { + b = ((ResolvedType) lowerBound).isParameterizedWithTypeVariable(); + } else if (lowerBound.isTypeVariableReference() + && ((TypeVariableReference) lowerBound).getTypeVariable().getDeclaringElementKind() == TypeVariable.METHOD) { b = true; } if (b) { @@ -2176,14 +2117,16 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl } } } - parameterizedWithTypeVariable=FuzzyBoolean.NO; + parameterizedWithTypeVariable = FuzzyBoolean.NO; } return parameterizedWithTypeVariable.alwaysTrue(); } protected boolean ajMembersNeedParameterization() { - if (isParameterizedType()) return true; - if (getSuperclass() != null) return getSuperclass().ajMembersNeedParameterization(); + if (isParameterizedType()) + return true; + if (getSuperclass() != null) + return getSuperclass().ajMembersNeedParameterization(); return false; } @@ -2191,22 +2134,21 @@ public abstract class ResolvedType extends UnresolvedType implements AnnotatedEl Map myMap = getMemberParameterizationMap(); if (myMap.isEmpty()) { // might extend a parameterized aspect that we also need to consider... - if (getSuperclass() != null) return getSuperclass().getAjMemberParameterizationMap(); + if (getSuperclass() != null) + return getSuperclass().getAjMemberParameterizationMap(); } return myMap; } - + public void setBinaryPath(String binaryPath) { this.binaryPath = binaryPath; } /** - * Returns the path to the jar or class file from which this - * binary aspect came or null if not a binary aspect + * Returns the path to the jar or class file from which this binary aspect came or null if not a binary aspect */ public String getBinaryPath() { return binaryPath; } - } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java index 26fbf0566..153335a74 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java @@ -11,7 +11,6 @@ * Alexandre Vasseur support for @AJ aspects * ******************************************************************/ - package org.aspectj.weaver.bcel; import java.lang.reflect.Modifier; @@ -64,13 +63,12 @@ import org.aspectj.weaver.UnresolvedType; import org.aspectj.weaver.WeaverMessages; import org.aspectj.weaver.World; import org.aspectj.weaver.ast.Var; +import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor; import org.aspectj.weaver.patterns.AndPointcut; -import org.aspectj.weaver.patterns.IdentityPointcutVisitor; import org.aspectj.weaver.patterns.NotPointcut; import org.aspectj.weaver.patterns.OrPointcut; import org.aspectj.weaver.patterns.ThisOrTargetPointcut; - /* * Some fun implementation stuff: * @@ -122,22 +120,21 @@ import org.aspectj.weaver.patterns.ThisOrTargetPointcut; */ public class BcelShadow extends Shadow { - - private ShadowRange range; - private final BcelWorld world; - private final LazyMethodGen enclosingMethod; - + + private ShadowRange range; + private final BcelWorld world; + private final LazyMethodGen enclosingMethod; + // SECRETAPI - for testing, this will tell us if the optimization succeeded *on the last shadow processed* public static boolean appliedLazyTjpOptimization; - - // Some instructions have a target type that will vary - // from the signature (pr109728) (1.4 declaring type issue) - private String actualInstructionTargetType; + + // Some instructions have a target type that will vary + // from the signature (pr109728) (1.4 declaring type issue) + private String actualInstructionTargetType; /** - * This generates an unassociated shadow, rooted in a particular method but not rooted - * to any particular point in the code. It should be given to a rooted ShadowRange - * in the {@link ShadowRange#associateWithShadow(BcelShadow)} method. + * This generates an unassociated shadow, rooted in a particular method but not rooted to any particular point in the code. It + * should be given to a rooted ShadowRange in the {@link ShadowRange#associateWithShadow(BcelShadow)} method. */ public BcelShadow(BcelWorld world, Kind kind, Member signature, LazyMethodGen enclosingMethod, BcelShadow enclosingShadow) { super(kind, signature, enclosingShadow); @@ -149,19 +146,20 @@ public class BcelShadow extends Shadow { public BcelShadow copyInto(LazyMethodGen recipient, BcelShadow enclosing) { BcelShadow s = new BcelShadow(world, getKind(), getSignature(), recipient, enclosing); - if (mungers.size()>0) { + if (mungers.size() > 0) { List src = mungers; - if (s.mungers==Collections.EMPTY_LIST) s.mungers = new ArrayList(); + if (s.mungers == Collections.EMPTY_LIST) + s.mungers = new ArrayList(); List dest = s.mungers; - - for (Iterator i = src.iterator(); i.hasNext(); ) { + + for (Iterator i = src.iterator(); i.hasNext();) { dest.add(i.next()); } } return s; } - // ---- overridden behaviour + // ---- overridden behaviour public World getIWorld() { return world; @@ -172,67 +170,67 @@ public class BcelShadow extends Shadow { int depth = 1; InstructionHandle ih = range.getStart(); - // Go back from where we are looking for 'NEW' that takes us to a stack depth of 0. INVOKESPECIAL <init> + // Go back from where we are looking for 'NEW' that takes us to a stack depth of 0. INVOKESPECIAL <init> while (true) { Instruction inst = ih.getInstruction(); - if (inst.opcode==Constants.INVOKESPECIAL - && ((InvokeInstruction) inst).getName(cpg).equals("<init>")) { + if (inst.opcode == Constants.INVOKESPECIAL && ((InvokeInstruction) inst).getName(cpg).equals("<init>")) { depth++; - } else if (inst.opcode==Constants.NEW) { + } else if (inst.opcode == Constants.NEW) { depth--; - if (depth == 0) break; - } else if (inst.opcode==Constants.DUP_X2) { + if (depth == 0) + break; + } else if (inst.opcode == Constants.DUP_X2) { // This code seen in the wild (by Brad): -// 40: new #12; //class java/lang/StringBuffer -// STACK: STRINGBUFFER -// 43: dup -// STACK: STRINGBUFFER/STRINGBUFFER -// 44: aload_0 -// STACK: STRINGBUFFER/STRINGBUFFER/THIS -// 45: dup_x2 -// STACK: THIS/STRINGBUFFER/STRINGBUFFER/THIS -// 46: getfield #36; //Field value:Ljava/lang/String; -// STACK: THIS/STRINGBUFFER/STRINGBUFFER/STRING<value> -// 49: invokestatic #37; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; -// STACK: THIS/STRINGBUFFER/STRINGBUFFER/STRING -// 52: invokespecial #19; //Method java/lang/StringBuffer."<init>":(Ljava/lang/String;)V -// STACK: THIS/STRINGBUFFER -// 55: aload_1 -// STACK: THIS/STRINGBUFFER/LOCAL1 -// 56: invokevirtual #22; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; -// STACK: THIS/STRINGBUFFER -// 59: invokevirtual #34; //Method java/lang/StringBuffer.toString:()Ljava/lang/String; -// STACK: THIS/STRING -// 62: putfield #36; //Field value:Ljava/lang/String; -// STACK: <empty> -// 65: return - + // 40: new #12; //class java/lang/StringBuffer + // STACK: STRINGBUFFER + // 43: dup + // STACK: STRINGBUFFER/STRINGBUFFER + // 44: aload_0 + // STACK: STRINGBUFFER/STRINGBUFFER/THIS + // 45: dup_x2 + // STACK: THIS/STRINGBUFFER/STRINGBUFFER/THIS + // 46: getfield #36; //Field value:Ljava/lang/String; + // STACK: THIS/STRINGBUFFER/STRINGBUFFER/STRING<value> + // 49: invokestatic #37; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; + // STACK: THIS/STRINGBUFFER/STRINGBUFFER/STRING + // 52: invokespecial #19; //Method java/lang/StringBuffer."<init>":(Ljava/lang/String;)V + // STACK: THIS/STRINGBUFFER + // 55: aload_1 + // STACK: THIS/STRINGBUFFER/LOCAL1 + // 56: invokevirtual #22; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; + // STACK: THIS/STRINGBUFFER + // 59: invokevirtual #34; //Method java/lang/StringBuffer.toString:()Ljava/lang/String; + // STACK: THIS/STRING + // 62: putfield #36; //Field value:Ljava/lang/String; + // STACK: <empty> + // 65: return + // if we attempt to match on the ctor call to StringBuffer.<init> then we get into trouble. // if we simply delete the new/dup pair without fixing up the dup_x2 then the dup_x2 will fail due to there - // not being 3 elements on the stack for it to work with. The fix *in this situation* is to change it to + // not being 3 elements on the stack for it to work with. The fix *in this situation* is to change it to // a simple 'dup' - + // this fix is *not* very clean - but a general purpose decent solution will take much longer and this // bytecode sequence has only been seen once in the wild. ih.setInstruction(InstructionConstants.DUP); } ih = ih.getPrev(); } - // now IH points to the NEW. We're followed by the DUP, and that is followed - // by the actual instruction we care about. + // now IH points to the NEW. We're followed by the DUP, and that is followed + // by the actual instruction we care about. InstructionHandle newHandle = ih; InstructionHandle endHandle = newHandle.getNext(); InstructionHandle nextHandle; - if (endHandle.getInstruction().opcode==Constants.DUP) { - nextHandle = endHandle.getNext(); + if (endHandle.getInstruction().opcode == Constants.DUP) { + nextHandle = endHandle.getNext(); retargetFrom(newHandle, nextHandle); retargetFrom(endHandle, nextHandle); - } else if (endHandle.getInstruction().opcode==Constants.DUP_X1) { + } else if (endHandle.getInstruction().opcode == Constants.DUP_X1) { InstructionHandle dupHandle = endHandle; endHandle = endHandle.getNext(); nextHandle = endHandle.getNext(); - if (endHandle.getInstruction().opcode==Constants.SWAP) {} - else { + if (endHandle.getInstruction().opcode == Constants.SWAP) { + } else { // XXX see next XXX comment throw new RuntimeException("Unhandled kind of new " + endHandle); } @@ -256,67 +254,68 @@ public class BcelShadow extends Shadow { throw new BCException("shouldn't happen"); } } + private void retargetFrom(InstructionHandle old, InstructionHandle fresh) { InstructionTargeter[] sources = old.getTargetersArray(); if (sources != null) { for (int i = sources.length - 1; i >= 0; i--) { if (sources[i] instanceof ExceptionRange) { - ExceptionRange it = (ExceptionRange)sources[i]; + ExceptionRange it = (ExceptionRange) sources[i]; System.err.println("..."); - it.updateTarget(old,fresh,it.getBody()); + it.updateTarget(old, fresh, it.getBody()); } else { - sources[i].updateTarget(old, fresh); + sources[i].updateTarget(old, fresh); } } } } - + // records advice that is stopping us doing the lazyTjp optimization private List badAdvice = null; - + public void addAdvicePreventingLazyTjp(BcelAdvice advice) { - if (badAdvice == null) badAdvice = new ArrayList(); + if (badAdvice == null) + badAdvice = new ArrayList(); badAdvice.add(advice); } - - protected void prepareForMungers() { - // if we're a constructor call, we need to remove the new:dup or the new:dup_x1:swap, + + protected void prepareForMungers() { + // if we're a constructor call, we need to remove the new:dup or the new:dup_x1:swap, // and store all our // arguments on the frame. - - // ??? This is a bit of a hack (for the Java langauge). We do this because - // we sometime add code "outsideBefore" when dealing with weaving join points. We only - // do this for exposing state that is on the stack. It turns out to just work for - // everything except for constructor calls and exception handlers. If we were to clean - // this up, every ShadowRange would have three instructionHandle points, the start of + + // ??? This is a bit of a hack (for the Java langauge). We do this because + // we sometime add code "outsideBefore" when dealing with weaving join points. We only + // do this for exposing state that is on the stack. It turns out to just work for + // everything except for constructor calls and exception handlers. If we were to clean + // this up, every ShadowRange would have three instructionHandle points, the start of // the arg-setup code, the start of the running code, and the end of the running code. if (getKind() == ConstructorCall) { if (!world.isJoinpointArrayConstructionEnabled() || !this.getSignature().getDeclaringType().isArray()) - deleteNewAndDup(); // no new/dup for new array construction + deleteNewAndDup(); // no new/dup for new array construction initializeArgVars(); } else if (getKind() == PreInitialization) { // pr74952 ShadowRange range = getRange(); - range.insert(InstructionConstants.NOP,Range.InsideAfter); + range.insert(InstructionConstants.NOP, Range.InsideAfter); } else if (getKind() == ExceptionHandler) { - + ShadowRange range = getRange(); InstructionList body = range.getBody(); - InstructionHandle start = range.getStart(); - - // Create a store instruction to put the value from the top of the - // stack into a local variable slot. This is a trimmed version of + InstructionHandle start = range.getStart(); + + // Create a store instruction to put the value from the top of the + // stack into a local variable slot. This is a trimmed version of // what is in initializeArgVars() (since there is only one argument // at a handler jp and only before advice is supported) (pr46298) - argVars = new BcelVar[1]; - //int positionOffset = (hasTarget() ? 1 : 0) + ((hasThis() && !getKind().isTargetSameAsThis()) ? 1 : 0); + argVars = new BcelVar[1]; + // int positionOffset = (hasTarget() ? 1 : 0) + ((hasThis() && !getKind().isTargetSameAsThis()) ? 1 : 0); UnresolvedType tx = getArgType(0); - argVars[0] = genTempVar(tx, "ajc$arg0"); - InstructionHandle insertedInstruction = - range.insert(argVars[0].createStore(getFactory()), Range.OutsideBefore); + argVars[0] = genTempVar(tx, "ajc$arg0"); + InstructionHandle insertedInstruction = range.insert(argVars[0].createStore(getFactory()), Range.OutsideBefore); - // Now the exception range starts just after our new instruction. - // The next bit of code changes the exception range to point at - // the store instruction + // Now the exception range starts just after our new instruction. + // The next bit of code changes the exception range to point at + // the store instruction InstructionTargeter[] targeters = start.getTargetersArray(); for (int i = 0; i < targeters.length; i++) { InstructionTargeter t = targeters[i]; @@ -328,663 +327,480 @@ public class BcelShadow extends Shadow { } // now we ask each munger to request our state - isThisJoinPointLazy = true;//world.isXlazyTjp(); // lazy is default now + isThisJoinPointLazy = true;// world.isXlazyTjp(); // lazy is default now badAdvice = null; for (Iterator iter = mungers.iterator(); iter.hasNext();) { ShadowMunger munger = (ShadowMunger) iter.next(); munger.specializeOn(this); } - - + initializeThisJoinPoint(); - if (thisJoinPointVar!=null && !isThisJoinPointLazy && badAdvice!=null && badAdvice.size()>1) { + if (thisJoinPointVar != null && !isThisJoinPointLazy && badAdvice != null && badAdvice.size() > 1) { // something stopped us making it a lazy tjp // can't build tjp lazily, no suitable test... int valid = 0; for (Iterator iter = badAdvice.iterator(); iter.hasNext();) { BcelAdvice element = (BcelAdvice) iter.next(); ISourceLocation sLoc = element.getSourceLocation(); - if (sLoc!=null && sLoc.getLine()>0) valid++; + if (sLoc != null && sLoc.getLine() > 0) + valid++; } - if (valid!=0) { + if (valid != 0) { ISourceLocation[] badLocs = new ISourceLocation[valid]; int i = 0; for (Iterator iter = badAdvice.iterator(); iter.hasNext();) { BcelAdvice element = (BcelAdvice) iter.next(); ISourceLocation sLoc = element.getSourceLocation(); - if (sLoc!=null) badLocs[i++]=sLoc; + if (sLoc != null) + badLocs[i++] = sLoc; } - world.getLint().multipleAdviceStoppingLazyTjp.signal( - new String[] {this.toString()}, - getSourceLocation(),badLocs - ); + world.getLint().multipleAdviceStoppingLazyTjp + .signal(new String[] { this.toString() }, getSourceLocation(), badLocs); } } - badAdvice=null; - - - // If we are an expression kind, we require our target/arguments on the stack - // before we do our actual thing. However, they may have been removed - // from the stack as the shadowMungers have requested state. - // if any of our shadowMungers requested either the arguments or target, - // the munger will have added code - // to pop the target/arguments into temporary variables, represented by - // targetVar and argVars. In such a case, we must make sure to re-push the - // values. - - // If we are nonExpressionKind, we don't expect arguments on the stack - // so this is moot. If our argVars happen to be null, then we know that - // no ShadowMunger has squirrelled away our arguments, so they're still - // on the stack. + badAdvice = null; + + // If we are an expression kind, we require our target/arguments on the stack + // before we do our actual thing. However, they may have been removed + // from the stack as the shadowMungers have requested state. + // if any of our shadowMungers requested either the arguments or target, + // the munger will have added code + // to pop the target/arguments into temporary variables, represented by + // targetVar and argVars. In such a case, we must make sure to re-push the + // values. + + // If we are nonExpressionKind, we don't expect arguments on the stack + // so this is moot. If our argVars happen to be null, then we know that + // no ShadowMunger has squirrelled away our arguments, so they're still + // on the stack. InstructionFactory fact = getFactory(); if (getKind().argsOnStack() && argVars != null) { - - // Special case first (pr46298). If we are an exception handler and the instruction - // just after the shadow is a POP then we should remove the pop. The code + + // Special case first (pr46298). If we are an exception handler and the instruction + // just after the shadow is a POP then we should remove the pop. The code // above which generated the store instruction has already cleared the stack. // We also don't generate any code for the arguments in this case as it would be // an incorrect aload. - if (getKind() == ExceptionHandler - && range.getEnd().getNext().getInstruction().equals(InstructionConstants.POP)) { + if (getKind() == ExceptionHandler && range.getEnd().getNext().getInstruction().equals(InstructionConstants.POP)) { // easier than deleting it ... range.getEnd().getNext().setInstruction(InstructionConstants.NOP); } else { - range.insert( - BcelRenderer.renderExprs(fact, world, argVars), - Range.InsideBefore); - if (targetVar != null) { - range.insert( - BcelRenderer.renderExpr(fact, world, targetVar), - Range.InsideBefore); - } - if (getKind() == ConstructorCall) { - if (!world.isJoinpointArrayConstructionEnabled() || !this.getSignature().getDeclaringType().isArray()) { - range.insert(InstructionFactory.createDup(1), Range.InsideBefore); - range.insert( - fact.createNew( - (ObjectType) BcelWorld.makeBcelType( - getSignature().getDeclaringType())), - Range.InsideBefore); - } - } + range.insert(BcelRenderer.renderExprs(fact, world, argVars), Range.InsideBefore); + if (targetVar != null) { + range.insert(BcelRenderer.renderExpr(fact, world, targetVar), Range.InsideBefore); + } + if (getKind() == ConstructorCall) { + if (!world.isJoinpointArrayConstructionEnabled() || !this.getSignature().getDeclaringType().isArray()) { + range.insert(InstructionFactory.createDup(1), Range.InsideBefore); + range.insert(fact.createNew((ObjectType) BcelWorld.makeBcelType(getSignature().getDeclaringType())), + Range.InsideBefore); + } + } } } - } + } + + // ---- getters - // ---- getters + public ShadowRange getRange() { + return range; + } - public ShadowRange getRange() { - return range; - } public void setRange(ShadowRange range) { this.range = range; } - + private int sourceline = -1; - - public int getSourceLine() { - // if the kind of join point for which we are a shadow represents - // a method or constructor execution, then the best source line is - // the one from the enclosingMethod declarationLineNumber if available. - if (sourceline!=-1) return sourceline; - Kind kind = getKind(); - if ( (kind == MethodExecution) || - (kind == ConstructorExecution) || - (kind == AdviceExecution) || - (kind == StaticInitialization) || - (kind == PreInitialization) || - (kind == Initialization)) { - if (getEnclosingMethod().hasDeclaredLineNumberInfo()) { - sourceline= getEnclosingMethod().getDeclarationLineNumber(); - return sourceline; - } - } - - if (range == null) { - if (getEnclosingMethod().hasBody()) { - sourceline= Utility.getSourceLine(getEnclosingMethod().getBody().getStart()); - return sourceline; - } else { - sourceline= 0; - return sourceline; - } - } - sourceline = Utility.getSourceLine(range.getStart()); - if (sourceline < 0) sourceline = 0; - return sourceline; - } - - // overrides - public UnresolvedType getEnclosingType() { - return getEnclosingClass().getType(); - } - - public LazyClassGen getEnclosingClass() { - return enclosingMethod.getEnclosingClass(); - } - - public BcelWorld getWorld() { - return world; - } - - // ---- factory methods - - public static BcelShadow makeConstructorExecution( - BcelWorld world, - LazyMethodGen enclosingMethod, - InstructionHandle justBeforeStart) - { + + public int getSourceLine() { + // if the kind of join point for which we are a shadow represents + // a method or constructor execution, then the best source line is + // the one from the enclosingMethod declarationLineNumber if available. + if (sourceline != -1) + return sourceline; + Kind kind = getKind(); + if ((kind == MethodExecution) || (kind == ConstructorExecution) || (kind == AdviceExecution) + || (kind == StaticInitialization) || (kind == PreInitialization) || (kind == Initialization)) { + if (getEnclosingMethod().hasDeclaredLineNumberInfo()) { + sourceline = getEnclosingMethod().getDeclarationLineNumber(); + return sourceline; + } + } + + if (range == null) { + if (getEnclosingMethod().hasBody()) { + sourceline = Utility.getSourceLine(getEnclosingMethod().getBody().getStart()); + return sourceline; + } else { + sourceline = 0; + return sourceline; + } + } + sourceline = Utility.getSourceLine(range.getStart()); + if (sourceline < 0) + sourceline = 0; + return sourceline; + } + + // overrides + public UnresolvedType getEnclosingType() { + return getEnclosingClass().getType(); + } + + public LazyClassGen getEnclosingClass() { + return enclosingMethod.getEnclosingClass(); + } + + public BcelWorld getWorld() { + return world; + } + + // ---- factory methods + + public static BcelShadow makeConstructorExecution(BcelWorld world, LazyMethodGen enclosingMethod, + InstructionHandle justBeforeStart) { final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = - new BcelShadow( - world, - ConstructorExecution, - world.makeJoinPointSignatureFromMethod(enclosingMethod,Member.CONSTRUCTOR), - enclosingMethod, - null); + BcelShadow s = new BcelShadow(world, ConstructorExecution, world.makeJoinPointSignatureFromMethod(enclosingMethod, + Member.CONSTRUCTOR), enclosingMethod, null); ShadowRange r = new ShadowRange(body); r.associateWithShadow(s); - r.associateWithTargets( - Range.genStart(body, justBeforeStart.getNext()), - Range.genEnd(body)); + r.associateWithTargets(Range.genStart(body, justBeforeStart.getNext()), Range.genEnd(body)); return s; } - public static BcelShadow makeStaticInitialization( - BcelWorld world, - LazyMethodGen enclosingMethod) - { - InstructionList body = enclosingMethod.getBody(); - // move the start past ajc$preClinit - InstructionHandle clinitStart = body.getStart(); - if (clinitStart.getInstruction() instanceof InvokeInstruction) { - InvokeInstruction ii = (InvokeInstruction)clinitStart.getInstruction(); - if (ii - .getName(enclosingMethod.getEnclosingClass().getConstantPool()) - .equals(NameMangler.AJC_PRE_CLINIT_NAME)) { + public static BcelShadow makeStaticInitialization(BcelWorld world, LazyMethodGen enclosingMethod) { + InstructionList body = enclosingMethod.getBody(); + // move the start past ajc$preClinit + InstructionHandle clinitStart = body.getStart(); + if (clinitStart.getInstruction() instanceof InvokeInstruction) { + InvokeInstruction ii = (InvokeInstruction) clinitStart.getInstruction(); + if (ii.getName(enclosingMethod.getEnclosingClass().getConstantPool()).equals(NameMangler.AJC_PRE_CLINIT_NAME)) { clinitStart = clinitStart.getNext(); } - } - - InstructionHandle clinitEnd = body.getEnd(); - - //XXX should move the end before the postClinit, but the return is then tricky... -// if (clinitEnd.getInstruction() instanceof InvokeInstruction) { -// InvokeInstruction ii = (InvokeInstruction)clinitEnd.getInstruction(); -// if (ii.getName(enclosingMethod.getEnclosingClass().getConstantPool()).equals(NameMangler.AJC_POST_CLINIT_NAME)) { -// clinitEnd = clinitEnd.getPrev(); -// } -// } - - - - BcelShadow s = - new BcelShadow( - world, - StaticInitialization, - world.makeJoinPointSignatureFromMethod(enclosingMethod,Member.STATIC_INITIALIZATION), - enclosingMethod, - null); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets( - Range.genStart(body, clinitStart), - Range.genEnd(body, clinitEnd)); - return s; - } - - /** Make the shadow for an exception handler. Currently makes an empty shadow that - * only allows before advice to be woven into it. - */ + } + InstructionHandle clinitEnd = body.getEnd(); - public static BcelShadow makeExceptionHandler( - BcelWorld world, - ExceptionRange exceptionRange, - LazyMethodGen enclosingMethod, - InstructionHandle startOfHandler, - BcelShadow enclosingShadow) - { + // XXX should move the end before the postClinit, but the return is then tricky... + // if (clinitEnd.getInstruction() instanceof InvokeInstruction) { + // InvokeInstruction ii = (InvokeInstruction)clinitEnd.getInstruction(); + // if (ii.getName(enclosingMethod.getEnclosingClass().getConstantPool()).equals(NameMangler.AJC_POST_CLINIT_NAME)) { + // clinitEnd = clinitEnd.getPrev(); + // } + // } + + BcelShadow s = new BcelShadow(world, StaticInitialization, world.makeJoinPointSignatureFromMethod(enclosingMethod, + Member.STATIC_INITIALIZATION), enclosingMethod, null); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets(Range.genStart(body, clinitStart), Range.genEnd(body, clinitEnd)); + return s; + } + + /** + * Make the shadow for an exception handler. Currently makes an empty shadow that only allows before advice to be woven into it. + */ + + public static BcelShadow makeExceptionHandler(BcelWorld world, ExceptionRange exceptionRange, LazyMethodGen enclosingMethod, + InstructionHandle startOfHandler, BcelShadow enclosingShadow) { InstructionList body = enclosingMethod.getBody(); UnresolvedType catchType = exceptionRange.getCatchType(); UnresolvedType inType = enclosingMethod.getEnclosingClass().getType(); - - ResolvedMemberImpl sig = MemberImpl.makeExceptionHandlerSignature(inType, catchType); - sig.setParameterNames(new String[] {findHandlerParamName(startOfHandler)}); - - BcelShadow s = - new BcelShadow( - world, - ExceptionHandler, - sig, - enclosingMethod, - enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - InstructionHandle start = Range.genStart(body, startOfHandler); - InstructionHandle end = Range.genEnd(body, start); - - r.associateWithTargets(start, end); - exceptionRange.updateTarget(startOfHandler, start, body); - return s; - } - - private static String findHandlerParamName(InstructionHandle startOfHandler) { - if (startOfHandler.getInstruction().isStoreInstruction() && - startOfHandler.getNext() != null) - { + + ResolvedMemberImpl sig = MemberImpl.makeExceptionHandlerSignature(inType, catchType); + sig.setParameterNames(new String[] { findHandlerParamName(startOfHandler) }); + + BcelShadow s = new BcelShadow(world, ExceptionHandler, sig, enclosingMethod, enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + InstructionHandle start = Range.genStart(body, startOfHandler); + InstructionHandle end = Range.genEnd(body, start); + + r.associateWithTargets(start, end); + exceptionRange.updateTarget(startOfHandler, start, body); + return s; + } + + private static String findHandlerParamName(InstructionHandle startOfHandler) { + if (startOfHandler.getInstruction().isStoreInstruction() && startOfHandler.getNext() != null) { int slot = startOfHandler.getInstruction().getIndex(); - //System.out.println("got store: " + startOfHandler.getInstruction() + ", " + index); + // System.out.println("got store: " + startOfHandler.getInstruction() + ", " + index); Iterator tIter = startOfHandler.getNext().getTargeters().iterator(); while (tIter.hasNext()) { - InstructionTargeter targeter = (InstructionTargeter)tIter.next(); + InstructionTargeter targeter = (InstructionTargeter) tIter.next(); if (targeter instanceof LocalVariableTag) { - LocalVariableTag t = (LocalVariableTag)targeter; + LocalVariableTag t = (LocalVariableTag) targeter; if (t.getSlot() == slot) { return t.getName(); } } } } - + return "<missing>"; } - - /** create an init join point associated w/ an interface in the body of a constructor */ - - public static BcelShadow makeIfaceInitialization( - BcelWorld world, - LazyMethodGen constructor, - Member interfaceConstructorSignature) - { + + /** create an init join point associated w/ an interface in the body of a constructor */ + + public static BcelShadow makeIfaceInitialization(BcelWorld world, LazyMethodGen constructor, + Member interfaceConstructorSignature) { // this call marks the instruction list as changed constructor.getBody(); // UnresolvedType inType = constructor.getEnclosingClass().getType(); - BcelShadow s = - new BcelShadow( - world, - Initialization, - interfaceConstructorSignature, - constructor, - null); -// s.fallsThrough = true; -// ShadowRange r = new ShadowRange(body); -// r.associateWithShadow(s); -// InstructionHandle start = Range.genStart(body, handle); -// InstructionHandle end = Range.genEnd(body, handle); -// -// r.associateWithTargets(start, end); - return s; - } - + BcelShadow s = new BcelShadow(world, Initialization, interfaceConstructorSignature, constructor, null); + // s.fallsThrough = true; + // ShadowRange r = new ShadowRange(body); + // r.associateWithShadow(s); + // InstructionHandle start = Range.genStart(body, handle); + // InstructionHandle end = Range.genEnd(body, handle); + // + // r.associateWithTargets(start, end); + return s; + } + public void initIfaceInitializer(InstructionHandle end) { final InstructionList body = enclosingMethod.getBody(); ShadowRange r = new ShadowRange(body); r.associateWithShadow(this); InstructionHandle nop = body.insert(end, InstructionConstants.NOP); - - r.associateWithTargets( - Range.genStart(body, nop), - Range.genEnd(body, nop)); - } - -// public static BcelShadow makeIfaceConstructorExecution( -// BcelWorld world, -// LazyMethodGen constructor, -// InstructionHandle next, -// Member interfaceConstructorSignature) -// { -// // final InstructionFactory fact = constructor.getEnclosingClass().getFactory(); -// InstructionList body = constructor.getBody(); -// // UnresolvedType inType = constructor.getEnclosingClass().getType(); -// BcelShadow s = -// new BcelShadow( -// world, -// ConstructorExecution, -// interfaceConstructorSignature, -// constructor, -// null); -// s.fallsThrough = true; -// ShadowRange r = new ShadowRange(body); -// r.associateWithShadow(s); -// // ??? this may or may not work -// InstructionHandle start = Range.genStart(body, next); -// //InstructionHandle end = Range.genEnd(body, body.append(start, fact.NOP)); -// InstructionHandle end = Range.genStart(body, next); -// //body.append(start, fact.NOP); -// -// r.associateWithTargets(start, end); -// return s; -// } - - - /** Create an initialization join point associated with a constructor, but not - * with any body of code yet. If this is actually matched, it's range will be set - * when we inline self constructors. - * - * @param constructor The constructor starting this initialization. - */ - public static BcelShadow makeUnfinishedInitialization( - BcelWorld world, - LazyMethodGen constructor) - { - BcelShadow ret = new BcelShadow( - world, - Initialization, - world.makeJoinPointSignatureFromMethod(constructor,Member.CONSTRUCTOR), - constructor, - null); + + r.associateWithTargets(Range.genStart(body, nop), Range.genEnd(body, nop)); + } + + // public static BcelShadow makeIfaceConstructorExecution( + // BcelWorld world, + // LazyMethodGen constructor, + // InstructionHandle next, + // Member interfaceConstructorSignature) + // { + // // final InstructionFactory fact = constructor.getEnclosingClass().getFactory(); + // InstructionList body = constructor.getBody(); + // // UnresolvedType inType = constructor.getEnclosingClass().getType(); + // BcelShadow s = + // new BcelShadow( + // world, + // ConstructorExecution, + // interfaceConstructorSignature, + // constructor, + // null); + // s.fallsThrough = true; + // ShadowRange r = new ShadowRange(body); + // r.associateWithShadow(s); + // // ??? this may or may not work + // InstructionHandle start = Range.genStart(body, next); + // //InstructionHandle end = Range.genEnd(body, body.append(start, fact.NOP)); + // InstructionHandle end = Range.genStart(body, next); + // //body.append(start, fact.NOP); + // + // r.associateWithTargets(start, end); + // return s; + // } + + /** + * Create an initialization join point associated with a constructor, but not with any body of code yet. If this is actually + * matched, it's range will be set when we inline self constructors. + * + * @param constructor The constructor starting this initialization. + */ + public static BcelShadow makeUnfinishedInitialization(BcelWorld world, LazyMethodGen constructor) { + BcelShadow ret = new BcelShadow(world, Initialization, world.makeJoinPointSignatureFromMethod(constructor, + Member.CONSTRUCTOR), constructor, null); if (constructor.getEffectiveSignature() != null) { ret.setMatchingSignature(constructor.getEffectiveSignature().getEffectiveSignature()); } return ret; } - public static BcelShadow makeUnfinishedPreinitialization( - BcelWorld world, - LazyMethodGen constructor) - { - BcelShadow ret = new BcelShadow( - world, - PreInitialization, - world.makeJoinPointSignatureFromMethod(constructor,Member.CONSTRUCTOR), - constructor, - null); + public static BcelShadow makeUnfinishedPreinitialization(BcelWorld world, LazyMethodGen constructor) { + BcelShadow ret = new BcelShadow(world, PreInitialization, world.makeJoinPointSignatureFromMethod(constructor, + Member.CONSTRUCTOR), constructor, null); if (constructor.getEffectiveSignature() != null) { ret.setMatchingSignature(constructor.getEffectiveSignature().getEffectiveSignature()); } return ret; } - - - public static BcelShadow makeMethodExecution( - BcelWorld world, - LazyMethodGen enclosingMethod, - boolean lazyInit) - { - if (!lazyInit) return makeMethodExecution(world, enclosingMethod); - - BcelShadow s = - new BcelShadow( - world, - MethodExecution, - enclosingMethod.getMemberView(), - enclosingMethod, - null); - + + public static BcelShadow makeMethodExecution(BcelWorld world, LazyMethodGen enclosingMethod, boolean lazyInit) { + if (!lazyInit) + return makeMethodExecution(world, enclosingMethod); + + BcelShadow s = new BcelShadow(world, MethodExecution, enclosingMethod.getMemberView(), enclosingMethod, null); + return s; } - - + public void init() { - if (range != null) return; - + if (range != null) + return; + final InstructionList body = enclosingMethod.getBody(); ShadowRange r = new ShadowRange(body); r.associateWithShadow(this); - r.associateWithTargets( - Range.genStart(body), - Range.genEnd(body)); - } - - public static BcelShadow makeMethodExecution( - BcelWorld world, - LazyMethodGen enclosingMethod) - { - return makeShadowForMethod(world, enclosingMethod, MethodExecution, - enclosingMethod.getMemberView()); //world.makeMethodSignature(enclosingMethod)); - } - - - public static BcelShadow makeShadowForMethod(BcelWorld world, - LazyMethodGen enclosingMethod, Shadow.Kind kind, Member sig) - { - final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = - new BcelShadow( - world, - kind, - sig, - enclosingMethod, - null); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(// OPTIMIZE this occurs lots of times for all jp kinds... - Range.genStart(body), - Range.genEnd(body)); - return s; - } - - - - public static BcelShadow makeAdviceExecution( - BcelWorld world, - LazyMethodGen enclosingMethod) - { + r.associateWithTargets(Range.genStart(body), Range.genEnd(body)); + } + + public static BcelShadow makeMethodExecution(BcelWorld world, LazyMethodGen enclosingMethod) { + return makeShadowForMethod(world, enclosingMethod, MethodExecution, enclosingMethod.getMemberView()); // world. + // makeMethodSignature + // ( + // enclosingMethod)) + // ; + } + + public static BcelShadow makeShadowForMethod(BcelWorld world, LazyMethodGen enclosingMethod, Shadow.Kind kind, Member sig) { final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = - new BcelShadow( - world, - AdviceExecution, - world.makeJoinPointSignatureFromMethod(enclosingMethod, Member.ADVICE), - enclosingMethod, - null); + BcelShadow s = new BcelShadow(world, kind, sig, enclosingMethod, null); ShadowRange r = new ShadowRange(body); r.associateWithShadow(s); - r.associateWithTargets(Range.genStart(body), Range.genEnd(body)); + r.associateWithTargets(// OPTIMIZE this occurs lots of times for all jp kinds... + Range.genStart(body), Range.genEnd(body)); return s; } + public static BcelShadow makeAdviceExecution(BcelWorld world, LazyMethodGen enclosingMethod) { + final InstructionList body = enclosingMethod.getBody(); + BcelShadow s = new BcelShadow(world, AdviceExecution, world + .makeJoinPointSignatureFromMethod(enclosingMethod, Member.ADVICE), enclosingMethod, null); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets(Range.genStart(body), Range.genEnd(body)); + return s; + } - // constructor call shadows are <em>initially</em> just around the - // call to the constructor. If ANY advice gets put on it, we move - // the NEW instruction inside the join point, which involves putting + // constructor call shadows are <em>initially</em> just around the + // call to the constructor. If ANY advice gets put on it, we move + // the NEW instruction inside the join point, which involves putting // all the arguments in temps. - public static BcelShadow makeConstructorCall( - BcelWorld world, - LazyMethodGen enclosingMethod, - InstructionHandle callHandle, - BcelShadow enclosingShadow) - { - final InstructionList body = enclosingMethod.getBody(); - - Member sig = world.makeJoinPointSignatureForMethodInvocation( - enclosingMethod.getEnclosingClass(), - (InvokeInstruction) callHandle.getInstruction()); - - BcelShadow s = - new BcelShadow( - world, - ConstructorCall, - sig, - enclosingMethod, - enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets( - Range.genStart(body, callHandle), - Range.genEnd(body, callHandle)); - retargetAllBranches(callHandle, r.getStart()); - return s; - } - - public static BcelShadow makeArrayConstructorCall(BcelWorld world,LazyMethodGen enclosingMethod,InstructionHandle arrayInstruction,BcelShadow enclosingShadow) { - final InstructionList body = enclosingMethod.getBody(); - Member sig = world.makeJoinPointSignatureForArrayConstruction(enclosingMethod.getEnclosingClass(),arrayInstruction); - BcelShadow s = - new BcelShadow( - world, - ConstructorCall, - sig, - enclosingMethod, - enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets( - Range.genStart(body, arrayInstruction), - Range.genEnd(body, arrayInstruction)); - retargetAllBranches(arrayInstruction, r.getStart()); - return s; - } - - public static BcelShadow makeMonitorEnter(BcelWorld world,LazyMethodGen enclosingMethod,InstructionHandle monitorInstruction,BcelShadow enclosingShadow) { - final InstructionList body = enclosingMethod.getBody(); - Member sig = world.makeJoinPointSignatureForMonitorEnter(enclosingMethod.getEnclosingClass(),monitorInstruction); - BcelShadow s = new BcelShadow(world,SynchronizationLock,sig,enclosingMethod,enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets( - Range.genStart(body, monitorInstruction), - Range.genEnd(body, monitorInstruction)); - retargetAllBranches(monitorInstruction, r.getStart()); - return s; - } - - public static BcelShadow makeMonitorExit(BcelWorld world,LazyMethodGen enclosingMethod,InstructionHandle monitorInstruction,BcelShadow enclosingShadow) { - final InstructionList body = enclosingMethod.getBody(); - Member sig = world.makeJoinPointSignatureForMonitorExit(enclosingMethod.getEnclosingClass(),monitorInstruction); - BcelShadow s = new BcelShadow(world,SynchronizationUnlock,sig,enclosingMethod,enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets( - Range.genStart(body, monitorInstruction), - Range.genEnd(body, monitorInstruction)); - retargetAllBranches(monitorInstruction, r.getStart()); - return s; - } - - // see pr77166 -// public static BcelShadow makeArrayLoadCall( -// BcelWorld world, -// LazyMethodGen enclosingMethod, -// InstructionHandle arrayInstruction, -// BcelShadow enclosingShadow) -// { -// final InstructionList body = enclosingMethod.getBody(); -// Member sig = world.makeJoinPointSignatureForArrayLoad(enclosingMethod.getEnclosingClass(),arrayInstruction); -// BcelShadow s = -// new BcelShadow( -// world, -// MethodCall, -// sig, -// enclosingMethod, -// enclosingShadow); -// ShadowRange r = new ShadowRange(body); -// r.associateWithShadow(s); -// r.associateWithTargets( -// Range.genStart(body, arrayInstruction), -// Range.genEnd(body, arrayInstruction)); -// retargetAllBranches(arrayInstruction, r.getStart()); -// return s; -// } - - public static BcelShadow makeMethodCall( - BcelWorld world, - LazyMethodGen enclosingMethod, - InstructionHandle callHandle, - BcelShadow enclosingShadow) - { - final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = - new BcelShadow( - world, - MethodCall, - world.makeJoinPointSignatureForMethodInvocation( - enclosingMethod.getEnclosingClass(), - (InvokeInstruction) callHandle.getInstruction()), - enclosingMethod, - enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets( - Range.genStart(body, callHandle), - Range.genEnd(body, callHandle)); - retargetAllBranches(callHandle, r.getStart()); - return s; - } - - - public static BcelShadow makeShadowForMethodCall( - BcelWorld world, - LazyMethodGen enclosingMethod, - InstructionHandle callHandle, - BcelShadow enclosingShadow, - Kind kind, - ResolvedMember sig) - { - final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = - new BcelShadow( - world, - kind, - sig, - enclosingMethod, - enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets( - Range.genStart(body, callHandle), - Range.genEnd(body, callHandle)); - retargetAllBranches(callHandle, r.getStart()); - return s; - } - - - public static BcelShadow makeFieldGet( - BcelWorld world, - ResolvedMember field, - LazyMethodGen enclosingMethod, - InstructionHandle getHandle, - BcelShadow enclosingShadow) - { - final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = - new BcelShadow( - world, - FieldGet, - field, -// BcelWorld.makeFieldSignature( -// enclosingMethod.getEnclosingClass(), -// (FieldInstruction) getHandle.getInstruction()), - enclosingMethod, - enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets( - Range.genStart(body, getHandle), - Range.genEnd(body, getHandle)); - retargetAllBranches(getHandle, r.getStart()); - return s; - } - - public static BcelShadow makeFieldSet( - BcelWorld world, - ResolvedMember field, - LazyMethodGen enclosingMethod, - InstructionHandle setHandle, - BcelShadow enclosingShadow) - { - final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = - new BcelShadow( - world, - FieldSet, - field, -// BcelWorld.makeFieldJoinPointSignature( -// enclosingMethod.getEnclosingClass(), -// (FieldInstruction) setHandle.getInstruction()), - enclosingMethod, - enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets( - Range.genStart(body, setHandle), - Range.genEnd(body, setHandle)); - retargetAllBranches(setHandle, r.getStart()); - return s; - } + public static BcelShadow makeConstructorCall(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle callHandle, + BcelShadow enclosingShadow) { + final InstructionList body = enclosingMethod.getBody(); + + Member sig = world.makeJoinPointSignatureForMethodInvocation(enclosingMethod.getEnclosingClass(), + (InvokeInstruction) callHandle.getInstruction()); + + BcelShadow s = new BcelShadow(world, ConstructorCall, sig, enclosingMethod, enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets(Range.genStart(body, callHandle), Range.genEnd(body, callHandle)); + retargetAllBranches(callHandle, r.getStart()); + return s; + } + + public static BcelShadow makeArrayConstructorCall(BcelWorld world, LazyMethodGen enclosingMethod, + InstructionHandle arrayInstruction, BcelShadow enclosingShadow) { + final InstructionList body = enclosingMethod.getBody(); + Member sig = world.makeJoinPointSignatureForArrayConstruction(enclosingMethod.getEnclosingClass(), arrayInstruction); + BcelShadow s = new BcelShadow(world, ConstructorCall, sig, enclosingMethod, enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets(Range.genStart(body, arrayInstruction), Range.genEnd(body, arrayInstruction)); + retargetAllBranches(arrayInstruction, r.getStart()); + return s; + } + + public static BcelShadow makeMonitorEnter(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle monitorInstruction, + BcelShadow enclosingShadow) { + final InstructionList body = enclosingMethod.getBody(); + Member sig = world.makeJoinPointSignatureForMonitorEnter(enclosingMethod.getEnclosingClass(), monitorInstruction); + BcelShadow s = new BcelShadow(world, SynchronizationLock, sig, enclosingMethod, enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets(Range.genStart(body, monitorInstruction), Range.genEnd(body, monitorInstruction)); + retargetAllBranches(monitorInstruction, r.getStart()); + return s; + } + + public static BcelShadow makeMonitorExit(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle monitorInstruction, + BcelShadow enclosingShadow) { + final InstructionList body = enclosingMethod.getBody(); + Member sig = world.makeJoinPointSignatureForMonitorExit(enclosingMethod.getEnclosingClass(), monitorInstruction); + BcelShadow s = new BcelShadow(world, SynchronizationUnlock, sig, enclosingMethod, enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets(Range.genStart(body, monitorInstruction), Range.genEnd(body, monitorInstruction)); + retargetAllBranches(monitorInstruction, r.getStart()); + return s; + } + + // see pr77166 + // public static BcelShadow makeArrayLoadCall( + // BcelWorld world, + // LazyMethodGen enclosingMethod, + // InstructionHandle arrayInstruction, + // BcelShadow enclosingShadow) + // { + // final InstructionList body = enclosingMethod.getBody(); + // Member sig = world.makeJoinPointSignatureForArrayLoad(enclosingMethod.getEnclosingClass(),arrayInstruction); + // BcelShadow s = + // new BcelShadow( + // world, + // MethodCall, + // sig, + // enclosingMethod, + // enclosingShadow); + // ShadowRange r = new ShadowRange(body); + // r.associateWithShadow(s); + // r.associateWithTargets( + // Range.genStart(body, arrayInstruction), + // Range.genEnd(body, arrayInstruction)); + // retargetAllBranches(arrayInstruction, r.getStart()); + // return s; + // } + + public static BcelShadow makeMethodCall(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle callHandle, + BcelShadow enclosingShadow) { + final InstructionList body = enclosingMethod.getBody(); + BcelShadow s = new BcelShadow(world, MethodCall, world.makeJoinPointSignatureForMethodInvocation(enclosingMethod + .getEnclosingClass(), (InvokeInstruction) callHandle.getInstruction()), enclosingMethod, enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets(Range.genStart(body, callHandle), Range.genEnd(body, callHandle)); + retargetAllBranches(callHandle, r.getStart()); + return s; + } + + public static BcelShadow makeShadowForMethodCall(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle callHandle, + BcelShadow enclosingShadow, Kind kind, ResolvedMember sig) { + final InstructionList body = enclosingMethod.getBody(); + BcelShadow s = new BcelShadow(world, kind, sig, enclosingMethod, enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets(Range.genStart(body, callHandle), Range.genEnd(body, callHandle)); + retargetAllBranches(callHandle, r.getStart()); + return s; + } + + public static BcelShadow makeFieldGet(BcelWorld world, ResolvedMember field, LazyMethodGen enclosingMethod, + InstructionHandle getHandle, BcelShadow enclosingShadow) { + final InstructionList body = enclosingMethod.getBody(); + BcelShadow s = new BcelShadow(world, FieldGet, field, + // BcelWorld.makeFieldSignature( + // enclosingMethod.getEnclosingClass(), + // (FieldInstruction) getHandle.getInstruction()), + enclosingMethod, enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets(Range.genStart(body, getHandle), Range.genEnd(body, getHandle)); + retargetAllBranches(getHandle, r.getStart()); + return s; + } + + public static BcelShadow makeFieldSet(BcelWorld world, ResolvedMember field, LazyMethodGen enclosingMethod, + InstructionHandle setHandle, BcelShadow enclosingShadow) { + final InstructionList body = enclosingMethod.getBody(); + BcelShadow s = new BcelShadow(world, FieldSet, field, + // BcelWorld.makeFieldJoinPointSignature( + // enclosingMethod.getEnclosingClass(), + // (FieldInstruction) setHandle.getInstruction()), + enclosingMethod, enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets(Range.genStart(body, setHandle), Range.genEnd(body, setHandle)); + retargetAllBranches(setHandle, r.getStart()); + return s; + } public static void retargetAllBranches(InstructionHandle from, InstructionHandle to) { InstructionTargeter[] sources = from.getTargetersArray(); @@ -998,163 +814,173 @@ public class BcelShadow extends Shadow { } } -// // ---- type access methods -// private ObjectType getTargetBcelType() { -// return (ObjectType) BcelWorld.makeBcelType(getTargetType()); -// } -// private Type getArgBcelType(int arg) { -// return BcelWorld.makeBcelType(getArgType(arg)); -// } + // // ---- type access methods + // private ObjectType getTargetBcelType() { + // return (ObjectType) BcelWorld.makeBcelType(getTargetType()); + // } + // private Type getArgBcelType(int arg) { + // return BcelWorld.makeBcelType(getArgType(arg)); + // } - // ---- kinding + // ---- kinding /** - * If the end of my range has no real instructions following then - * my context needs a return at the end. + * If the end of my range has no real instructions following then my context needs a return at the end. */ - public boolean terminatesWithReturn() { - return getRange().getRealNext() == null; - } - - /** + public boolean terminatesWithReturn() { + return getRange().getRealNext() == null; + } + + /** * Is arg0 occupied with the value of this */ - public boolean arg0HoldsThis() { - if (getKind().isEnclosingKind()) { - return !getSignature().isStatic(); - } else if (enclosingShadow == null) { - //XXX this is mostly right - // this doesn't do the right thing for calls in the pre part of introduced constructors. - return !enclosingMethod.isStatic(); - } else { - return ((BcelShadow)enclosingShadow).arg0HoldsThis(); - } - } - - // ---- argument getting methods - - private BcelVar thisVar = null; - private BcelVar targetVar = null; - private BcelVar[] argVars = null; - private Map/*<UnresolvedType,BcelVar>*/ kindedAnnotationVars = null; - private Map/*<UnresolvedType,BcelVar>*/ thisAnnotationVars = null; - private Map/*<UnresolvedType,BcelVar>*/ targetAnnotationVars = null; - private Map/*<UnresolvedType,BcelVar>*/[] argAnnotationVars = null; - private Map/*<UnresolvedType,BcelVar>*/ withinAnnotationVars = null; - private Map/*<UnresolvedType,BcelVar>*/ withincodeAnnotationVars = null; - - public Var getThisVar() { - if (!hasThis()) { - throw new IllegalStateException("no this"); - } - initializeThisVar(); - return thisVar; - } + public boolean arg0HoldsThis() { + if (getKind().isEnclosingKind()) { + return !getSignature().isStatic(); + } else if (enclosingShadow == null) { + // XXX this is mostly right + // this doesn't do the right thing for calls in the pre part of introduced constructors. + return !enclosingMethod.isStatic(); + } else { + return ((BcelShadow) enclosingShadow).arg0HoldsThis(); + } + } + + // ---- argument getting methods + + private BcelVar thisVar = null; + private BcelVar targetVar = null; + private BcelVar[] argVars = null; + private Map/* <UnresolvedType,BcelVar> */kindedAnnotationVars = null; + private Map/* <UnresolvedType,BcelVar> */thisAnnotationVars = null; + private Map/* <UnresolvedType,BcelVar> */targetAnnotationVars = null; + private Map/* <UnresolvedType,BcelVar> */[] argAnnotationVars = null; + private Map/* <UnresolvedType,BcelVar> */withinAnnotationVars = null; + private Map/* <UnresolvedType,BcelVar> */withincodeAnnotationVars = null; + + public Var getThisVar() { + if (!hasThis()) { + throw new IllegalStateException("no this"); + } + initializeThisVar(); + return thisVar; + } + public Var getThisAnnotationVar(UnresolvedType forAnnotationType) { - if (!hasThis()) { - throw new IllegalStateException("no this"); - } - initializeThisAnnotationVars(); // FIXME asc Why bother with this if we always return one? - // Even if we can't find one, we have to return one as we might have this annotation at runtime - Var v = (Var) thisAnnotationVars.get(forAnnotationType); - if (v==null) - v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world),(BcelVar)getThisVar()); - return v; - } - public Var getTargetVar() { - if (!hasTarget()) { - throw new IllegalStateException("no target"); - } - initializeTargetVar(); - return targetVar; - } - public Var getTargetAnnotationVar(UnresolvedType forAnnotationType) { - if (!hasTarget()) { - throw new IllegalStateException("no target"); - } - initializeTargetAnnotationVars(); // FIXME asc why bother with this if we always return one? - Var v =(Var) targetAnnotationVars.get(forAnnotationType); - // Even if we can't find one, we have to return one as we might have this annotation at runtime - if (v==null) - v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world),(BcelVar)getTargetVar()); + if (!hasThis()) { + throw new IllegalStateException("no this"); + } + initializeThisAnnotationVars(); // FIXME asc Why bother with this if we always return one? + // Even if we can't find one, we have to return one as we might have this annotation at runtime + Var v = (Var) thisAnnotationVars.get(forAnnotationType); + if (v == null) + v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world), (BcelVar) getThisVar()); return v; - } - public Var getArgVar(int i) { - initializeArgVars(); - return argVars[i]; - } - public Var getArgAnnotationVar(int i,UnresolvedType forAnnotationType) { + } + + public Var getTargetVar() { + if (!hasTarget()) { + throw new IllegalStateException("no target"); + } + initializeTargetVar(); + return targetVar; + } + + public Var getTargetAnnotationVar(UnresolvedType forAnnotationType) { + if (!hasTarget()) { + throw new IllegalStateException("no target"); + } + initializeTargetAnnotationVars(); // FIXME asc why bother with this if we always return one? + Var v = (Var) targetAnnotationVars.get(forAnnotationType); + // Even if we can't find one, we have to return one as we might have this annotation at runtime + if (v == null) + v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world), (BcelVar) getTargetVar()); + return v; + } + + public Var getArgVar(int i) { + initializeArgVars(); + return argVars[i]; + } + + public Var getArgAnnotationVar(int i, UnresolvedType forAnnotationType) { initializeArgAnnotationVars(); - - Var v= (Var) argAnnotationVars[i].get(forAnnotationType); - if (v==null) - v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world),(BcelVar)getArgVar(i)); + + Var v = (Var) argAnnotationVars[i].get(forAnnotationType); + if (v == null) + v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world), (BcelVar) getArgVar(i)); return v; - } - public Var getKindedAnnotationVar(UnresolvedType forAnnotationType) { - initializeKindedAnnotationVars(); - return (Var) kindedAnnotationVars.get(forAnnotationType); - } + } + + public Var getKindedAnnotationVar(UnresolvedType forAnnotationType) { + initializeKindedAnnotationVars(); + return (Var) kindedAnnotationVars.get(forAnnotationType); + } + public Var getWithinAnnotationVar(UnresolvedType forAnnotationType) { initializeWithinAnnotationVars(); return (Var) withinAnnotationVars.get(forAnnotationType); - } + } + public Var getWithinCodeAnnotationVar(UnresolvedType forAnnotationType) { initializeWithinCodeAnnotationVars(); return (Var) withincodeAnnotationVars.get(forAnnotationType); } - - // reflective thisJoinPoint support - private BcelVar thisJoinPointVar = null; - private boolean isThisJoinPointLazy; - private int lazyTjpConsumers = 0; - private BcelVar thisJoinPointStaticPartVar = null; - // private BcelVar thisEnclosingJoinPointStaticPartVar = null; - + + // reflective thisJoinPoint support + private BcelVar thisJoinPointVar = null; + private boolean isThisJoinPointLazy; + private int lazyTjpConsumers = 0; + private BcelVar thisJoinPointStaticPartVar = null; + + // private BcelVar thisEnclosingJoinPointStaticPartVar = null; + public final Var getThisJoinPointStaticPartVar() { return getThisJoinPointStaticPartBcelVar(); } + public final Var getThisEnclosingJoinPointStaticPartVar() { return getThisEnclosingJoinPointStaticPartBcelVar(); } - - public void requireThisJoinPoint(boolean hasGuardTest, boolean isAround) { - if (!isAround){ + + public void requireThisJoinPoint(boolean hasGuardTest, boolean isAround) { + if (!isAround) { if (!hasGuardTest) { isThisJoinPointLazy = false; } else { lazyTjpConsumers++; } } -// if (!hasGuardTest) { -// isThisJoinPointLazy = false; -// } else { -// lazyTjpConsumers++; -// } - if (thisJoinPointVar == null) { + // if (!hasGuardTest) { + // isThisJoinPointLazy = false; + // } else { + // lazyTjpConsumers++; + // } + if (thisJoinPointVar == null) { thisJoinPointVar = genTempVar(UnresolvedType.forName("org.aspectj.lang.JoinPoint")); - } - } - - - public Var getThisJoinPointVar() { - requireThisJoinPoint(false,false); - return thisJoinPointVar; - } - - void initializeThisJoinPoint() { - if (thisJoinPointVar == null) return; - - if (isThisJoinPointLazy) { - isThisJoinPointLazy = checkLazyTjp(); - } - + } + } + + public Var getThisJoinPointVar() { + requireThisJoinPoint(false, false); + return thisJoinPointVar; + } + + void initializeThisJoinPoint() { + if (thisJoinPointVar == null) + return; + + if (isThisJoinPointLazy) { + isThisJoinPointLazy = checkLazyTjp(); + } + if (isThisJoinPointLazy) { appliedLazyTjpOptimization = true; createThisJoinPoint(); // make sure any state needed is initialized, but throw the instructions out - - if (lazyTjpConsumers == 1) return; // special case only one lazyTjpUser - + + if (lazyTjpConsumers == 1) + return; // special case only one lazyTjpUser + InstructionFactory fact = getFactory(); InstructionList il = new InstructionList(); il.append(InstructionConstants.ACONST_NULL); @@ -1167,682 +993,657 @@ public class BcelShadow extends Shadow { il.append(thisJoinPointVar.createStore(fact)); range.insert(il, Range.OutsideBefore); } - } - - private boolean checkLazyTjp() { - // check for around advice - for (Iterator i = mungers.iterator(); i.hasNext();) { + } + + private boolean checkLazyTjp() { + // check for around advice + for (Iterator i = mungers.iterator(); i.hasNext();) { ShadowMunger munger = (ShadowMunger) i.next(); if (munger instanceof Advice) { - if ( ((Advice)munger).getKind() == AdviceKind.Around) { - if (munger.getSourceLocation()!=null) { // do we know enough to bother reporting? + if (((Advice) munger).getKind() == AdviceKind.Around) { + if (munger.getSourceLocation() != null) { // do we know enough to bother reporting? if (world.getLint().canNotImplementLazyTjp.isEnabled()) { - world.getLint().canNotImplementLazyTjp.signal( - new String[] {toString()}, - getSourceLocation(), - new ISourceLocation[] { munger.getSourceLocation() } - ); + world.getLint().canNotImplementLazyTjp.signal(new String[] { toString() }, getSourceLocation(), + new ISourceLocation[] { munger.getSourceLocation() }); } } return false; } } } - - return true; - } - - InstructionList loadThisJoinPoint() { + + return true; + } + + InstructionList loadThisJoinPoint() { InstructionFactory fact = getFactory(); InstructionList il = new InstructionList(); - if (isThisJoinPointLazy) { - // If we're lazy, build the join point right here. - il.append(createThisJoinPoint()); - - // Does someone else need it? If so, store it for later retrieval - if (lazyTjpConsumers > 1) { + if (isThisJoinPointLazy) { + // If we're lazy, build the join point right here. + il.append(createThisJoinPoint()); + + // Does someone else need it? If so, store it for later retrieval + if (lazyTjpConsumers > 1) { il.append(thisJoinPointVar.createStore(fact)); - + InstructionHandle end = il.append(thisJoinPointVar.createLoad(fact)); - + il.insert(InstructionFactory.createBranchInstruction(Constants.IFNONNULL, end)); il.insert(thisJoinPointVar.createLoad(fact)); - } - } else { - // If not lazy, its already been built and stored, just retrieve it + } + } else { + // If not lazy, its already been built and stored, just retrieve it thisJoinPointVar.appendLoad(il, fact); - } - + } + return il; - } + } InstructionList createThisJoinPoint() { InstructionFactory fact = getFactory(); InstructionList il = new InstructionList(); - + BcelVar staticPart = getThisJoinPointStaticPartBcelVar(); staticPart.appendLoad(il, fact); if (hasThis()) { - ((BcelVar)getThisVar()).appendLoad(il, fact); + ((BcelVar) getThisVar()).appendLoad(il, fact); } else { il.append(InstructionConstants.ACONST_NULL); } if (hasTarget()) { - ((BcelVar)getTargetVar()).appendLoad(il, fact); + ((BcelVar) getTargetVar()).appendLoad(il, fact); } else { il.append(InstructionConstants.ACONST_NULL); } - - switch(getArgCount()) { - case 0: - il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", - "makeJP", LazyClassGen.tjpType, - new Type[] { LazyClassGen.staticTjpType, - Type.OBJECT, Type.OBJECT}, - Constants.INVOKESTATIC)); - break; - case 1: - ((BcelVar)getArgVar(0)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT)); - il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", - "makeJP", LazyClassGen.tjpType, - new Type[] { LazyClassGen.staticTjpType, - Type.OBJECT, Type.OBJECT, Type.OBJECT}, - Constants.INVOKESTATIC)); - break; - case 2: - ((BcelVar)getArgVar(0)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT)); - ((BcelVar)getArgVar(1)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT)); - il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", - "makeJP", LazyClassGen.tjpType, - new Type[] { LazyClassGen.staticTjpType, - Type.OBJECT, Type.OBJECT, Type.OBJECT, Type.OBJECT}, - Constants.INVOKESTATIC)); - break; - default: - il.append(makeArgsObjectArray()); - il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", - "makeJP", LazyClassGen.tjpType, - new Type[] { LazyClassGen.staticTjpType, - Type.OBJECT, Type.OBJECT, new ArrayType(Type.OBJECT, 1)}, - Constants.INVOKESTATIC)); - break; - } - + + switch (getArgCount()) { + case 0: + il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", "makeJP", LazyClassGen.tjpType, new Type[] { + LazyClassGen.staticTjpType, Type.OBJECT, Type.OBJECT }, Constants.INVOKESTATIC)); + break; + case 1: + ((BcelVar) getArgVar(0)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT)); + il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", "makeJP", LazyClassGen.tjpType, new Type[] { + LazyClassGen.staticTjpType, Type.OBJECT, Type.OBJECT, Type.OBJECT }, Constants.INVOKESTATIC)); + break; + case 2: + ((BcelVar) getArgVar(0)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT)); + ((BcelVar) getArgVar(1)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT)); + il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", "makeJP", LazyClassGen.tjpType, new Type[] { + LazyClassGen.staticTjpType, Type.OBJECT, Type.OBJECT, Type.OBJECT, Type.OBJECT }, Constants.INVOKESTATIC)); + break; + default: + il.append(makeArgsObjectArray()); + il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", "makeJP", LazyClassGen.tjpType, new Type[] { + LazyClassGen.staticTjpType, Type.OBJECT, Type.OBJECT, new ArrayType(Type.OBJECT, 1) }, Constants.INVOKESTATIC)); + break; + } + return il; } - /** - * Get the Var for the jpStaticPart - * @return - */ - public BcelVar getThisJoinPointStaticPartBcelVar() { - return getThisJoinPointStaticPartBcelVar(false); - } - - /** - * Get the Var for the xxxxJpStaticPart, xxx = this or enclosing - * @param isEnclosingJp true to have the enclosingJpStaticPart - * @return - */ - public BcelVar getThisJoinPointStaticPartBcelVar(final boolean isEnclosingJp) { - if (thisJoinPointStaticPartVar == null) { - Field field = getEnclosingClass().getTjpField(this, isEnclosingJp); - ResolvedType sjpType = null; - if (world.isTargettingAspectJRuntime12()) { // TAG:SUPPORTING12: We didn't have different jpsp types in 1.2 - sjpType = world.getCoreType(UnresolvedType.JOINPOINT_STATICPART); - } else { - sjpType = isEnclosingJp? - world.getCoreType(UnresolvedType.JOINPOINT_ENCLOSINGSTATICPART): - world.getCoreType(UnresolvedType.JOINPOINT_STATICPART); - } - thisJoinPointStaticPartVar = new BcelFieldRef( - sjpType, - getEnclosingClass().getClassName(), - field.getName()); -// getEnclosingClass().warnOnAddedStaticInitializer(this,munger.getSourceLocation()); - } - return thisJoinPointStaticPartVar; - } - - /** - * Get the Var for the enclosingJpStaticPart - * @return - */ - public BcelVar getThisEnclosingJoinPointStaticPartBcelVar() { - if (enclosingShadow == null) { - // the enclosing of an execution is itself - return getThisJoinPointStaticPartBcelVar(true); - } else { - return ((BcelShadow)enclosingShadow).getThisJoinPointStaticPartBcelVar(true); - } - } - - //??? need to better understand all the enclosing variants - public Member getEnclosingCodeSignature() { - if (getKind().isEnclosingKind()) { - return getSignature(); - } else if (getKind() == Shadow.PreInitialization) { - // PreInit doesn't enclose code but its signature - // is correctly the signature of the ctor. - return getSignature(); - } else if (enclosingShadow == null) { - return getEnclosingMethod().getMemberView(); - } else { - return enclosingShadow.getSignature(); - } - } - - - private InstructionList makeArgsObjectArray() { - InstructionFactory fact = getFactory(); - BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY); - final InstructionList il = new InstructionList(); - int alen = getArgCount() ; - il.append(Utility.createConstant(fact, alen)); - il.append(fact.createNewArray(Type.OBJECT, (short)1)); - arrayVar.appendStore(il, fact); - - int stateIndex = 0; - for (int i = 0, len = getArgCount(); i<len; i++) { - arrayVar.appendConvertableArrayStore(il, fact, stateIndex, (BcelVar)getArgVar(i)); - stateIndex++; - } - arrayVar.appendLoad(il, fact); - return il; - } - - // ---- initializing var tables - - /* initializing this is doesn't do anything, because this - * is protected from side-effects, so we don't need to copy its location - */ - - private void initializeThisVar() { - if (thisVar != null) return; - thisVar = new BcelVar(getThisType().resolve(world), 0); - thisVar.setPositionInAroundState(0); - } - public void initializeTargetVar() { - InstructionFactory fact = getFactory(); - if (targetVar != null) return; - if (getKind().isTargetSameAsThis()) { - if (hasThis()) initializeThisVar(); - targetVar = thisVar; - } else { - initializeArgVars(); // gotta pop off the args before we find the target - UnresolvedType type = getTargetType(); - type = ensureTargetTypeIsCorrect(type); - targetVar = genTempVar(type, "ajc$target"); - range.insert(targetVar.createStore(fact), Range.OutsideBefore); - targetVar.setPositionInAroundState(hasThis() ? 1 : 0); - } - } - - /* PR 72528 - * This method double checks the target type under certain conditions. The Java 1.4 - * compilers seem to take calls to clone methods on array types and create bytecode that - * looks like clone is being called on Object. If we advise a clone call with around - * advice we extract the call into a helper method which we can then refer to. Because the - * type in the bytecode for the call to clone is Object we create a helper method with - * an Object parameter - this is not correct as we have lost the fact that the actual - * type is an array type. If we don't do the check below we will create code that fails - * java verification. This method checks for the peculiar set of conditions and if they - * are true, it has a sneak peek at the code before the call to see what is on the stack. - */ - public UnresolvedType ensureTargetTypeIsCorrect(UnresolvedType tx) { - - Member msig = getSignature(); - if (msig.getArity()==0 && - getKind() == MethodCall && - msig.getName().charAt(0) == 'c' && - tx.equals(ResolvedType.OBJECT) && - msig.getReturnType().equals(ResolvedType.OBJECT) && - msig.getName().equals("clone")) { - - // Lets go back through the code from the start of the shadow - InstructionHandle searchPtr = range.getStart().getPrev(); - while (Range.isRangeHandle(searchPtr) || - searchPtr.getInstruction().isStoreInstruction()) { // ignore this instruction - it doesnt give us the info we want - searchPtr = searchPtr.getPrev(); - } - - // A load instruction may tell us the real type of what the clone() call is on - if (searchPtr.getInstruction().isLoadInstruction()) { - LocalVariableTag lvt = LazyMethodGen.getLocalVariableTag(searchPtr,searchPtr.getInstruction().getIndex()); - if (lvt!=null) return UnresolvedType.forSignature(lvt.getType()); - } - // A field access instruction may tell us the real type of what the clone() call is on - if (searchPtr.getInstruction() instanceof FieldInstruction) { - FieldInstruction si = (FieldInstruction)searchPtr.getInstruction(); - Type t = si.getFieldType(getEnclosingClass().getConstantPool()); - return BcelWorld.fromBcel(t); - } - // A new array instruction obviously tells us it is an array type ! - if (searchPtr.getInstruction().opcode==Constants.ANEWARRAY) { - //ANEWARRAY ana = (ANEWARRAY)searchPoint.getInstruction(); -// Type t = ana.getType(getEnclosingClass().getConstantPool()); - // Just use a standard java.lang.object array - that will work fine - return BcelWorld.fromBcel(new ArrayType(Type.OBJECT,1)); - } - // A multi new array instruction obviously tells us it is an array type ! - if (searchPtr.getInstruction() instanceof MULTIANEWARRAY) { - MULTIANEWARRAY ana = (MULTIANEWARRAY)searchPtr.getInstruction(); - // Type t = ana.getType(getEnclosingClass().getConstantPool()); - // t = new ArrayType(t,ana.getDimensions()); - // Just use a standard java.lang.object array - that will work fine - return BcelWorld.fromBcel(new ArrayType(Type.OBJECT,ana.getDimensions())); - } - throw new BCException("Can't determine real target of clone() when processing instruction "+ - searchPtr.getInstruction()+". Perhaps avoid selecting clone with your pointcut?"); - } - return tx; - } - - - public void initializeArgVars() { - if (argVars != null) return; - InstructionFactory fact = getFactory(); - int len = getArgCount(); - argVars = new BcelVar[len]; - int positionOffset = (hasTarget() ? 1 : 0) + - ((hasThis() && !getKind().isTargetSameAsThis()) ? 1 : 0); - - if (getKind().argsOnStack()) { - // we move backwards because we're popping off the stack - for (int i = len - 1; i >= 0; i--) { - UnresolvedType type = getArgType(i); - BcelVar tmp = genTempVar(type, "ajc$arg" + i); - range.insert(tmp.createStore(getFactory()), Range.OutsideBefore); - int position = i; - position += positionOffset; - tmp.setPositionInAroundState(position); - argVars[i] = tmp; - } - } else { - int index = 0; - if (arg0HoldsThis()) index++; - - for (int i = 0; i < len; i++) { - UnresolvedType type = getArgType(i); - BcelVar tmp = genTempVar(type, "ajc$arg" + i); - range.insert(tmp.createCopyFrom(fact, index), Range.OutsideBefore); - argVars[i] = tmp; - int position = i; - position += positionOffset; -// System.out.println("set position: " + tmp + ", " + position + " in " + this); -// System.out.println(" hasThis: " + hasThis() + ", hasTarget: " + hasTarget()); - tmp.setPositionInAroundState(position); - index += type.getSize(); - } - } - } - public void initializeForAroundClosure() { - initializeArgVars(); - if (hasTarget()) initializeTargetVar(); - if (hasThis()) initializeThisVar(); -// System.out.println("initialized: " + this + " thisVar = " + thisVar); - } - - public void initializeThisAnnotationVars() { - if (thisAnnotationVars != null) return; - thisAnnotationVars = new HashMap(); - // populate.. - } - public void initializeTargetAnnotationVars() { - if (targetAnnotationVars != null) return; - if (getKind().isTargetSameAsThis()) { - if (hasThis()) initializeThisAnnotationVars(); - targetAnnotationVars = thisAnnotationVars; - } else { - targetAnnotationVars = new HashMap(); - ResolvedType[] rtx = this.getTargetType().resolve(world).getAnnotationTypes(); // what about annotations we havent gotten yet but we will get in subclasses? - for (int i = 0; i < rtx.length; i++) { + /** + * Get the Var for the jpStaticPart + * + * @return + */ + public BcelVar getThisJoinPointStaticPartBcelVar() { + return getThisJoinPointStaticPartBcelVar(false); + } + + /** + * Get the Var for the xxxxJpStaticPart, xxx = this or enclosing + * + * @param isEnclosingJp true to have the enclosingJpStaticPart + * @return + */ + public BcelVar getThisJoinPointStaticPartBcelVar(final boolean isEnclosingJp) { + if (thisJoinPointStaticPartVar == null) { + Field field = getEnclosingClass().getTjpField(this, isEnclosingJp); + ResolvedType sjpType = null; + if (world.isTargettingAspectJRuntime12()) { // TAG:SUPPORTING12: We didn't have different jpsp types in 1.2 + sjpType = world.getCoreType(UnresolvedType.JOINPOINT_STATICPART); + } else { + sjpType = isEnclosingJp ? world.getCoreType(UnresolvedType.JOINPOINT_ENCLOSINGSTATICPART) : world + .getCoreType(UnresolvedType.JOINPOINT_STATICPART); + } + thisJoinPointStaticPartVar = new BcelFieldRef(sjpType, getEnclosingClass().getClassName(), field.getName()); + // getEnclosingClass().warnOnAddedStaticInitializer(this,munger.getSourceLocation()); + } + return thisJoinPointStaticPartVar; + } + + /** + * Get the Var for the enclosingJpStaticPart + * + * @return + */ + public BcelVar getThisEnclosingJoinPointStaticPartBcelVar() { + if (enclosingShadow == null) { + // the enclosing of an execution is itself + return getThisJoinPointStaticPartBcelVar(true); + } else { + return ((BcelShadow) enclosingShadow).getThisJoinPointStaticPartBcelVar(true); + } + } + + // ??? need to better understand all the enclosing variants + public Member getEnclosingCodeSignature() { + if (getKind().isEnclosingKind()) { + return getSignature(); + } else if (getKind() == Shadow.PreInitialization) { + // PreInit doesn't enclose code but its signature + // is correctly the signature of the ctor. + return getSignature(); + } else if (enclosingShadow == null) { + return getEnclosingMethod().getMemberView(); + } else { + return enclosingShadow.getSignature(); + } + } + + private InstructionList makeArgsObjectArray() { + InstructionFactory fact = getFactory(); + BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY); + final InstructionList il = new InstructionList(); + int alen = getArgCount(); + il.append(Utility.createConstant(fact, alen)); + il.append(fact.createNewArray(Type.OBJECT, (short) 1)); + arrayVar.appendStore(il, fact); + + int stateIndex = 0; + for (int i = 0, len = getArgCount(); i < len; i++) { + arrayVar.appendConvertableArrayStore(il, fact, stateIndex, (BcelVar) getArgVar(i)); + stateIndex++; + } + arrayVar.appendLoad(il, fact); + return il; + } + + // ---- initializing var tables + + /* + * initializing this is doesn't do anything, because this is protected from side-effects, so we don't need to copy its location + */ + + private void initializeThisVar() { + if (thisVar != null) + return; + thisVar = new BcelVar(getThisType().resolve(world), 0); + thisVar.setPositionInAroundState(0); + } + + public void initializeTargetVar() { + InstructionFactory fact = getFactory(); + if (targetVar != null) + return; + if (getKind().isTargetSameAsThis()) { + if (hasThis()) + initializeThisVar(); + targetVar = thisVar; + } else { + initializeArgVars(); // gotta pop off the args before we find the target + UnresolvedType type = getTargetType(); + type = ensureTargetTypeIsCorrect(type); + targetVar = genTempVar(type, "ajc$target"); + range.insert(targetVar.createStore(fact), Range.OutsideBefore); + targetVar.setPositionInAroundState(hasThis() ? 1 : 0); + } + } + + /* + * PR 72528 This method double checks the target type under certain conditions. The Java 1.4 compilers seem to take calls to + * clone methods on array types and create bytecode that looks like clone is being called on Object. If we advise a clone call + * with around advice we extract the call into a helper method which we can then refer to. Because the type in the bytecode for + * the call to clone is Object we create a helper method with an Object parameter - this is not correct as we have lost the fact + * that the actual type is an array type. If we don't do the check below we will create code that fails java verification. This + * method checks for the peculiar set of conditions and if they are true, it has a sneak peek at the code before the call to see + * what is on the stack. + */ + public UnresolvedType ensureTargetTypeIsCorrect(UnresolvedType tx) { + + Member msig = getSignature(); + if (msig.getArity() == 0 && getKind() == MethodCall && msig.getName().charAt(0) == 'c' && tx.equals(ResolvedType.OBJECT) + && msig.getReturnType().equals(ResolvedType.OBJECT) && msig.getName().equals("clone")) { + + // Lets go back through the code from the start of the shadow + InstructionHandle searchPtr = range.getStart().getPrev(); + while (Range.isRangeHandle(searchPtr) || searchPtr.getInstruction().isStoreInstruction()) { // ignore this instruction - + // it doesnt give us the + // info we want + searchPtr = searchPtr.getPrev(); + } + + // A load instruction may tell us the real type of what the clone() call is on + if (searchPtr.getInstruction().isLoadInstruction()) { + LocalVariableTag lvt = LazyMethodGen.getLocalVariableTag(searchPtr, searchPtr.getInstruction().getIndex()); + if (lvt != null) + return UnresolvedType.forSignature(lvt.getType()); + } + // A field access instruction may tell us the real type of what the clone() call is on + if (searchPtr.getInstruction() instanceof FieldInstruction) { + FieldInstruction si = (FieldInstruction) searchPtr.getInstruction(); + Type t = si.getFieldType(getEnclosingClass().getConstantPool()); + return BcelWorld.fromBcel(t); + } + // A new array instruction obviously tells us it is an array type ! + if (searchPtr.getInstruction().opcode == Constants.ANEWARRAY) { + // ANEWARRAY ana = (ANEWARRAY)searchPoint.getInstruction(); + // Type t = ana.getType(getEnclosingClass().getConstantPool()); + // Just use a standard java.lang.object array - that will work fine + return BcelWorld.fromBcel(new ArrayType(Type.OBJECT, 1)); + } + // A multi new array instruction obviously tells us it is an array type ! + if (searchPtr.getInstruction() instanceof MULTIANEWARRAY) { + MULTIANEWARRAY ana = (MULTIANEWARRAY) searchPtr.getInstruction(); + // Type t = ana.getType(getEnclosingClass().getConstantPool()); + // t = new ArrayType(t,ana.getDimensions()); + // Just use a standard java.lang.object array - that will work fine + return BcelWorld.fromBcel(new ArrayType(Type.OBJECT, ana.getDimensions())); + } + throw new BCException("Can't determine real target of clone() when processing instruction " + + searchPtr.getInstruction() + ". Perhaps avoid selecting clone with your pointcut?"); + } + return tx; + } + + public void initializeArgVars() { + if (argVars != null) + return; + InstructionFactory fact = getFactory(); + int len = getArgCount(); + argVars = new BcelVar[len]; + int positionOffset = (hasTarget() ? 1 : 0) + ((hasThis() && !getKind().isTargetSameAsThis()) ? 1 : 0); + + if (getKind().argsOnStack()) { + // we move backwards because we're popping off the stack + for (int i = len - 1; i >= 0; i--) { + UnresolvedType type = getArgType(i); + BcelVar tmp = genTempVar(type, "ajc$arg" + i); + range.insert(tmp.createStore(getFactory()), Range.OutsideBefore); + int position = i; + position += positionOffset; + tmp.setPositionInAroundState(position); + argVars[i] = tmp; + } + } else { + int index = 0; + if (arg0HoldsThis()) + index++; + + for (int i = 0; i < len; i++) { + UnresolvedType type = getArgType(i); + BcelVar tmp = genTempVar(type, "ajc$arg" + i); + range.insert(tmp.createCopyFrom(fact, index), Range.OutsideBefore); + argVars[i] = tmp; + int position = i; + position += positionOffset; + // System.out.println("set position: " + tmp + ", " + position + " in " + this); + // System.out.println(" hasThis: " + hasThis() + ", hasTarget: " + hasTarget()); + tmp.setPositionInAroundState(position); + index += type.getSize(); + } + } + } + + public void initializeForAroundClosure() { + initializeArgVars(); + if (hasTarget()) + initializeTargetVar(); + if (hasThis()) + initializeThisVar(); + // System.out.println("initialized: " + this + " thisVar = " + thisVar); + } + + public void initializeThisAnnotationVars() { + if (thisAnnotationVars != null) + return; + thisAnnotationVars = new HashMap(); + // populate.. + } + + public void initializeTargetAnnotationVars() { + if (targetAnnotationVars != null) + return; + if (getKind().isTargetSameAsThis()) { + if (hasThis()) + initializeThisAnnotationVars(); + targetAnnotationVars = thisAnnotationVars; + } else { + targetAnnotationVars = new HashMap(); + ResolvedType[] rtx = this.getTargetType().resolve(world).getAnnotationTypes(); // what about annotations we havent + // gotten yet but we will get in + // subclasses? + for (int i = 0; i < rtx.length; i++) { ResolvedType typeX = rtx[i]; - targetAnnotationVars.put(typeX,new TypeAnnotationAccessVar(typeX,(BcelVar)getTargetVar())); + targetAnnotationVars.put(typeX, new TypeAnnotationAccessVar(typeX, (BcelVar) getTargetVar())); } - // populate. - } - } - public void initializeArgAnnotationVars() { - if (argAnnotationVars != null) return; - int numArgs = getArgCount(); - argAnnotationVars = new Map[numArgs]; - for (int i = 0; i < argAnnotationVars.length; i++) { + // populate. + } + } + + public void initializeArgAnnotationVars() { + if (argAnnotationVars != null) + return; + int numArgs = getArgCount(); + argAnnotationVars = new Map[numArgs]; + for (int i = 0; i < argAnnotationVars.length; i++) { argAnnotationVars[i] = new HashMap(); - //FIXME asc just delete this logic - we always build the Var on demand, as we don't know at weave time + // FIXME asc just delete this logic - we always build the Var on demand, as we don't know at weave time // what the full set of annotations could be (due to static/dynamic type differences...) } - } - - protected ResolvedMember getRelevantMember(ResolvedMember foundMember, Member relevantMember, ResolvedType relevantType){ - if (foundMember != null){ - return foundMember; - } - - - foundMember = getSignature().resolve(world); - if (foundMember == null && relevantMember != null) { - foundMember = relevantType.lookupMemberWithSupersAndITDs(relevantMember); - } - - // check the ITD'd dooberries - List mungers = relevantType.resolve(world).getInterTypeMungers(); - for (Iterator iter = mungers.iterator(); iter.hasNext();) { - BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); - if (typeMunger.getMunger() instanceof NewMethodTypeMunger || - typeMunger.getMunger() instanceof NewConstructorTypeMunger) { - ResolvedMember fakerm = typeMunger.getSignature(); - if (fakerm.getName().equals(getSignature().getName()) && - fakerm.getParameterSignature().equals(getSignature().getParameterSignature())){ - if (foundMember.getKind()==ResolvedMember.CONSTRUCTOR){ - foundMember = AjcMemberMaker.interConstructor( - relevantType, - foundMember, - typeMunger.getAspectType()); - } else { - foundMember = AjcMemberMaker.interMethod(foundMember, - typeMunger.getAspectType(), false); - } - // in the above.. what about if it's on an Interface? Can that happen? - // then the last arg of the above should be true - return foundMember; - } - } - } - return foundMember; - } - - protected ResolvedType [] getAnnotations(ResolvedMember foundMember, Member relevantMember, ResolvedType relevantType){ - if (foundMember == null){ - // check the ITD'd dooberries - List mungers = relevantType.resolve(world).getInterTypeMungers(); - for (Iterator iter = mungers.iterator(); iter.hasNext();) { - BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); - if (typeMunger.getMunger() instanceof NewMethodTypeMunger || - typeMunger.getMunger() instanceof NewConstructorTypeMunger) { - ResolvedMember fakerm = typeMunger.getSignature(); - //if (fakerm.hasAnnotations()) - - ResolvedMember ajcMethod = (getSignature().getKind()==ResolvedMember.CONSTRUCTOR? - AjcMemberMaker.postIntroducedConstructor(typeMunger.getAspectType(),fakerm.getDeclaringType(),fakerm.getParameterTypes()): - AjcMemberMaker.interMethodDispatcher(fakerm,typeMunger.getAspectType())); - //AjcMemberMaker.interMethodBody(fakerm,typeMunger.getAspectType())); - ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod); - if (fakerm.getName().equals(getSignature().getName()) && - fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) { - relevantType = typeMunger.getAspectType(); - foundMember = rmm; - return foundMember.getAnnotationTypes(); - } - } - } - // didn't find in ITDs, look in supers - foundMember = relevantType.lookupMemberWithSupersAndITDs(relevantMember); - if (foundMember == null) { - throw new IllegalStateException("Couldn't find member " + relevantMember + " for type " + relevantType); - } - } - return foundMember.getAnnotationTypes(); - } - - /** - * By determining what "kind" of shadow we are, we can find out the - * annotations on the appropriate element (method, field, constructor, type). - * Then create one BcelVar entry in the map for each annotation, keyed by - * annotation type. + } + + protected ResolvedMember getRelevantMember(ResolvedMember foundMember, Member relevantMember, ResolvedType relevantType) { + if (foundMember != null) { + return foundMember; + } + + foundMember = getSignature().resolve(world); + if (foundMember == null && relevantMember != null) { + foundMember = relevantType.lookupMemberWithSupersAndITDs(relevantMember); + } + + // check the ITD'd dooberries + List mungers = relevantType.resolve(world).getInterTypeMungers(); + for (Iterator iter = mungers.iterator(); iter.hasNext();) { + BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); + if (typeMunger.getMunger() instanceof NewMethodTypeMunger || typeMunger.getMunger() instanceof NewConstructorTypeMunger) { + ResolvedMember fakerm = typeMunger.getSignature(); + if (fakerm.getName().equals(getSignature().getName()) + && fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) { + if (foundMember.getKind() == ResolvedMember.CONSTRUCTOR) { + foundMember = AjcMemberMaker.interConstructor(relevantType, foundMember, typeMunger.getAspectType()); + } else { + foundMember = AjcMemberMaker.interMethod(foundMember, typeMunger.getAspectType(), false); + } + // in the above.. what about if it's on an Interface? Can that happen? + // then the last arg of the above should be true + return foundMember; + } + } + } + return foundMember; + } + + protected ResolvedType[] getAnnotations(ResolvedMember foundMember, Member relevantMember, ResolvedType relevantType) { + if (foundMember == null) { + // check the ITD'd dooberries + List mungers = relevantType.resolve(world).getInterTypeMungers(); + for (Iterator iter = mungers.iterator(); iter.hasNext();) { + BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); + if (typeMunger.getMunger() instanceof NewMethodTypeMunger + || typeMunger.getMunger() instanceof NewConstructorTypeMunger) { + ResolvedMember fakerm = typeMunger.getSignature(); + // if (fakerm.hasAnnotations()) + + ResolvedMember ajcMethod = (getSignature().getKind() == ResolvedMember.CONSTRUCTOR ? AjcMemberMaker + .postIntroducedConstructor(typeMunger.getAspectType(), fakerm.getDeclaringType(), fakerm + .getParameterTypes()) : AjcMemberMaker + .interMethodDispatcher(fakerm, typeMunger.getAspectType())); + // AjcMemberMaker.interMethodBody(fakerm,typeMunger.getAspectType())); + ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod); + if (fakerm.getName().equals(getSignature().getName()) + && fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) { + relevantType = typeMunger.getAspectType(); + foundMember = rmm; + return foundMember.getAnnotationTypes(); + } + } + } + // didn't find in ITDs, look in supers + foundMember = relevantType.lookupMemberWithSupersAndITDs(relevantMember); + if (foundMember == null) { + throw new IllegalStateException("Couldn't find member " + relevantMember + " for type " + relevantType); + } + } + return foundMember.getAnnotationTypes(); + } + + /** + * By determining what "kind" of shadow we are, we can find out the annotations on the appropriate element (method, field, + * constructor, type). Then create one BcelVar entry in the map for each annotation, keyed by annotation type. */ - public void initializeKindedAnnotationVars() { - if (kindedAnnotationVars != null) return; - kindedAnnotationVars = new HashMap(); - - // FIXME asc Refactor this code, there is duplication - ResolvedType[] annotations = null; - Member shadowSignature = getSignature(); - Member annotationHolder = getSignature(); - ResolvedType relevantType = shadowSignature.getDeclaringType().resolve(world); - - if (relevantType.isRawType() || relevantType.isParameterizedType()) relevantType = relevantType.getGenericType(); - - if (getKind() == Shadow.StaticInitialization) { - annotations = relevantType.resolve(world).getAnnotationTypes(); - } else if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) { - ResolvedMember foundMember = findMethod2(relevantType.resolve(world).getDeclaredMethods(),getSignature()); - annotations = getAnnotations(foundMember, shadowSignature, relevantType); - annotationHolder = getRelevantMember(foundMember,shadowSignature,relevantType); - relevantType = annotationHolder.getDeclaringType().resolve(world); - - } else if (getKind() == Shadow.FieldSet || getKind() == Shadow.FieldGet) { - annotationHolder = findField(relevantType.getDeclaredFields(),getSignature()); - - if (annotationHolder==null) { - // check the ITD'd dooberries + public void initializeKindedAnnotationVars() { + if (kindedAnnotationVars != null) + return; + kindedAnnotationVars = new HashMap(); + + // FIXME asc Refactor this code, there is duplication + ResolvedType[] annotations = null; + Member shadowSignature = getSignature(); + Member annotationHolder = getSignature(); + ResolvedType relevantType = shadowSignature.getDeclaringType().resolve(world); + + if (relevantType.isRawType() || relevantType.isParameterizedType()) + relevantType = relevantType.getGenericType(); + + if (getKind() == Shadow.StaticInitialization) { + annotations = relevantType.resolve(world).getAnnotationTypes(); + } else if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) { + ResolvedMember foundMember = findMethod2(relevantType.resolve(world).getDeclaredMethods(), getSignature()); + annotations = getAnnotations(foundMember, shadowSignature, relevantType); + annotationHolder = getRelevantMember(foundMember, shadowSignature, relevantType); + relevantType = annotationHolder.getDeclaringType().resolve(world); + + } else if (getKind() == Shadow.FieldSet || getKind() == Shadow.FieldGet) { + annotationHolder = findField(relevantType.getDeclaredFields(), getSignature()); + + if (annotationHolder == null) { + // check the ITD'd dooberries List mungers = relevantType.resolve(world).getInterTypeMungers(); for (Iterator iter = mungers.iterator(); iter.hasNext();) { BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); if (typeMunger.getMunger() instanceof NewFieldTypeMunger) { - ResolvedMember fakerm = typeMunger.getSignature(); - //if (fakerm.hasAnnotations()) - ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm,typeMunger.getAspectType()); - ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod); - if (fakerm.equals(getSignature())) { - relevantType = typeMunger.getAspectType(); - annotationHolder = rmm; - } + ResolvedMember fakerm = typeMunger.getSignature(); + // if (fakerm.hasAnnotations()) + ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm, typeMunger.getAspectType()); + ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod); + if (fakerm.equals(getSignature())) { + relevantType = typeMunger.getAspectType(); + annotationHolder = rmm; + } } - } + } } - annotations = ((ResolvedMember)annotationHolder).getAnnotationTypes(); - - } else if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution || - getKind() == Shadow.AdviceExecution) { - //ResolvedMember rm[] = relevantType.getDeclaredMethods(); - ResolvedMember foundMember = findMethod2(relevantType.getDeclaredMethods(),getSignature()); - - annotations = getAnnotations(foundMember, shadowSignature, relevantType); - annotationHolder = foundMember; - annotationHolder = getRelevantMember(foundMember, annotationHolder,relevantType); - - } else if (getKind() == Shadow.ExceptionHandler) { - relevantType = getSignature().getParameterTypes()[0].resolve(world); - annotations = relevantType.getAnnotationTypes(); - } else if (getKind() == Shadow.PreInitialization || getKind() == Shadow.Initialization) { - ResolvedMember found = findMethod2(relevantType.getDeclaredMethods(),getSignature()); - annotations = found.getAnnotationTypes(); - } - - if (annotations == null) { - // We can't have recognized the shadow - should blow up now to be on the safe side - throw new BCException("Could not discover annotations for shadow: "+getKind()); - } - + annotations = ((ResolvedMember) annotationHolder).getAnnotationTypes(); + + } else if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution + || getKind() == Shadow.AdviceExecution) { + // ResolvedMember rm[] = relevantType.getDeclaredMethods(); + ResolvedMember foundMember = findMethod2(relevantType.getDeclaredMethods(), getSignature()); + + annotations = getAnnotations(foundMember, shadowSignature, relevantType); + annotationHolder = foundMember; + annotationHolder = getRelevantMember(foundMember, annotationHolder, relevantType); + + } else if (getKind() == Shadow.ExceptionHandler) { + relevantType = getSignature().getParameterTypes()[0].resolve(world); + annotations = relevantType.getAnnotationTypes(); + } else if (getKind() == Shadow.PreInitialization || getKind() == Shadow.Initialization) { + ResolvedMember found = findMethod2(relevantType.getDeclaredMethods(), getSignature()); + annotations = found.getAnnotationTypes(); + } + + if (annotations == null) { + // We can't have recognized the shadow - should blow up now to be on the safe side + throw new BCException("Could not discover annotations for shadow: " + getKind()); + } + for (int i = 0; i < annotations.length; i++) { ResolvedType annotationType = annotations[i]; - AnnotationAccessVar accessVar = new AnnotationAccessVar(getKind(),annotationType.resolve(world),relevantType,annotationHolder); - kindedAnnotationVars.put(annotationType,accessVar); + AnnotationAccessVar accessVar = new AnnotationAccessVar(getKind(), annotationType.resolve(world), relevantType, + annotationHolder); + kindedAnnotationVars.put(annotationType, accessVar); } - } - - //FIXME asc whats the real diff between this one and the version in findMethod()? - ResolvedMember findMethod2(ResolvedMember rm[], Member sig) { + } + + // FIXME asc whats the real diff between this one and the version in findMethod()? + ResolvedMember findMethod2(ResolvedMember rm[], Member sig) { ResolvedMember found = null; // String searchString = getSignature().getName()+getSignature().getParameterSignature(); - for (int i = 0; i < rm.length && found==null; i++) { + for (int i = 0; i < rm.length && found == null; i++) { ResolvedMember member = rm[i]; if (member.getName().equals(sig.getName()) && member.getParameterSignature().equals(sig.getParameterSignature())) - found = member; + found = member; } return found; - } - - private ResolvedMember findMethod(ResolvedType aspectType, ResolvedMember ajcMethod) { - ResolvedMember decMethods[] = aspectType.getDeclaredMethods(); - for (int i = 0; i < decMethods.length; i++) { - ResolvedMember member = decMethods[i]; - if (member.equals(ajcMethod)) return member; - } + } + + private ResolvedMember findMethod(ResolvedType aspectType, ResolvedMember ajcMethod) { + ResolvedMember decMethods[] = aspectType.getDeclaredMethods(); + for (int i = 0; i < decMethods.length; i++) { + ResolvedMember member = decMethods[i]; + if (member.equals(ajcMethod)) + return member; + } return null; } - - - private ResolvedMember findField(ResolvedMember[] members,Member lookingFor) { - for (int i = 0; i < members.length; i++) { - ResolvedMember member = members[i]; - if ( member.getName().equals(getSignature().getName()) && - member.getType().equals(getSignature().getType())) { - return member; + private ResolvedMember findField(ResolvedMember[] members, Member lookingFor) { + for (int i = 0; i < members.length; i++) { + ResolvedMember member = members[i]; + if (member.getName().equals(getSignature().getName()) && member.getType().equals(getSignature().getType())) { + return member; + } } - } - return null; + return null; } - - + public void initializeWithinAnnotationVars() { - if (withinAnnotationVars != null) return; - withinAnnotationVars = new HashMap(); - - ResolvedType[] annotations = getEnclosingType().resolve(world).getAnnotationTypes(); + if (withinAnnotationVars != null) + return; + withinAnnotationVars = new HashMap(); + + ResolvedType[] annotations = getEnclosingType().resolve(world).getAnnotationTypes(); for (int i = 0; i < annotations.length; i++) { ResolvedType ann = annotations[i]; Kind k = Shadow.StaticInitialization; - withinAnnotationVars.put(ann,new AnnotationAccessVar(k,ann,getEnclosingType(),null)); - } - } - - public void initializeWithinCodeAnnotationVars() { - if (withincodeAnnotationVars != null) return; - withincodeAnnotationVars = new HashMap(); - - // For some shadow we are interested in annotations on the method containing that shadow. + withinAnnotationVars.put(ann, new AnnotationAccessVar(k, ann, getEnclosingType(), null)); + } + } + + public void initializeWithinCodeAnnotationVars() { + if (withincodeAnnotationVars != null) + return; + withincodeAnnotationVars = new HashMap(); + + // For some shadow we are interested in annotations on the method containing that shadow. ResolvedType[] annotations = getEnclosingMethod().getMemberView().getAnnotationTypes(); for (int i = 0; i < annotations.length; i++) { ResolvedType ann = annotations[i]; - Kind k = (getEnclosingMethod().getMemberView().getKind()==Member.CONSTRUCTOR? - Shadow.ConstructorExecution:Shadow.MethodExecution); - withincodeAnnotationVars.put(ann, - new AnnotationAccessVar(k,ann,getEnclosingType(),getEnclosingCodeSignature())); - } - } - - - // ---- weave methods - - void weaveBefore(BcelAdvice munger) { - range.insert( - munger.getAdviceInstructions(this, null, range.getRealStart()), - Range.InsideBefore); - } - - public void weaveAfter(BcelAdvice munger) { - weaveAfterThrowing(munger, UnresolvedType.THROWABLE); - weaveAfterReturning(munger); - } - + Kind k = (getEnclosingMethod().getMemberView().getKind() == Member.CONSTRUCTOR ? Shadow.ConstructorExecution + : Shadow.MethodExecution); + withincodeAnnotationVars.put(ann, new AnnotationAccessVar(k, ann, getEnclosingType(), getEnclosingCodeSignature())); + } + } + + // ---- weave methods + + void weaveBefore(BcelAdvice munger) { + range.insert(munger.getAdviceInstructions(this, null, range.getRealStart()), Range.InsideBefore); + } + + public void weaveAfter(BcelAdvice munger) { + weaveAfterThrowing(munger, UnresolvedType.THROWABLE); + weaveAfterReturning(munger); + } + /** - * The basic strategy here is to add a set of instructions at the end of - * the shadow range that dispatch the advice, and then return whatever the - * shadow was going to return anyway. + * The basic strategy here is to add a set of instructions at the end of the shadow range that dispatch the advice, and then + * return whatever the shadow was going to return anyway. * - * To achieve this, we note all the return statements in the advice, and - * replace them with code that: - * 1) stores the return value on top of the stack in a temp var - * 2) jumps to the start of our advice block - * 3) restores the return value at the end of the advice block before - * ultimately returning + * To achieve this, we note all the return statements in the advice, and replace them with code that: 1) stores the return value + * on top of the stack in a temp var 2) jumps to the start of our advice block 3) restores the return value at the end of the + * advice block before ultimately returning * - * We also need to bind the return value into a returning parameter, if the - * advice specified one. + * We also need to bind the return value into a returning parameter, if the advice specified one. */ - public void weaveAfterReturning(BcelAdvice munger) { - List returns = findReturnInstructions(); - boolean hasReturnInstructions = !returns.isEmpty(); - - // list of instructions that handle the actual return from the join point - InstructionList retList = new InstructionList(); - - // variable that holds the return value - BcelVar returnValueVar = null; - - if (hasReturnInstructions) { - returnValueVar = generateReturnInstructions(returns,retList); - } else { - // we need at least one instruction, as the target for jumps - retList.append(InstructionConstants.NOP); - } - - // list of instructions for dispatching to the advice itself - InstructionList advice = getAfterReturningAdviceDispatchInstructions( - munger, retList.getStart()); - - if (hasReturnInstructions) { - InstructionHandle gotoTarget = advice.getStart(); + public void weaveAfterReturning(BcelAdvice munger) { + List returns = findReturnInstructions(); + boolean hasReturnInstructions = !returns.isEmpty(); + + // list of instructions that handle the actual return from the join point + InstructionList retList = new InstructionList(); + + // variable that holds the return value + BcelVar returnValueVar = null; + + if (hasReturnInstructions) { + returnValueVar = generateReturnInstructions(returns, retList); + } else { + // we need at least one instruction, as the target for jumps + retList.append(InstructionConstants.NOP); + } + + // list of instructions for dispatching to the advice itself + InstructionList advice = getAfterReturningAdviceDispatchInstructions(munger, retList.getStart()); + + if (hasReturnInstructions) { + InstructionHandle gotoTarget = advice.getStart(); for (Iterator i = returns.iterator(); i.hasNext();) { InstructionHandle ih = (InstructionHandle) i.next(); retargetReturnInstruction(munger.hasExtraParameter(), returnValueVar, gotoTarget, ih); } - } - - range.append(advice); - range.append(retList); - } + } + + range.append(advice); + range.append(retList); + } /** * @return a list of all the return instructions in the range of this shadow */ private List findReturnInstructions() { List returns = new ArrayList(); - for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) { - if (ih.getInstruction().isReturnInstruction()) { - returns.add(ih); - } - } + for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) { + if (ih.getInstruction().isReturnInstruction()) { + returns.add(ih); + } + } return returns; } /** - * Given a list containing all the return instruction handles for this shadow, - * finds the last return instruction and copies it, making this the ultimate - * return. If the shadow has a non-void return type, we also create a temporary - * variable to hold the return value, and load the value from this var before - * returning (see pr148007 for why we do this - it works around a JRockit bug, - * and is also closer to what javac generates) + * Given a list containing all the return instruction handles for this shadow, finds the last return instruction and copies it, + * making this the ultimate return. If the shadow has a non-void return type, we also create a temporary variable to hold the + * return value, and load the value from this var before returning (see pr148007 for why we do this - it works around a JRockit + * bug, and is also closer to what javac generates) * - * Sometimes the 'last return' isnt the right one - some rogue code can - * include the real return from the body of a subroutine that exists at the end - * of the method. In this case the last return is RETURN but that may not be - * correct for a method with a non-void return type... pr151673 + * Sometimes the 'last return' isnt the right one - some rogue code can include the real return from the body of a subroutine + * that exists at the end of the method. In this case the last return is RETURN but that may not be correct for a method with a + * non-void return type... pr151673 * * @param returns list of all the return instructions in the shadow - * @param returnInstructions instruction list into which the return instructions should - * be generated + * @param returnInstructions instruction list into which the return instructions should be generated * @return the variable holding the return value, if needed */ private BcelVar generateReturnInstructions(List returns, InstructionList returnInstructions) { BcelVar returnValueVar = null; - if (this.hasANonVoidReturnType()) { - // Find the last *correct* return - this is a method with a non-void return type - // so ignore RETURN - Instruction newReturnInstruction = null; - int i=returns.size()-1; - while (newReturnInstruction == null && i>=0) { - InstructionHandle ih = (InstructionHandle)returns.get(i); - if (ih.getInstruction().opcode!=Constants.RETURN) { - newReturnInstruction = Utility.copyInstruction(ih.getInstruction()); - } - i--; - } - returnValueVar = genTempVar(this.getReturnType()); - returnValueVar.appendLoad(returnInstructions,getFactory()); - returnInstructions.append(newReturnInstruction); - } else { - InstructionHandle lastReturnHandle = (InstructionHandle)returns.get(returns.size() - 1); - Instruction newReturnInstruction = Utility.copyInstruction(lastReturnHandle.getInstruction()); - returnInstructions.append(newReturnInstruction); - } - return returnValueVar; - } - + if (this.hasANonVoidReturnType()) { + // Find the last *correct* return - this is a method with a non-void return type + // so ignore RETURN + Instruction newReturnInstruction = null; + int i = returns.size() - 1; + while (newReturnInstruction == null && i >= 0) { + InstructionHandle ih = (InstructionHandle) returns.get(i); + if (ih.getInstruction().opcode != Constants.RETURN) { + newReturnInstruction = Utility.copyInstruction(ih.getInstruction()); + } + i--; + } + returnValueVar = genTempVar(this.getReturnType()); + returnValueVar.appendLoad(returnInstructions, getFactory()); + returnInstructions.append(newReturnInstruction); + } else { + InstructionHandle lastReturnHandle = (InstructionHandle) returns.get(returns.size() - 1); + Instruction newReturnInstruction = Utility.copyInstruction(lastReturnHandle.getInstruction()); + returnInstructions.append(newReturnInstruction); + } + return returnValueVar; + } + /** * @return true, iff this shadow returns a value */ @@ -1852,24 +1653,26 @@ public class BcelShadow extends Shadow { /** * Get the list of instructions used to dispatch to the after advice + * * @param munger * @param firstInstructionInReturnSequence * @return */ - private InstructionList getAfterReturningAdviceDispatchInstructions(BcelAdvice munger, InstructionHandle firstInstructionInReturnSequence) { + private InstructionList getAfterReturningAdviceDispatchInstructions(BcelAdvice munger, + InstructionHandle firstInstructionInReturnSequence) { InstructionList advice = new InstructionList(); - - BcelVar tempVar = null; - if (munger.hasExtraParameter()) { - tempVar = insertAdviceInstructionsForBindingReturningParameter(advice); - } - advice.append(munger.getAdviceInstructions(this, tempVar, firstInstructionInReturnSequence)); + + BcelVar tempVar = null; + if (munger.hasExtraParameter()) { + tempVar = insertAdviceInstructionsForBindingReturningParameter(advice); + } + advice.append(munger.getAdviceInstructions(this, tempVar, firstInstructionInReturnSequence)); return advice; } /** - * If the after() returning(Foo f) form is used, bind the return value to the parameter. - * If the shadow returns void, bind null. + * If the after() returning(Foo f) form is used, bind the return value to the parameter. If the shadow returns void, bind null. + * * @param advice * @return */ @@ -1881,133 +1684,127 @@ public class BcelShadow extends Shadow { advice.append(InstructionConstants.ACONST_NULL); tempVar.appendStore(advice, getFactory()); } else { - tempVar = genTempVar(tempVarType); - advice.append(InstructionFactory.createDup(tempVarType.getSize())); - tempVar.appendStore(advice, getFactory()); + tempVar = genTempVar(tempVarType); + advice.append(InstructionFactory.createDup(tempVarType.getSize())); + tempVar.appendStore(advice, getFactory()); } return tempVar; } - /** * Helper method for weaveAfterReturning * - * Each return instruction in the method body is retargeted by calling this method. - * The return instruction is replaced by up to three instructions: - * 1) if the shadow returns a value, and that value is bound to an after returning - * parameter, then we DUP the return value on the top of the stack - * 2) if the shadow returns a value, we store it in the returnValueVar (it will - * be retrieved from here when we ultimately return after the advice dispatch) - * 3) if the return was the last instruction, we add a NOP (it will fall through - * to the advice dispatch), otherwise we add a GOTO that branches to the - * supplied gotoTarget (start of the advice dispatch) + * Each return instruction in the method body is retargeted by calling this method. The return instruction is replaced by up to + * three instructions: 1) if the shadow returns a value, and that value is bound to an after returning parameter, then we DUP + * the return value on the top of the stack 2) if the shadow returns a value, we store it in the returnValueVar (it will be + * retrieved from here when we ultimately return after the advice dispatch) 3) if the return was the last instruction, we add a + * NOP (it will fall through to the advice dispatch), otherwise we add a GOTO that branches to the supplied gotoTarget (start of + * the advice dispatch) */ - private void retargetReturnInstruction(boolean hasReturningParameter, BcelVar returnValueVar, InstructionHandle gotoTarget, InstructionHandle returnHandle) { + private void retargetReturnInstruction(boolean hasReturningParameter, BcelVar returnValueVar, InstructionHandle gotoTarget, + InstructionHandle returnHandle) { // pr148007, work around JRockit bug // replace ret with store into returnValueVar, followed by goto if not // at the end of the instruction list... InstructionList newInstructions = new InstructionList(); if (returnValueVar != null) { - if (hasReturningParameter) { - // we have to dup the return val before consuming it... - newInstructions.append(InstructionFactory.createDup(this.getReturnType().getSize())); - } + if (hasReturningParameter) { + // we have to dup the return val before consuming it... + newInstructions.append(InstructionFactory.createDup(this.getReturnType().getSize())); + } // store the return value into this var - returnValueVar.appendStore(newInstructions,getFactory()); + returnValueVar.appendStore(newInstructions, getFactory()); } - if (!isLastInstructionInRange(returnHandle,range)) { - newInstructions.append(InstructionFactory.createBranchInstruction( - Constants.GOTO, - gotoTarget)); + if (!isLastInstructionInRange(returnHandle, range)) { + newInstructions.append(InstructionFactory.createBranchInstruction(Constants.GOTO, gotoTarget)); } if (newInstructions.isEmpty()) { newInstructions.append(InstructionConstants.NOP); } - Utility.replaceInstruction(returnHandle,newInstructions,enclosingMethod); - } - - private boolean isLastInstructionInRange(InstructionHandle ih, ShadowRange aRange) { - return ih.getNext() == aRange.getEnd(); - } - - public void weaveAfterThrowing(BcelAdvice munger, UnresolvedType catchType) { - // a good optimization would be not to generate anything here - // if the shadow is GUARANTEED empty (i.e., there's NOTHING, not even - // a shadow, inside me). - if (getRange().getStart().getNext() == getRange().getEnd()) return; - InstructionFactory fact = getFactory(); - InstructionList handler = new InstructionList(); - BcelVar exceptionVar = genTempVar(catchType); - exceptionVar.appendStore(handler, fact); - - // pr62642 - // I will now jump through some firey BCEL hoops to generate a trivial bit of code: - // if (exc instanceof ExceptionInInitializerError) - // throw (ExceptionInInitializerError)exc; - if (this.getEnclosingMethod().getName().equals("<clinit>")) { - ResolvedType eiieType = world.resolve("java.lang.ExceptionInInitializerError"); - ObjectType eiieBcelType = (ObjectType)BcelWorld.makeBcelType(eiieType); - InstructionList ih = new InstructionList(InstructionConstants.NOP); - handler.append(exceptionVar.createLoad(fact)); - handler.append(fact.createInstanceOf(eiieBcelType)); - InstructionBranch bi = - InstructionFactory.createBranchInstruction(Constants.IFEQ,ih.getStart()); - handler.append(bi); - handler.append(exceptionVar.createLoad(fact)); - handler.append(fact.createCheckCast(eiieBcelType)); - handler.append(InstructionConstants.ATHROW); - handler.append(ih); - } - - InstructionList endHandler = new InstructionList( - exceptionVar.createLoad(fact)); - handler.append(munger.getAdviceInstructions(this, exceptionVar, endHandler.getStart())); - handler.append(endHandler); - handler.append(InstructionConstants.ATHROW); - InstructionHandle handlerStart = handler.getStart(); - - if (isFallsThrough()) { - InstructionHandle jumpTarget = handler.append(InstructionConstants.NOP); - handler.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, jumpTarget)); - } + Utility.replaceInstruction(returnHandle, newInstructions, enclosingMethod); + } + + private boolean isLastInstructionInRange(InstructionHandle ih, ShadowRange aRange) { + return ih.getNext() == aRange.getEnd(); + } + + public void weaveAfterThrowing(BcelAdvice munger, UnresolvedType catchType) { + // a good optimization would be not to generate anything here + // if the shadow is GUARANTEED empty (i.e., there's NOTHING, not even + // a shadow, inside me). + if (getRange().getStart().getNext() == getRange().getEnd()) + return; + InstructionFactory fact = getFactory(); + InstructionList handler = new InstructionList(); + BcelVar exceptionVar = genTempVar(catchType); + exceptionVar.appendStore(handler, fact); + + // pr62642 + // I will now jump through some firey BCEL hoops to generate a trivial bit of code: + // if (exc instanceof ExceptionInInitializerError) + // throw (ExceptionInInitializerError)exc; + if (this.getEnclosingMethod().getName().equals("<clinit>")) { + ResolvedType eiieType = world.resolve("java.lang.ExceptionInInitializerError"); + ObjectType eiieBcelType = (ObjectType) BcelWorld.makeBcelType(eiieType); + InstructionList ih = new InstructionList(InstructionConstants.NOP); + handler.append(exceptionVar.createLoad(fact)); + handler.append(fact.createInstanceOf(eiieBcelType)); + InstructionBranch bi = InstructionFactory.createBranchInstruction(Constants.IFEQ, ih.getStart()); + handler.append(bi); + handler.append(exceptionVar.createLoad(fact)); + handler.append(fact.createCheckCast(eiieBcelType)); + handler.append(InstructionConstants.ATHROW); + handler.append(ih); + } + + InstructionList endHandler = new InstructionList(exceptionVar.createLoad(fact)); + handler.append(munger.getAdviceInstructions(this, exceptionVar, endHandler.getStart())); + handler.append(endHandler); + handler.append(InstructionConstants.ATHROW); + InstructionHandle handlerStart = handler.getStart(); + + if (isFallsThrough()) { + InstructionHandle jumpTarget = handler.append(InstructionConstants.NOP); + handler.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, jumpTarget)); + } InstructionHandle protectedEnd = handler.getStart(); - range.insert(handler, Range.InsideAfter); - - enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(), - handlerStart, (ObjectType)BcelWorld.makeBcelType(catchType), //???Type.THROWABLE, - // high priority if our args are on the stack - getKind().hasHighPriorityExceptions()); - } - - - //??? this shares a lot of code with the above weaveAfterThrowing - //??? would be nice to abstract that to say things only once - public void weaveSoftener(BcelAdvice munger, UnresolvedType catchType) { - // a good optimization would be not to generate anything here - // if the shadow is GUARANTEED empty (i.e., there's NOTHING, not even - // a shadow, inside me). - if (getRange().getStart().getNext() == getRange().getEnd()) return; - - InstructionFactory fact = getFactory(); - InstructionList handler = new InstructionList(); + range.insert(handler, Range.InsideAfter); + + enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(), handlerStart, + (ObjectType) BcelWorld.makeBcelType(catchType), // ???Type.THROWABLE, + // high priority if our args are on the stack + getKind().hasHighPriorityExceptions()); + } + + // ??? this shares a lot of code with the above weaveAfterThrowing + // ??? would be nice to abstract that to say things only once + public void weaveSoftener(BcelAdvice munger, UnresolvedType catchType) { + // a good optimization would be not to generate anything here + // if the shadow is GUARANTEED empty (i.e., there's NOTHING, not even + // a shadow, inside me). + if (getRange().getStart().getNext() == getRange().getEnd()) + return; + + InstructionFactory fact = getFactory(); + InstructionList handler = new InstructionList(); InstructionList rtExHandler = new InstructionList(); - BcelVar exceptionVar = genTempVar(catchType); - + BcelVar exceptionVar = genTempVar(catchType); + handler.append(fact.createNew(NameMangler.SOFT_EXCEPTION_TYPE)); - handler.append(InstructionFactory.createDup(1)); - handler.append(exceptionVar.createLoad(fact)); - handler.append(fact.createInvoke(NameMangler.SOFT_EXCEPTION_TYPE, "<init>", - Type.VOID, new Type[] { Type.THROWABLE }, Constants.INVOKESPECIAL)); //??? special - handler.append(InstructionConstants.ATHROW); + handler.append(InstructionFactory.createDup(1)); + handler.append(exceptionVar.createLoad(fact)); + handler.append(fact.createInvoke(NameMangler.SOFT_EXCEPTION_TYPE, "<init>", Type.VOID, new Type[] { Type.THROWABLE }, + Constants.INVOKESPECIAL)); // ??? special + handler.append(InstructionConstants.ATHROW); // ENH 42737 - exceptionVar.appendStore(rtExHandler, fact); + exceptionVar.appendStore(rtExHandler, fact); // aload_1 rtExHandler.append(exceptionVar.createLoad(fact)); // instanceof class java/lang/RuntimeException rtExHandler.append(fact.createInstanceOf(new ObjectType("java.lang.RuntimeException"))); // ifeq go to new SOFT_EXCEPTION_TYPE instruction - rtExHandler.append(InstructionFactory.createBranchInstruction(Constants.IFEQ,handler.getStart())); + rtExHandler.append(InstructionFactory.createBranchInstruction(Constants.IFEQ, handler.getStart())); // aload_1 rtExHandler.append(exceptionVar.createLoad(fact)); // athrow @@ -2016,327 +1813,272 @@ public class BcelShadow extends Shadow { InstructionHandle handlerStart = rtExHandler.getStart(); if (isFallsThrough()) { - InstructionHandle jumpTarget = range.getEnd();//handler.append(fact.NOP); - rtExHandler.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, jumpTarget)); - } + InstructionHandle jumpTarget = range.getEnd();// handler.append(fact.NOP); + rtExHandler.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, jumpTarget)); + } rtExHandler.append(handler); InstructionHandle protectedEnd = rtExHandler.getStart(); - range.insert(rtExHandler, Range.InsideAfter); - - enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(), - handlerStart, (ObjectType)BcelWorld.makeBcelType(catchType), - // high priority if our args are on the stack - getKind().hasHighPriorityExceptions()); - } + range.insert(rtExHandler, Range.InsideAfter); + enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(), handlerStart, + (ObjectType) BcelWorld.makeBcelType(catchType), + // high priority if our args are on the stack + getKind().hasHighPriorityExceptions()); + } public void weavePerObjectEntry(final BcelAdvice munger, final BcelVar onVar) { - final InstructionFactory fact = getFactory(); - + final InstructionFactory fact = getFactory(); InstructionList entryInstructions = new InstructionList(); InstructionList entrySuccessInstructions = new InstructionList(); onVar.appendLoad(entrySuccessInstructions, fact); - entrySuccessInstructions.append( - Utility.createInvoke(fact, world, - AjcMemberMaker.perObjectBind(munger.getConcreteAspect()))); - - InstructionList testInstructions = - munger.getTestInstructions(this, entrySuccessInstructions.getStart(), - range.getRealStart(), - entrySuccessInstructions.getStart()); - + entrySuccessInstructions + .append(Utility.createInvoke(fact, world, AjcMemberMaker.perObjectBind(munger.getConcreteAspect()))); + + InstructionList testInstructions = munger.getTestInstructions(this, entrySuccessInstructions.getStart(), range + .getRealStart(), entrySuccessInstructions.getStart()); + entryInstructions.append(testInstructions); entryInstructions.append(entrySuccessInstructions); - + range.insert(entryInstructions, Range.InsideBefore); } - - // PTWIMPL Create static initializer to call the aspect factory + + // PTWIMPL Create static initializer to call the aspect factory /** * Causes the aspect instance to be *set* for later retrievable through localAspectof()/aspectOf() */ - public void weavePerTypeWithinAspectInitialization(final BcelAdvice munger,UnresolvedType t) { - - if (t.resolve(world).isInterface()) return; // Don't initialize statics in - final InstructionFactory fact = getFactory(); + public void weavePerTypeWithinAspectInitialization(final BcelAdvice munger, UnresolvedType t) { + + if (t.resolve(world).isInterface()) + return; // Don't initialize statics in + final InstructionFactory fact = getFactory(); InstructionList entryInstructions = new InstructionList(); InstructionList entrySuccessInstructions = new InstructionList(); - + BcelWorld.getBcelObjectType(munger.getConcreteAspect()); String aspectname = munger.getConcreteAspect().getName(); - + String ptwField = NameMangler.perTypeWithinFieldForTarget(munger.getConcreteAspect()); - entrySuccessInstructions.append(InstructionFactory.PUSH(fact.getConstantPool(),t.getName())); - - entrySuccessInstructions.append(fact.createInvoke(aspectname,"ajc$createAspectInstance",new ObjectType(aspectname), - new Type[]{new ObjectType("java.lang.String")},Constants.INVOKESTATIC)); - entrySuccessInstructions.append(fact.createPutStatic(t.getName(),ptwField, - new ObjectType(aspectname))); - + entrySuccessInstructions.append(InstructionFactory.PUSH(fact.getConstantPool(), t.getName())); + + entrySuccessInstructions.append(fact.createInvoke(aspectname, "ajc$createAspectInstance", new ObjectType(aspectname), + new Type[] { new ObjectType("java.lang.String") }, Constants.INVOKESTATIC)); + entrySuccessInstructions.append(fact.createPutStatic(t.getName(), ptwField, new ObjectType(aspectname))); + entryInstructions.append(entrySuccessInstructions); - + range.insert(entryInstructions, Range.InsideBefore); } - - + public void weaveCflowEntry(final BcelAdvice munger, final Member cflowField) { - final boolean isPer = munger.getKind() == AdviceKind.PerCflowBelowEntry || - munger.getKind() == AdviceKind.PerCflowEntry; - + final boolean isPer = munger.getKind() == AdviceKind.PerCflowBelowEntry || munger.getKind() == AdviceKind.PerCflowEntry; + final Type objectArrayType = new ArrayType(Type.OBJECT, 1); - final InstructionFactory fact = getFactory(); + final InstructionFactory fact = getFactory(); final BcelVar testResult = genTempVar(ResolvedType.BOOLEAN); InstructionList entryInstructions = new InstructionList(); { InstructionList entrySuccessInstructions = new InstructionList(); - + if (munger.hasDynamicTests()) { entryInstructions.append(Utility.createConstant(fact, 0)); testResult.appendStore(entryInstructions, fact); - + entrySuccessInstructions.append(Utility.createConstant(fact, 1)); testResult.appendStore(entrySuccessInstructions, fact); } if (isPer) { - entrySuccessInstructions.append( - fact.createInvoke(munger.getConcreteAspect().getName(), - NameMangler.PERCFLOW_PUSH_METHOD, - Type.VOID, - new Type[] { }, - Constants.INVOKESTATIC)); + entrySuccessInstructions.append(fact.createInvoke(munger.getConcreteAspect().getName(), + NameMangler.PERCFLOW_PUSH_METHOD, Type.VOID, new Type[] {}, Constants.INVOKESTATIC)); } else { BcelVar[] cflowStateVars = munger.getExposedStateAsBcelVars(false); - + if (cflowStateVars.length == 0) { // This should be getting managed by a counter - lets make sure. - if (!cflowField.getType().getName().endsWith("CFlowCounter")) + if (!cflowField.getType().getName().endsWith("CFlowCounter")) throw new RuntimeException("Incorrectly attempting counter operation on stacked cflow"); - entrySuccessInstructions.append( - Utility.createGet(fact, cflowField)); - //arrayVar.appendLoad(entrySuccessInstructions, fact); - entrySuccessInstructions.append(fact.createInvoke(NameMangler.CFLOW_COUNTER_TYPE,"inc",Type.VOID,new Type[] { },Constants.INVOKEVIRTUAL)); + entrySuccessInstructions.append(Utility.createGet(fact, cflowField)); + // arrayVar.appendLoad(entrySuccessInstructions, fact); + entrySuccessInstructions.append(fact.createInvoke(NameMangler.CFLOW_COUNTER_TYPE, "inc", Type.VOID, + new Type[] {}, Constants.INVOKEVIRTUAL)); } else { - BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY); - - int alen = cflowStateVars.length; - entrySuccessInstructions.append(Utility.createConstant(fact, alen)); - entrySuccessInstructions.append(fact.createNewArray(Type.OBJECT, (short) 1)); - arrayVar.appendStore(entrySuccessInstructions, fact); - - for (int i = 0; i < alen; i++) { - arrayVar.appendConvertableArrayStore( - entrySuccessInstructions, - fact, - i, - cflowStateVars[i]); - } - - entrySuccessInstructions.append( - Utility.createGet(fact, cflowField)); - arrayVar.appendLoad(entrySuccessInstructions, fact); - - entrySuccessInstructions.append( - fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "push", Type.VOID, - new Type[] { objectArrayType }, - Constants.INVOKEVIRTUAL)); + BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY); + + int alen = cflowStateVars.length; + entrySuccessInstructions.append(Utility.createConstant(fact, alen)); + entrySuccessInstructions.append(fact.createNewArray(Type.OBJECT, (short) 1)); + arrayVar.appendStore(entrySuccessInstructions, fact); + + for (int i = 0; i < alen; i++) { + arrayVar.appendConvertableArrayStore(entrySuccessInstructions, fact, i, cflowStateVars[i]); + } + + entrySuccessInstructions.append(Utility.createGet(fact, cflowField)); + arrayVar.appendLoad(entrySuccessInstructions, fact); + + entrySuccessInstructions.append(fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "push", Type.VOID, + new Type[] { objectArrayType }, Constants.INVOKEVIRTUAL)); } } - - InstructionList testInstructions = - munger.getTestInstructions(this, entrySuccessInstructions.getStart(), - range.getRealStart(), - entrySuccessInstructions.getStart()); + InstructionList testInstructions = munger.getTestInstructions(this, entrySuccessInstructions.getStart(), range + .getRealStart(), entrySuccessInstructions.getStart()); entryInstructions.append(testInstructions); entryInstructions.append(entrySuccessInstructions); } - + // this is the same for both per and non-per weaveAfter(new BcelAdvice(null, null, null, 0, 0, 0, null, null) { - public InstructionList getAdviceInstructions( - BcelShadow s, - BcelVar extraArgVar, - InstructionHandle ifNoAdvice) { + public InstructionList getAdviceInstructions(BcelShadow s, BcelVar extraArgVar, InstructionHandle ifNoAdvice) { InstructionList exitInstructions = new InstructionList(); if (munger.hasDynamicTests()) { testResult.appendLoad(exitInstructions, fact); - exitInstructions.append( - InstructionFactory.createBranchInstruction( - Constants.IFEQ, - ifNoAdvice)); + exitInstructions.append(InstructionFactory.createBranchInstruction(Constants.IFEQ, ifNoAdvice)); } exitInstructions.append(Utility.createGet(fact, cflowField)); - if (munger.getKind() != AdviceKind.PerCflowEntry && - munger.getKind() != AdviceKind.PerCflowBelowEntry && - munger.getExposedStateAsBcelVars(false).length==0) { - exitInstructions - .append( - fact - .createInvoke( - NameMangler.CFLOW_COUNTER_TYPE, - "dec", - Type.VOID, - new Type[] { - }, Constants.INVOKEVIRTUAL)); + if (munger.getKind() != AdviceKind.PerCflowEntry && munger.getKind() != AdviceKind.PerCflowBelowEntry + && munger.getExposedStateAsBcelVars(false).length == 0) { + exitInstructions.append(fact.createInvoke(NameMangler.CFLOW_COUNTER_TYPE, "dec", Type.VOID, new Type[] {}, + Constants.INVOKEVIRTUAL)); } else { - exitInstructions - .append( - fact - .createInvoke( - NameMangler.CFLOW_STACK_TYPE, - "pop", - Type.VOID, - new Type[] { - }, Constants.INVOKEVIRTUAL)); + exitInstructions.append(fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "pop", Type.VOID, new Type[] {}, + Constants.INVOKEVIRTUAL)); } return exitInstructions; } }); - - + range.insert(entryInstructions, Range.InsideBefore); } - - /* Implementation notes: - * - * AroundInline still extracts the instructions of the original shadow into - * an extracted method. This allows inlining of even that advice that doesn't - * call proceed or calls proceed more than once. - * - * It extracts the instructions of the original shadow into a method. - * - * Then it extracts the instructions of the advice into a new method defined on - * this enclosing class. This new method can then be specialized as below. - * - * Then it searches in the instructions of the advice for any call to the - * proceed method. - * - * At such a call, there is stuff on the stack representing the arguments to - * proceed. Pop these into the frame. - * - * Now build the stack for the call to the extracted method, taking values - * either from the join point state or from the new frame locs from proceed. - * Now call the extracted method. The right return value should be on the - * stack, so no cast is necessary. - * - * If only one call to proceed is made, we can re-inline the original shadow. - * We are not doing that presently. - * - * If the body of the advice can be determined to not alter the stack, or if - * this shadow doesn't care about the stack, i.e. method-execution, then the - * new method for the advice can also be re-lined. We are not doing that - * presently. - */ - public void weaveAroundInline(BcelAdvice munger,boolean hasDynamicTest) { - + + /* + * Implementation notes: + * + * AroundInline still extracts the instructions of the original shadow into an extracted method. This allows inlining of even + * that advice that doesn't call proceed or calls proceed more than once. + * + * It extracts the instructions of the original shadow into a method. + * + * Then it extracts the instructions of the advice into a new method defined on this enclosing class. This new method can then + * be specialized as below. + * + * Then it searches in the instructions of the advice for any call to the proceed method. + * + * At such a call, there is stuff on the stack representing the arguments to proceed. Pop these into the frame. + * + * Now build the stack for the call to the extracted method, taking values either from the join point state or from the new + * frame locs from proceed. Now call the extracted method. The right return value should be on the stack, so no cast is + * necessary. + * + * If only one call to proceed is made, we can re-inline the original shadow. We are not doing that presently. + * + * If the body of the advice can be determined to not alter the stack, or if this shadow doesn't care about the stack, i.e. + * method-execution, then the new method for the advice can also be re-lined. We are not doing that presently. + */ + public void weaveAroundInline(BcelAdvice munger, boolean hasDynamicTest) { + // !!! THIS BLOCK OF CODE SHOULD BE IN A METHOD CALLED weaveAround(...); - Member mungerSig = munger.getSignature(); - //Member originalSig = mungerSig; // If mungerSig is on a parameterized type, originalSig is the member on the generic type - if (mungerSig instanceof ResolvedMember) { - ResolvedMember rm = (ResolvedMember)mungerSig; - if (rm.hasBackingGenericMember()) mungerSig = rm.getBackingGenericMember(); - } - ResolvedType declaringType = world.resolve(mungerSig.getDeclaringType(),true); - if (declaringType.isMissing()) { - world.getLint().cantFindType.signal( - new String[] {WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE,declaringType.getClassName())}, - getSourceLocation(), - new ISourceLocation[]{ munger.getSourceLocation()} - ); -// IMessage msg = new Message( -// WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE,declaringType.getClassName()), -// "",IMessage.ERROR,getSourceLocation(),null, -// new ISourceLocation[]{ munger.getSourceLocation()}); -// world.getMessageHandler().handleMessage(msg); - } - //??? might want some checks here to give better errors - ResolvedType rt = (declaringType.isParameterizedType()?declaringType.getGenericType():declaringType); - BcelObjectType ot = BcelWorld.getBcelObjectType(rt); -// if (ot==null) { -// world.getMessageHandler().handleMessage( -// MessageUtil.warn("Unable to find modifiable delegate for the aspect '"+rt.getName()+"' containing around advice - cannot implement inlining",munger.getSourceLocation())); -// weaveAroundClosure(munger, hasDynamicTest); -// return; -// } + Member mungerSig = munger.getSignature(); + // Member originalSig = mungerSig; // If mungerSig is on a parameterized type, originalSig is the member on the generic type + if (mungerSig instanceof ResolvedMember) { + ResolvedMember rm = (ResolvedMember) mungerSig; + if (rm.hasBackingGenericMember()) + mungerSig = rm.getBackingGenericMember(); + } + ResolvedType declaringType = world.resolve(mungerSig.getDeclaringType(), true); + if (declaringType.isMissing()) { + world.getLint().cantFindType.signal(new String[] { WeaverMessages.format( + WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE, declaringType.getClassName()) }, getSourceLocation(), + new ISourceLocation[] { munger.getSourceLocation() }); + // IMessage msg = new Message( + // WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE,declaringType.getClassName()), + // "",IMessage.ERROR,getSourceLocation(),null, + // new ISourceLocation[]{ munger.getSourceLocation()}); + // world.getMessageHandler().handleMessage(msg); + } + // ??? might want some checks here to give better errors + ResolvedType rt = (declaringType.isParameterizedType() ? declaringType.getGenericType() : declaringType); + BcelObjectType ot = BcelWorld.getBcelObjectType(rt); + // if (ot==null) { + // world.getMessageHandler().handleMessage( + // MessageUtil.warn("Unable to find modifiable delegate for the aspect '"+rt.getName()+ + // "' containing around advice - cannot implement inlining",munger.getSourceLocation())); + // weaveAroundClosure(munger, hasDynamicTest); + // return; + // } LazyMethodGen adviceMethod = ot.getLazyClassGen().getLazyMethodGen(mungerSig); if (!adviceMethod.getCanInline()) { weaveAroundClosure(munger, hasDynamicTest); return; } - // specific test for @AJ proceedInInners - if (munger.getConcreteAspect().isAnnotationStyleAspect()) { - // if we can't find one proceed() we suspect that the call - // is happening in an inner class so we don't inline it. - // Note: for code style, this is done at Aspect compilation time. - boolean canSeeProceedPassedToOther = false; - InstructionHandle curr = adviceMethod.getBody().getStart(); - InstructionHandle end = adviceMethod.getBody().getEnd(); - ConstantPool cpg = adviceMethod.getEnclosingClass().getConstantPool(); - while (curr != end) { - InstructionHandle next = curr.getNext(); - Instruction inst = curr.getInstruction(); - if ((inst instanceof InvokeInstruction) - && ((InvokeInstruction)inst).getSignature(cpg).indexOf("Lorg/aspectj/lang/ProceedingJoinPoint;") > 0) { - // we may want to refine to exclude stuff returning jp ? - // does code style skip inline if i write dump(thisJoinPoint) ? - canSeeProceedPassedToOther = true;// we see one pjp passed around - dangerous - break; - } - curr = next; - } - if (canSeeProceedPassedToOther) { - // remember this decision to avoid re-analysis - adviceMethod.setCanInline(false); - weaveAroundClosure(munger, hasDynamicTest); - return; - } - } - - + // specific test for @AJ proceedInInners + if (munger.getConcreteAspect().isAnnotationStyleAspect()) { + // if we can't find one proceed() we suspect that the call + // is happening in an inner class so we don't inline it. + // Note: for code style, this is done at Aspect compilation time. + boolean canSeeProceedPassedToOther = false; + InstructionHandle curr = adviceMethod.getBody().getStart(); + InstructionHandle end = adviceMethod.getBody().getEnd(); + ConstantPool cpg = adviceMethod.getEnclosingClass().getConstantPool(); + while (curr != end) { + InstructionHandle next = curr.getNext(); + Instruction inst = curr.getInstruction(); + if ((inst instanceof InvokeInstruction) + && ((InvokeInstruction) inst).getSignature(cpg).indexOf("Lorg/aspectj/lang/ProceedingJoinPoint;") > 0) { + // we may want to refine to exclude stuff returning jp ? + // does code style skip inline if i write dump(thisJoinPoint) ? + canSeeProceedPassedToOther = true;// we see one pjp passed around - dangerous + break; + } + curr = next; + } + if (canSeeProceedPassedToOther) { + // remember this decision to avoid re-analysis + adviceMethod.setCanInline(false); + weaveAroundClosure(munger, hasDynamicTest); + return; + } + } // We can't inline around methods if they have around advice on them, this // is because the weaving will extract the body and hence the proceed call. - //??? should consider optimizations to recognize simple cases that don't require body extraction + // ??? should consider optimizations to recognize simple cases that don't require body extraction enclosingMethod.setCanInline(false); - + // start by exposing various useful things into the frame final InstructionFactory fact = getFactory(); - + // now generate the aroundBody method // eg. "private static final void method_aroundBody0(M, M, String, org.aspectj.lang.JoinPoint)" - LazyMethodGen extractedMethod = - extractMethod( - NameMangler.aroundCallbackMethodName(getSignature(),getEnclosingClass()), - Modifier.PRIVATE, - munger); - - // now extract the advice into its own method - String adviceMethodName = - NameMangler.aroundCallbackMethodName(getSignature(),getEnclosingClass()) + "$advice"; - - List argVarList = new ArrayList(); - List proceedVarList = new ArrayList(); + LazyMethodGen extractedMethod = extractMethod(NameMangler.aroundCallbackMethodName(getSignature(), getEnclosingClass()), + Modifier.PRIVATE, munger); + + // now extract the advice into its own method + String adviceMethodName = NameMangler.aroundCallbackMethodName(getSignature(), getEnclosingClass()) + "$advice"; + + List argVarList = new ArrayList(); + List proceedVarList = new ArrayList(); int extraParamOffset = 0; - + // Create the extra parameters that are needed for passing to proceed // This code is very similar to that found in makeCallToCallback and should // be rationalized in the future - + if (thisVar != null) { argVarList.add(thisVar); proceedVarList.add(new BcelVar(thisVar.getType(), extraParamOffset)); extraParamOffset += thisVar.getType().getSize(); } - + if (targetVar != null && targetVar != thisVar) { argVarList.add(targetVar); proceedVarList.add(new BcelVar(targetVar.getType(), extraParamOffset)); @@ -2352,1205 +2094,1053 @@ public class BcelShadow extends Shadow { proceedVarList.add(new BcelVar(thisJoinPointVar.getType(), extraParamOffset)); extraParamOffset += thisJoinPointVar.getType().getSize(); } - + // We use the munger signature here because it allows for any parameterization of the mungers pointcut that // may have occurred ie. if the pointcut is p(T t) in the super aspect and that has become p(Foo t) in the sub aspect - // then here the munger signature will have 'Foo' as an argument in it whilst the adviceMethod argument type will be 'Object' - since - // it represents the advice method in the superaspect which uses the erasure of the type variable p(Object t) - see pr174449. - - Type[] adviceParameterTypes = - BcelWorld.makeBcelTypes(munger.getSignature().getParameterTypes()); -// adviceMethod.getArgumentTypes(); - adviceMethod.getArgumentTypes(); // forces initialization ... dont like this but seems to be required for some tests to pass, I think that means - // there is a LazyMethodGen method that is not correctly setup to call initialize() when it is invoked - but I dont have - // time right now to discover which - Type[] extractedMethodParameterTypes = extractedMethod.getArgumentTypes(); - Type[] parameterTypes = - new Type[extractedMethodParameterTypes.length - + adviceParameterTypes.length - + 1]; + // then here the munger signature will have 'Foo' as an argument in it whilst the adviceMethod argument type will be + // 'Object' - since + // it represents the advice method in the superaspect which uses the erasure of the type variable p(Object t) - see + // pr174449. + + Type[] adviceParameterTypes = BcelWorld.makeBcelTypes(munger.getSignature().getParameterTypes()); + // adviceMethod.getArgumentTypes(); + adviceMethod.getArgumentTypes(); // forces initialization ... dont like this but seems to be required for some tests to + // pass, I think that means + // there is a LazyMethodGen method that is not correctly setup to call initialize() when it is invoked - but I dont have + // time right now to discover which + Type[] extractedMethodParameterTypes = extractedMethod.getArgumentTypes(); + Type[] parameterTypes = new Type[extractedMethodParameterTypes.length + adviceParameterTypes.length + 1]; int parameterIndex = 0; - System.arraycopy( - extractedMethodParameterTypes, - 0, - parameterTypes, - parameterIndex, - extractedMethodParameterTypes.length); + System.arraycopy(extractedMethodParameterTypes, 0, parameterTypes, parameterIndex, extractedMethodParameterTypes.length); parameterIndex += extractedMethodParameterTypes.length; - parameterTypes[parameterIndex++] = - BcelWorld.makeBcelType(adviceMethod.getEnclosingClass().getType()); - System.arraycopy( - adviceParameterTypes, - 0, - parameterTypes, - parameterIndex, - adviceParameterTypes.length); -// parameterTypes is [Bug, C, org.aspectj.lang.JoinPoint, X, org.aspectj.lang.ProceedingJoinPoint, java.lang.Object, java.lang.Object] - LazyMethodGen localAdviceMethod = - new LazyMethodGen( - Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC, - BcelWorld.makeBcelType(mungerSig.getReturnType()), - adviceMethodName, - parameterTypes, - new String[0], - getEnclosingClass()); - + parameterTypes[parameterIndex++] = BcelWorld.makeBcelType(adviceMethod.getEnclosingClass().getType()); + System.arraycopy(adviceParameterTypes, 0, parameterTypes, parameterIndex, adviceParameterTypes.length); + // parameterTypes is [Bug, C, org.aspectj.lang.JoinPoint, X, org.aspectj.lang.ProceedingJoinPoint, java.lang.Object, + // java.lang.Object] + LazyMethodGen localAdviceMethod = new LazyMethodGen(Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC, BcelWorld + .makeBcelType(mungerSig.getReturnType()), adviceMethodName, parameterTypes, new String[0], getEnclosingClass()); + String donorFileName = adviceMethod.getEnclosingClass().getInternalFileName(); String recipientFileName = getEnclosingClass().getInternalFileName(); -// System.err.println("donor " + donorFileName); -// System.err.println("recip " + recipientFileName); - if (! donorFileName.equals(recipientFileName)) { + // System.err.println("donor " + donorFileName); + // System.err.println("recip " + recipientFileName); + if (!donorFileName.equals(recipientFileName)) { localAdviceMethod.fromFilename = donorFileName; - getEnclosingClass().addInlinedSourceFileInfo( - donorFileName, - adviceMethod.highestLineNumber); + getEnclosingClass().addInlinedSourceFileInfo(donorFileName, adviceMethod.highestLineNumber); } - + getEnclosingClass().addMethodGen(localAdviceMethod); - + // create a map that will move all slots in advice method forward by extraParamOffset // in order to make room for the new proceed-required arguments that are added at // the beginning of the parameter list int nVars = adviceMethod.getMaxLocals() + extraParamOffset; IntMap varMap = IntMap.idMap(nVars); - for (int i=extraParamOffset; i < nVars; i++) { - varMap.put(i-extraParamOffset, i); + for (int i = extraParamOffset; i < nVars; i++) { + varMap.put(i - extraParamOffset, i); } localAdviceMethod.getBody().insert( - BcelClassWeaver.genInlineInstructions(adviceMethod, - localAdviceMethod, varMap, fact, true)); + BcelClassWeaver.genInlineInstructions(adviceMethod, localAdviceMethod, varMap, fact, true)); - - localAdviceMethod.setMaxLocals(nVars); - - //System.err.println(localAdviceMethod); - - - // the shadow is now empty. First, create a correct call - // to the around advice. This includes both the call (which may involve - // value conversion of the advice arguments) and the return - // (which may involve value conversion of the return value). Right now - // we push a null for the unused closure. It's sad, but there it is. - - InstructionList advice = new InstructionList(); - // InstructionHandle adviceMethodInvocation; - { - for (Iterator i = argVarList.iterator(); i.hasNext(); ) { - BcelVar var = (BcelVar)i.next(); + + // System.err.println(localAdviceMethod); + + // the shadow is now empty. First, create a correct call + // to the around advice. This includes both the call (which may involve + // value conversion of the advice arguments) and the return + // (which may involve value conversion of the return value). Right now + // we push a null for the unused closure. It's sad, but there it is. + + InstructionList advice = new InstructionList(); + // InstructionHandle adviceMethodInvocation; + { + for (Iterator i = argVarList.iterator(); i.hasNext();) { + BcelVar var = (BcelVar) i.next(); var.appendLoad(advice, fact); - } - // ??? we don't actually need to push NULL for the closure if we take care - advice.append( - munger.getAdviceArgSetup( - this, - null, - (munger.getConcreteAspect().isAnnotationStyleAspect() && munger.getDeclaringAspect()!=null && munger.getDeclaringAspect().resolve(world).isAnnotationStyleAspect())? - this.loadThisJoinPoint(): - new InstructionList(InstructionConstants.ACONST_NULL))); - // adviceMethodInvocation = - advice.append( - Utility.createInvoke(fact, localAdviceMethod)); //(fact, getWorld(), munger.getSignature())); - advice.append( - Utility.createConversion( - getFactory(), - BcelWorld.makeBcelType(mungerSig.getReturnType()), - extractedMethod.getReturnType(),world.isInJava5Mode())); - if (! isFallsThrough()) { - advice.append(InstructionFactory.createReturn(extractedMethod.getReturnType())); - } - } - + } + // ??? we don't actually need to push NULL for the closure if we take care + advice.append(munger.getAdviceArgSetup(this, null, + (munger.getConcreteAspect().isAnnotationStyleAspect() && munger.getDeclaringAspect() != null && munger + .getDeclaringAspect().resolve(world).isAnnotationStyleAspect()) ? this.loadThisJoinPoint() + : new InstructionList(InstructionConstants.ACONST_NULL))); + // adviceMethodInvocation = + advice.append(Utility.createInvoke(fact, localAdviceMethod)); // (fact, getWorld(), munger.getSignature())); + advice.append(Utility.createConversion(getFactory(), BcelWorld.makeBcelType(mungerSig.getReturnType()), extractedMethod + .getReturnType(), world.isInJava5Mode())); + if (!isFallsThrough()) { + advice.append(InstructionFactory.createReturn(extractedMethod.getReturnType())); + } + } + // now, situate the call inside the possible dynamic tests, // and actually add the whole mess to the shadow - if (! hasDynamicTest) { - range.append(advice); - } else { - InstructionList afterThingie = new InstructionList(InstructionConstants.NOP); - InstructionList callback = makeCallToCallback(extractedMethod); + if (!hasDynamicTest) { + range.append(advice); + } else { + InstructionList afterThingie = new InstructionList(InstructionConstants.NOP); + InstructionList callback = makeCallToCallback(extractedMethod); if (terminatesWithReturn()) { - callback.append( - InstructionFactory.createReturn(extractedMethod.getReturnType())); + callback.append(InstructionFactory.createReturn(extractedMethod.getReturnType())); } else { - //InstructionHandle endNop = range.insert(fact.NOP, Range.InsideAfter); - advice.append( - InstructionFactory.createBranchInstruction( - Constants.GOTO, - afterThingie.getStart())); + // InstructionHandle endNop = range.insert(fact.NOP, Range.InsideAfter); + advice.append(InstructionFactory.createBranchInstruction(Constants.GOTO, afterThingie.getStart())); } - range.append( - munger.getTestInstructions( - this, - advice.getStart(), - callback.getStart(), - advice.getStart())); - range.append(advice); - range.append(callback); - range.append(afterThingie); - } - - - // now search through the advice, looking for a call to PROCEED. - // Then we replace the call to proceed with some argument setup, and a - // call to the extracted method. - - // inlining support for code style aspects - if (!munger.getDeclaringType().isAnnotationStyleAspect()) { - String proceedName = - NameMangler.proceedMethodName(munger.getSignature().getName()); - - InstructionHandle curr = localAdviceMethod.getBody().getStart(); - InstructionHandle end = localAdviceMethod.getBody().getEnd(); - ConstantPool cpg = localAdviceMethod.getEnclosingClass().getConstantPool(); - while (curr != end) { - InstructionHandle next = curr.getNext(); - Instruction inst = curr.getInstruction(); - if ((inst.opcode==Constants.INVOKESTATIC) - && proceedName.equals(((InvokeInstruction) inst).getMethodName(cpg))) { - - localAdviceMethod.getBody().append( - curr, - getRedoneProceedCall( - fact, - extractedMethod, - munger, - localAdviceMethod, - proceedVarList)); - Utility.deleteInstruction(curr, localAdviceMethod); - } - curr = next; - } - // and that's it. - } else { - //ATAJ inlining support for @AJ aspects - // [TODO document @AJ code rule: don't manipulate 2 jps proceed at the same time.. in an advice body] - InstructionHandle curr = localAdviceMethod.getBody().getStart(); - InstructionHandle end = localAdviceMethod.getBody().getEnd(); - ConstantPool cpg = localAdviceMethod.getEnclosingClass().getConstantPool(); - while (curr != end) { - InstructionHandle next = curr.getNext(); - Instruction inst = curr.getInstruction(); - if ((inst instanceof INVOKEINTERFACE) - && "proceed".equals(((INVOKEINTERFACE) inst).getMethodName(cpg))) { - final boolean isProceedWithArgs; - if (((INVOKEINTERFACE) inst).getArgumentTypes(cpg).length == 1) { - // proceed with args as a boxed Object[] - isProceedWithArgs = true; - } else { - isProceedWithArgs = false; - } - InstructionList insteadProceedIl = getRedoneProceedCallForAnnotationStyle( - fact, - extractedMethod, - munger, - localAdviceMethod, - proceedVarList, - isProceedWithArgs - ); - localAdviceMethod.getBody().append(curr, insteadProceedIl); - Utility.deleteInstruction(curr, localAdviceMethod); - } - curr = next; - } - } - } - - private InstructionList getRedoneProceedCall( - InstructionFactory fact, - LazyMethodGen callbackMethod, - BcelAdvice munger, - LazyMethodGen localAdviceMethod, - List argVarList) - { + range.append(munger.getTestInstructions(this, advice.getStart(), callback.getStart(), advice.getStart())); + range.append(advice); + range.append(callback); + range.append(afterThingie); + } + + // now search through the advice, looking for a call to PROCEED. + // Then we replace the call to proceed with some argument setup, and a + // call to the extracted method. + + // inlining support for code style aspects + if (!munger.getDeclaringType().isAnnotationStyleAspect()) { + String proceedName = NameMangler.proceedMethodName(munger.getSignature().getName()); + + InstructionHandle curr = localAdviceMethod.getBody().getStart(); + InstructionHandle end = localAdviceMethod.getBody().getEnd(); + ConstantPool cpg = localAdviceMethod.getEnclosingClass().getConstantPool(); + while (curr != end) { + InstructionHandle next = curr.getNext(); + Instruction inst = curr.getInstruction(); + if ((inst.opcode == Constants.INVOKESTATIC) && proceedName.equals(((InvokeInstruction) inst).getMethodName(cpg))) { + + localAdviceMethod.getBody().append(curr, + getRedoneProceedCall(fact, extractedMethod, munger, localAdviceMethod, proceedVarList)); + Utility.deleteInstruction(curr, localAdviceMethod); + } + curr = next; + } + // and that's it. + } else { + // ATAJ inlining support for @AJ aspects + // [TODO document @AJ code rule: don't manipulate 2 jps proceed at the same time.. in an advice body] + InstructionHandle curr = localAdviceMethod.getBody().getStart(); + InstructionHandle end = localAdviceMethod.getBody().getEnd(); + ConstantPool cpg = localAdviceMethod.getEnclosingClass().getConstantPool(); + while (curr != end) { + InstructionHandle next = curr.getNext(); + Instruction inst = curr.getInstruction(); + if ((inst instanceof INVOKEINTERFACE) && "proceed".equals(((INVOKEINTERFACE) inst).getMethodName(cpg))) { + final boolean isProceedWithArgs; + if (((INVOKEINTERFACE) inst).getArgumentTypes(cpg).length == 1) { + // proceed with args as a boxed Object[] + isProceedWithArgs = true; + } else { + isProceedWithArgs = false; + } + InstructionList insteadProceedIl = getRedoneProceedCallForAnnotationStyle(fact, extractedMethod, munger, + localAdviceMethod, proceedVarList, isProceedWithArgs); + localAdviceMethod.getBody().append(curr, insteadProceedIl); + Utility.deleteInstruction(curr, localAdviceMethod); + } + curr = next; + } + } + } + + private InstructionList getRedoneProceedCall(InstructionFactory fact, LazyMethodGen callbackMethod, BcelAdvice munger, + LazyMethodGen localAdviceMethod, List argVarList) { InstructionList ret = new InstructionList(); // we have on stack all the arguments for the ADVICE call. // we have in frame somewhere all the arguments for the non-advice call. - + BcelVar[] adviceVars = munger.getExposedStateAsBcelVars(true); - IntMap proceedMap = makeProceedArgumentMap(adviceVars); + IntMap proceedMap = makeProceedArgumentMap(adviceVars); + + // System.out.println(proceedMap + " for " + this); + // System.out.println(argVarList); -// System.out.println(proceedMap + " for " + this); -// System.out.println(argVarList); - - ResolvedType[] proceedParamTypes = - world.resolve(munger.getSignature().getParameterTypes()); + ResolvedType[] proceedParamTypes = world.resolve(munger.getSignature().getParameterTypes()); // remove this*JoinPoint* as arguments to proceed - if (munger.getBaseParameterCount()+1 < proceedParamTypes.length) { - int len = munger.getBaseParameterCount()+1; + if (munger.getBaseParameterCount() + 1 < proceedParamTypes.length) { + int len = munger.getBaseParameterCount() + 1; ResolvedType[] newTypes = new ResolvedType[len]; System.arraycopy(proceedParamTypes, 0, newTypes, 0, len); proceedParamTypes = newTypes; } - //System.out.println("stateTypes: " + Arrays.asList(stateTypes)); - BcelVar[] proceedVars = - Utility.pushAndReturnArrayOfVars(proceedParamTypes, ret, fact, localAdviceMethod); + // System.out.println("stateTypes: " + Arrays.asList(stateTypes)); + BcelVar[] proceedVars = Utility.pushAndReturnArrayOfVars(proceedParamTypes, ret, fact, localAdviceMethod); Type[] stateTypes = callbackMethod.getArgumentTypes(); -// System.out.println("stateTypes: " + Arrays.asList(stateTypes)); - - for (int i=0, len=stateTypes.length; i < len; i++) { - Type stateType = stateTypes[i]; - ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world); - if (proceedMap.hasKey(i)) { - //throw new RuntimeException("unimplemented"); + // System.out.println("stateTypes: " + Arrays.asList(stateTypes)); + + for (int i = 0, len = stateTypes.length; i < len; i++) { + Type stateType = stateTypes[i]; + ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world); + if (proceedMap.hasKey(i)) { + // throw new RuntimeException("unimplemented"); proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX); - } else { + } else { ((BcelVar) argVarList.get(i)).appendLoad(ret, fact); - } + } + } + + ret.append(Utility.createInvoke(fact, callbackMethod)); + ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), BcelWorld.makeBcelType(munger.getSignature() + .getReturnType()))); + return ret; + } + + // private static boolean bindsThisOrTarget(Pointcut pointcut) { + // ThisTargetFinder visitor = new ThisTargetFinder(); + // pointcut.accept(visitor, null); + // return visitor.bindsThisOrTarget; + // } + + // private static class ThisTargetFinder extends IdentityPointcutVisitor { + // boolean bindsThisOrTarget = false; + // + // public Object visit(ThisOrTargetPointcut node, Object data) { + // if (node.isBinding()) { + // bindsThisOrTarget = true; + // } + // return node; + // } + // + // public Object visit(AndPointcut node, Object data) { + // if (!bindsThisOrTarget) node.getLeft().accept(this, data); + // if (!bindsThisOrTarget) node.getRight().accept(this, data); + // return node; + // } + // + // public Object visit(NotPointcut node, Object data) { + // if (!bindsThisOrTarget) node.getNegatedPointcut().accept(this, data); + // return node; + // } + // + // public Object visit(OrPointcut node, Object data) { + // if (!bindsThisOrTarget) node.getLeft().accept(this, data); + // if (!bindsThisOrTarget) node.getRight().accept(this, data); + // return node; + // } + // } + + /** + * Annotation style handling for inlining. + * + * Note: The proceedingjoinpoint is already on the stack (since the user was calling pjp.proceed(...) + * + * The proceed map is ignored (in terms of argument repositioning) since we have a fixed expected format for annotation style. + * The aim here is to change the proceed() call into a call to the xxx_aroundBody0 method. + * + * + */ + private InstructionList getRedoneProceedCallForAnnotationStyle(InstructionFactory fact, LazyMethodGen callbackMethod, + BcelAdvice munger, LazyMethodGen localAdviceMethod, List argVarList, boolean isProceedWithArgs) { + InstructionList ret = new InstructionList(); + + // store the Object[] array on stack if proceed with args + if (isProceedWithArgs) { + + // STORE the Object[] into a local variable + Type objectArrayType = Type.OBJECT_ARRAY; + int theObjectArrayLocalNumber = localAdviceMethod.allocateLocal(objectArrayType); + ret.append(InstructionFactory.createStore(objectArrayType, theObjectArrayLocalNumber)); + + // STORE the ProceedingJoinPoint instance into a local variable + Type proceedingJpType = Type.getType("Lorg/aspectj/lang/ProceedingJoinPoint;"); + int pjpLocalNumber = localAdviceMethod.allocateLocal(proceedingJpType); + ret.append(InstructionFactory.createStore(proceedingJpType, pjpLocalNumber)); + + // Aim here initially is to determine whether the user will have provided a new + // this/target in the object array and consume them if they have, leaving us the rest of + // the arguments to process as regular arguments to the invocation at the original join point + + boolean pointcutBindsThis = bindsThis(munger); + boolean pointcutBindsTarget = bindsTarget(munger); + boolean targetIsSameAsThis = getKind().isTargetSameAsThis(); + + int nextArgumentToProvideForCallback = 0; + + if (hasThis()) { + if (!(pointcutBindsTarget && targetIsSameAsThis)) { + if (pointcutBindsThis) { + // they have supplied new this as first entry in object array, consume it + ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber)); + ret.append(Utility.createConstant(fact, 0)); + ret.append(InstructionFactory.createArrayLoad(Type.OBJECT)); + ret.append(Utility.createConversion(fact, Type.OBJECT, callbackMethod.getArgumentTypes()[0])); + } else { + // use local variable 0 + ret.append(InstructionFactory.createALOAD(0)); + } + nextArgumentToProvideForCallback++; + } + } + + if (hasTarget()) { + if (pointcutBindsTarget) { + if (getKind().isTargetSameAsThis()) { + ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber)); + ret.append(Utility.createConstant(fact, pointcutBindsThis ? 1 : 0)); + ret.append(InstructionFactory.createArrayLoad(Type.OBJECT)); + ret.append(Utility.createConversion(fact, Type.OBJECT, callbackMethod.getArgumentTypes()[0])); + } else { + int position = (hasThis() && pointcutBindsThis ? 1 : 0); + ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber)); + ret.append(Utility.createConstant(fact, position)); + ret.append(InstructionFactory.createArrayLoad(Type.OBJECT)); + ret.append(Utility.createConversion(fact, Type.OBJECT, callbackMethod.getArgumentTypes()[position])); + } + nextArgumentToProvideForCallback++; + } else { + if (getKind().isTargetSameAsThis()) { + // ret.append(new ALOAD(0)); + } else { + ret.append(InstructionFactory.createLoad(localAdviceMethod.getArgumentTypes()[0], hasThis() ? 1 : 0)); + nextArgumentToProvideForCallback++; + } + } + } + + // Where to start in the object array in order to pick up arguments + int indexIntoObjectArrayForArguments = (pointcutBindsThis ? 1 : 0) + (pointcutBindsTarget ? 1 : 0); + + int len = callbackMethod.getArgumentTypes().length; + for (int i = nextArgumentToProvideForCallback; i < len; i++) { + Type stateType = callbackMethod.getArgumentTypes()[i]; + BcelWorld.fromBcel(stateType).resolve(world); + if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) { + ret.append(new InstructionLV(Constants.ALOAD, pjpLocalNumber)); + } else { + ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber)); + ret.append(Utility + .createConstant(fact, i - nextArgumentToProvideForCallback + indexIntoObjectArrayForArguments)); + ret.append(InstructionFactory.createArrayLoad(Type.OBJECT)); + ret.append(Utility.createConversion(fact, Type.OBJECT, stateType)); + } + } + + } else { + Type proceedingJpType = Type.getType("Lorg/aspectj/lang/ProceedingJoinPoint;"); + int localJp = localAdviceMethod.allocateLocal(proceedingJpType); + ret.append(InstructionFactory.createStore(proceedingJpType, localJp)); + + for (int i = 0, len = callbackMethod.getArgumentTypes().length; i < len; i++) { + Type stateType = callbackMethod.getArgumentTypes()[i]; + /* ResolvedType stateTypeX = */ + BcelWorld.fromBcel(stateType).resolve(world); + if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) { + ret.append(InstructionFactory.createALOAD(localJp));// from localAdvice signature + // } else if ("Lorg/aspectj/lang/ProceedingJoinPoint;".equals(stateType.getSignature())) { + // //FIXME ALEX? + // ret.append(new ALOAD(localJp));// from localAdvice signature + // // ret.append(fact.createCheckCast( + // // (ReferenceType) BcelWorld.makeBcelType(stateTypeX) + // // )); + // // cast ? + // + } else { + ret.append(InstructionFactory.createLoad(stateType, i)); + } + } } - + + // do the callback invoke ret.append(Utility.createInvoke(fact, callbackMethod)); - ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), - BcelWorld.makeBcelType(munger.getSignature().getReturnType()))); + + // box it again. Handles cases where around advice does return something else than Object + if (!UnresolvedType.OBJECT.equals(munger.getSignature().getReturnType())) { + ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), Type.OBJECT)); + } + ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), BcelWorld.makeBcelType(munger.getSignature() + .getReturnType()))); + return ret; + + // + // + // + // if (proceedMap.hasKey(i)) { + // ret.append(new ALOAD(i)); + // //throw new RuntimeException("unimplemented"); + // //proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX); + // } else { + // //((BcelVar) argVarList.get(i)).appendLoad(ret, fact); + // //ret.append(new ALOAD(i)); + // if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) { + // ret.append(new ALOAD(i)); + // } else { + // ret.append(new ALOAD(i)); + // } + // } + // } + // + // ret.append(Utility.createInvoke(fact, callbackMethod)); + // ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), + // BcelWorld.makeBcelType(munger.getSignature().getReturnType()))); + // + // //ret.append(new ACONST_NULL());//will be POPed + // if (true) return ret; + // + // + // + // // we have on stack all the arguments for the ADVICE call. + // // we have in frame somewhere all the arguments for the non-advice call. + // + // BcelVar[] adviceVars = munger.getExposedStateAsBcelVars(); + // IntMap proceedMap = makeProceedArgumentMap(adviceVars); + // + // System.out.println(proceedMap + " for " + this); + // System.out.println(argVarList); + // + // ResolvedType[] proceedParamTypes = + // world.resolve(munger.getSignature().getParameterTypes()); + // // remove this*JoinPoint* as arguments to proceed + // if (munger.getBaseParameterCount()+1 < proceedParamTypes.length) { + // int len = munger.getBaseParameterCount()+1; + // ResolvedType[] newTypes = new ResolvedType[len]; + // System.arraycopy(proceedParamTypes, 0, newTypes, 0, len); + // proceedParamTypes = newTypes; + // } + // + // //System.out.println("stateTypes: " + Arrays.asList(stateTypes)); + // BcelVar[] proceedVars = + // Utility.pushAndReturnArrayOfVars(proceedParamTypes, ret, fact, localAdviceMethod); + // + // Type[] stateTypes = callbackMethod.getArgumentTypes(); + // // System.out.println("stateTypes: " + Arrays.asList(stateTypes)); + // + // for (int i=0, len=stateTypes.length; i < len; i++) { + // Type stateType = stateTypes[i]; + // ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world); + // if (proceedMap.hasKey(i)) { + // //throw new RuntimeException("unimplemented"); + // proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX); + // } else { + // ((BcelVar) argVarList.get(i)).appendLoad(ret, fact); + // } + // } + // + // ret.append(Utility.createInvoke(fact, callbackMethod)); + // ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), + // BcelWorld.makeBcelType(munger.getSignature().getReturnType()))); + // return ret; } - -// private static boolean bindsThisOrTarget(Pointcut pointcut) { -// ThisTargetFinder visitor = new ThisTargetFinder(); -// pointcut.accept(visitor, null); -// return visitor.bindsThisOrTarget; -// } - -// private static class ThisTargetFinder extends IdentityPointcutVisitor { -// boolean bindsThisOrTarget = false; -// -// public Object visit(ThisOrTargetPointcut node, Object data) { -// if (node.isBinding()) { -// bindsThisOrTarget = true; -// } -// return node; -// } -// -// public Object visit(AndPointcut node, Object data) { -// if (!bindsThisOrTarget) node.getLeft().accept(this, data); -// if (!bindsThisOrTarget) node.getRight().accept(this, data); -// return node; -// } -// -// public Object visit(NotPointcut node, Object data) { -// if (!bindsThisOrTarget) node.getNegatedPointcut().accept(this, data); -// return node; -// } -// -// public Object visit(OrPointcut node, Object data) { -// if (!bindsThisOrTarget) node.getLeft().accept(this, data); -// if (!bindsThisOrTarget) node.getRight().accept(this, data); -// return node; -// } -// } - - - /** - * Annotation style handling for inlining. - * - * Note: - * The proceedingjoinpoint is already on the stack (since the user was calling pjp.proceed(...) - * - * The proceed map is ignored (in terms of argument repositioning) since we have a fixed expected - * format for annotation style. The aim here is to change the proceed() call into a call to - * the xxx_aroundBody0 method. - * - * - */ - private InstructionList getRedoneProceedCallForAnnotationStyle( - InstructionFactory fact, - LazyMethodGen callbackMethod, - BcelAdvice munger, - LazyMethodGen localAdviceMethod, - List argVarList, - boolean isProceedWithArgs) - { - InstructionList ret = new InstructionList(); - - // store the Object[] array on stack if proceed with args - if (isProceedWithArgs) { - - // STORE the Object[] into a local variable - Type objectArrayType = Type.OBJECT_ARRAY; - int theObjectArrayLocalNumber = localAdviceMethod.allocateLocal(objectArrayType); - ret.append(InstructionFactory.createStore(objectArrayType, theObjectArrayLocalNumber)); - - // STORE the ProceedingJoinPoint instance into a local variable - Type proceedingJpType = Type.getType("Lorg/aspectj/lang/ProceedingJoinPoint;"); - int pjpLocalNumber = localAdviceMethod.allocateLocal(proceedingJpType); - ret.append(InstructionFactory.createStore(proceedingJpType, pjpLocalNumber)); - - // Aim here initially is to determine whether the user will have provided a new - // this/target in the object array and consume them if they have, leaving us the rest of - // the arguments to process as regular arguments to the invocation at the original join point - - boolean pointcutBindsThis = bindsThis(munger); - boolean pointcutBindsTarget = bindsTarget(munger); - boolean targetIsSameAsThis = getKind().isTargetSameAsThis(); - - int nextArgumentToProvideForCallback = 0; - - if (hasThis() ) { - if (!(pointcutBindsTarget && targetIsSameAsThis)) { - if (pointcutBindsThis) { - // they have supplied new this as first entry in object array, consume it - ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber)); - ret.append(Utility.createConstant(fact, 0)); - ret.append(InstructionFactory.createArrayLoad(Type.OBJECT)); - ret.append(Utility.createConversion(fact,Type.OBJECT,callbackMethod.getArgumentTypes()[0])); - } else { - // use local variable 0 - ret.append(InstructionFactory.createALOAD(0)); - } - nextArgumentToProvideForCallback++; - } - } - - - - if (hasTarget()) { - if (pointcutBindsTarget) { - if (getKind().isTargetSameAsThis()) { - ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber)); - ret.append(Utility.createConstant(fact, pointcutBindsThis?1:0)); - ret.append(InstructionFactory.createArrayLoad(Type.OBJECT)); - ret.append(Utility.createConversion(fact,Type.OBJECT,callbackMethod.getArgumentTypes()[0])); - } else { - int position =(hasThis()&& pointcutBindsThis?1:0); - ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber)); - ret.append(Utility.createConstant(fact, position)); - ret.append(InstructionFactory.createArrayLoad(Type.OBJECT)); - ret.append(Utility.createConversion(fact,Type.OBJECT,callbackMethod.getArgumentTypes()[position])); - } - nextArgumentToProvideForCallback++; - } else { - if (getKind().isTargetSameAsThis()) { - //ret.append(new ALOAD(0)); - } else { - ret.append(InstructionFactory.createLoad(localAdviceMethod.getArgumentTypes()[0],hasThis()?1:0)); - nextArgumentToProvideForCallback++; - } - } - } - - // Where to start in the object array in order to pick up arguments - int indexIntoObjectArrayForArguments = (pointcutBindsThis?1:0)+(pointcutBindsTarget?1:0); - - int len = callbackMethod.getArgumentTypes().length; - for (int i = nextArgumentToProvideForCallback; i < len; i++) { - Type stateType = callbackMethod.getArgumentTypes()[i]; - BcelWorld.fromBcel(stateType).resolve(world); - if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) { - ret.append(new InstructionLV(Constants.ALOAD, pjpLocalNumber)); - } else { - ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber)); - ret.append(Utility.createConstant(fact, i-nextArgumentToProvideForCallback+indexIntoObjectArrayForArguments)); - ret.append(InstructionFactory.createArrayLoad(Type.OBJECT)); - ret.append(Utility.createConversion(fact, Type.OBJECT, stateType)); - } - } - - } else { - Type proceedingJpType = Type.getType("Lorg/aspectj/lang/ProceedingJoinPoint;"); - int localJp = localAdviceMethod.allocateLocal(proceedingJpType); - ret.append(InstructionFactory.createStore(proceedingJpType, localJp)); - - for (int i = 0, len=callbackMethod.getArgumentTypes().length; i < len; i++) { - Type stateType = callbackMethod.getArgumentTypes()[i]; - /*ResolvedType stateTypeX =*/ - BcelWorld.fromBcel(stateType).resolve(world); - if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) { - ret.append(InstructionFactory.createALOAD(localJp));// from localAdvice signature -// } else if ("Lorg/aspectj/lang/ProceedingJoinPoint;".equals(stateType.getSignature())) { -// //FIXME ALEX? -// ret.append(new ALOAD(localJp));// from localAdvice signature -//// ret.append(fact.createCheckCast( -//// (ReferenceType) BcelWorld.makeBcelType(stateTypeX) -//// )); -// // cast ? -// - } else { - ret.append(InstructionFactory.createLoad(stateType, i)); - } - } - } - - // do the callback invoke - ret.append(Utility.createInvoke(fact, callbackMethod)); - - // box it again. Handles cases where around advice does return something else than Object - if (!UnresolvedType.OBJECT.equals(munger.getSignature().getReturnType())) { - ret.append(Utility.createConversion( - fact, - callbackMethod.getReturnType(), - Type.OBJECT - )); - } - ret.append(Utility.createConversion( - fact, - callbackMethod.getReturnType(), - BcelWorld.makeBcelType(munger.getSignature().getReturnType()) - )); - - return ret; - -// -// -// -// if (proceedMap.hasKey(i)) { -// ret.append(new ALOAD(i)); -// //throw new RuntimeException("unimplemented"); -// //proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX); -// } else { -// //((BcelVar) argVarList.get(i)).appendLoad(ret, fact); -// //ret.append(new ALOAD(i)); -// if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) { -// ret.append(new ALOAD(i)); -// } else { -// ret.append(new ALOAD(i)); -// } -// } -// } -// -// ret.append(Utility.createInvoke(fact, callbackMethod)); -// ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), -// BcelWorld.makeBcelType(munger.getSignature().getReturnType()))); -// -// //ret.append(new ACONST_NULL());//will be POPed -// if (true) return ret; -// -// -// -// // we have on stack all the arguments for the ADVICE call. -// // we have in frame somewhere all the arguments for the non-advice call. -// -// BcelVar[] adviceVars = munger.getExposedStateAsBcelVars(); -// IntMap proceedMap = makeProceedArgumentMap(adviceVars); -// -// System.out.println(proceedMap + " for " + this); -// System.out.println(argVarList); -// -// ResolvedType[] proceedParamTypes = -// world.resolve(munger.getSignature().getParameterTypes()); -// // remove this*JoinPoint* as arguments to proceed -// if (munger.getBaseParameterCount()+1 < proceedParamTypes.length) { -// int len = munger.getBaseParameterCount()+1; -// ResolvedType[] newTypes = new ResolvedType[len]; -// System.arraycopy(proceedParamTypes, 0, newTypes, 0, len); -// proceedParamTypes = newTypes; -// } -// -// //System.out.println("stateTypes: " + Arrays.asList(stateTypes)); -// BcelVar[] proceedVars = -// Utility.pushAndReturnArrayOfVars(proceedParamTypes, ret, fact, localAdviceMethod); -// -// Type[] stateTypes = callbackMethod.getArgumentTypes(); -//// System.out.println("stateTypes: " + Arrays.asList(stateTypes)); -// -// for (int i=0, len=stateTypes.length; i < len; i++) { -// Type stateType = stateTypes[i]; -// ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world); -// if (proceedMap.hasKey(i)) { -// //throw new RuntimeException("unimplemented"); -// proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX); -// } else { -// ((BcelVar) argVarList.get(i)).appendLoad(ret, fact); -// } -// } -// -// ret.append(Utility.createInvoke(fact, callbackMethod)); -// ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), -// BcelWorld.makeBcelType(munger.getSignature().getReturnType()))); -// return ret; - } - - private boolean bindsThis(BcelAdvice munger) { - UsesThisVisitor utv = new UsesThisVisitor(); - munger.getPointcut().accept(utv, null); + + private boolean bindsThis(BcelAdvice munger) { + UsesThisVisitor utv = new UsesThisVisitor(); + munger.getPointcut().accept(utv, null); return utv.usesThis; } - private boolean bindsTarget(BcelAdvice munger) { - UsesTargetVisitor utv = new UsesTargetVisitor(); - munger.getPointcut().accept(utv, null); + private boolean bindsTarget(BcelAdvice munger) { + UsesTargetVisitor utv = new UsesTargetVisitor(); + munger.getPointcut().accept(utv, null); return utv.usesTarget; } - - private static class UsesThisVisitor extends IdentityPointcutVisitor { - boolean usesThis = false; - - public Object visit(ThisOrTargetPointcut node, Object data) { - if (node.isThis() && node.isBinding()) usesThis=true; - return node; - } - - public Object visit(AndPointcut node, Object data) { - if (!usesThis) node.getLeft().accept(this, data); - if (!usesThis) node.getRight().accept(this, data); - return node; - } - - public Object visit(NotPointcut node, Object data) { - if (!usesThis) node.getNegatedPointcut().accept(this, data); - return node; - } - - public Object visit(OrPointcut node, Object data) { - if (!usesThis) node.getLeft().accept(this, data); - if (!usesThis) node.getRight().accept(this, data); - return node; - } - } - - - private static class UsesTargetVisitor extends IdentityPointcutVisitor { - boolean usesTarget = false; - - public Object visit(ThisOrTargetPointcut node, Object data) { - if (!node.isThis() && node.isBinding()) usesTarget=true; - return node; - } - - public Object visit(AndPointcut node, Object data) { - if (!usesTarget) node.getLeft().accept(this, data); - if (!usesTarget) node.getRight().accept(this, data); - return node; - } - - public Object visit(NotPointcut node, Object data) { - if (!usesTarget) node.getNegatedPointcut().accept(this, data); - return node; - } - - public Object visit(OrPointcut node, Object data) { - if (!usesTarget) node.getLeft().accept(this, data); - if (!usesTarget) node.getRight().accept(this, data); - return node; - } - } + + private static class UsesThisVisitor extends AbstractPatternNodeVisitor { + boolean usesThis = false; + + public Object visit(ThisOrTargetPointcut node, Object data) { + if (node.isThis() && node.isBinding()) + usesThis = true; + return node; + } + + public Object visit(AndPointcut node, Object data) { + if (!usesThis) + node.getLeft().accept(this, data); + if (!usesThis) + node.getRight().accept(this, data); + return node; + } + + public Object visit(NotPointcut node, Object data) { + if (!usesThis) + node.getNegatedPointcut().accept(this, data); + return node; + } + + public Object visit(OrPointcut node, Object data) { + if (!usesThis) + node.getLeft().accept(this, data); + if (!usesThis) + node.getRight().accept(this, data); + return node; + } + } + + private static class UsesTargetVisitor extends AbstractPatternNodeVisitor { + boolean usesTarget = false; + + public Object visit(ThisOrTargetPointcut node, Object data) { + if (!node.isThis() && node.isBinding()) + usesTarget = true; + return node; + } + + public Object visit(AndPointcut node, Object data) { + if (!usesTarget) + node.getLeft().accept(this, data); + if (!usesTarget) + node.getRight().accept(this, data); + return node; + } + + public Object visit(NotPointcut node, Object data) { + if (!usesTarget) + node.getNegatedPointcut().accept(this, data); + return node; + } + + public Object visit(OrPointcut node, Object data) { + if (!usesTarget) + node.getLeft().accept(this, data); + if (!usesTarget) + node.getRight().accept(this, data); + return node; + } + } public void weaveAroundClosure(BcelAdvice munger, boolean hasDynamicTest) { - InstructionFactory fact = getFactory(); + InstructionFactory fact = getFactory(); enclosingMethod.setCanInline(false); int linenumber = getSourceLine(); - // MOVE OUT ALL THE INSTRUCTIONS IN MY SHADOW INTO ANOTHER METHOD! - LazyMethodGen callbackMethod = - extractMethod( - NameMangler.aroundCallbackMethodName( - getSignature(), - getEnclosingClass()), - 0, - munger); - - BcelVar[] adviceVars = munger.getExposedStateAsBcelVars(true); - - String closureClassName = - NameMangler.makeClosureClassName( - getEnclosingClass().getType(), - getEnclosingClass().getNewGeneratedNameTag()); - - Member constructorSig = new MemberImpl(Member.CONSTRUCTOR, - UnresolvedType.forName(closureClassName), 0, "<init>", - "([Ljava/lang/Object;)V"); - - BcelVar closureHolder = null; - - // This is not being used currently since getKind() == preinitializaiton - // cannot happen in around advice - if (getKind() == PreInitialization) { - closureHolder = genTempVar(AjcMemberMaker.AROUND_CLOSURE_TYPE); - } - - InstructionList closureInstantiation = - makeClosureInstantiation(constructorSig, closureHolder); - - /*LazyMethodGen constructor = */ - makeClosureClassAndReturnConstructor( - closureClassName, - callbackMethod, - makeProceedArgumentMap(adviceVars) - ); - - InstructionList returnConversionCode; + // MOVE OUT ALL THE INSTRUCTIONS IN MY SHADOW INTO ANOTHER METHOD! + LazyMethodGen callbackMethod = extractMethod(NameMangler.aroundCallbackMethodName(getSignature(), getEnclosingClass()), 0, + munger); + + BcelVar[] adviceVars = munger.getExposedStateAsBcelVars(true); + + String closureClassName = NameMangler.makeClosureClassName(getEnclosingClass().getType(), getEnclosingClass() + .getNewGeneratedNameTag()); + + Member constructorSig = new MemberImpl(Member.CONSTRUCTOR, UnresolvedType.forName(closureClassName), 0, "<init>", + "([Ljava/lang/Object;)V"); + + BcelVar closureHolder = null; + + // This is not being used currently since getKind() == preinitializaiton + // cannot happen in around advice + if (getKind() == PreInitialization) { + closureHolder = genTempVar(AjcMemberMaker.AROUND_CLOSURE_TYPE); + } + + InstructionList closureInstantiation = makeClosureInstantiation(constructorSig, closureHolder); + + /* LazyMethodGen constructor = */ + makeClosureClassAndReturnConstructor(closureClassName, callbackMethod, makeProceedArgumentMap(adviceVars)); + + InstructionList returnConversionCode; if (getKind() == PreInitialization) { returnConversionCode = new InstructionList(); - + BcelVar stateTempVar = genTempVar(UnresolvedType.OBJECTARRAY); closureHolder.appendLoad(returnConversionCode, fact); - - returnConversionCode.append( - Utility.createInvoke( - fact, - world, - AjcMemberMaker.aroundClosurePreInitializationGetter())); + + returnConversionCode.append(Utility.createInvoke(fact, world, AjcMemberMaker.aroundClosurePreInitializationGetter())); stateTempVar.appendStore(returnConversionCode, fact); - + Type[] stateTypes = getSuperConstructorParameterTypes(); - + returnConversionCode.append(InstructionConstants.ALOAD_0); // put "this" back on the stack for (int i = 0, len = stateTypes.length; i < len; i++) { - UnresolvedType bcelTX = BcelWorld.fromBcel(stateTypes[i]); - ResolvedType stateRTX = world.resolve(bcelTX,true); - if (stateRTX.isMissing()) { - world.getLint().cantFindType.signal( - new String[] {WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE_PREINIT,bcelTX.getClassName())}, - getSourceLocation(), - new ISourceLocation[]{ munger.getSourceLocation()} - ); -// IMessage msg = new Message( -// WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE_PREINIT,bcelTX.getClassName()), -// "",IMessage.ERROR,getSourceLocation(),null, -// new ISourceLocation[]{ munger.getSourceLocation()}); -// world.getMessageHandler().handleMessage(msg); - } - stateTempVar.appendConvertableArrayLoad( - returnConversionCode, - fact, - i, - stateRTX); + UnresolvedType bcelTX = BcelWorld.fromBcel(stateTypes[i]); + ResolvedType stateRTX = world.resolve(bcelTX, true); + if (stateRTX.isMissing()) { + world.getLint().cantFindType.signal(new String[] { WeaverMessages.format( + WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE_PREINIT, bcelTX.getClassName()) }, + getSourceLocation(), new ISourceLocation[] { munger.getSourceLocation() }); + // IMessage msg = new Message( + // WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE_PREINIT,bcelTX.getClassName()), + // "",IMessage.ERROR,getSourceLocation(),null, + // new ISourceLocation[]{ munger.getSourceLocation()}); + // world.getMessageHandler().handleMessage(msg); + } + stateTempVar.appendConvertableArrayLoad(returnConversionCode, fact, i, stateRTX); } } else { - // pr226201 + // pr226201 Member mungerSignature = munger.getSignature(); if (munger.getSignature() instanceof ResolvedMember) { - if (((ResolvedMember)mungerSignature).hasBackingGenericMember()) { - mungerSignature = ((ResolvedMember)mungerSignature).getBackingGenericMember(); + if (((ResolvedMember) mungerSignature).hasBackingGenericMember()) { + mungerSignature = ((ResolvedMember) mungerSignature).getBackingGenericMember(); } } UnresolvedType returnType = mungerSignature.getReturnType(); - returnConversionCode = - Utility.createConversion( - getFactory(), - BcelWorld.makeBcelType(returnType), - callbackMethod.getReturnType(),world.isInJava5Mode()); + returnConversionCode = Utility.createConversion(getFactory(), BcelWorld.makeBcelType(returnType), callbackMethod + .getReturnType(), world.isInJava5Mode()); if (!isFallsThrough()) { - returnConversionCode.append( - InstructionFactory.createReturn(callbackMethod.getReturnType())); + returnConversionCode.append(InstructionFactory.createReturn(callbackMethod.getReturnType())); } } // initialize the bit flags for this shadow - int bitflags =0x000000; - if (getKind().isTargetSameAsThis()) bitflags|=0x010000; - if (hasThis()) bitflags|=0x001000; - if (bindsThis(munger)) bitflags|=0x000100; - if (hasTarget()) bitflags|=0x000010; - if (bindsTarget(munger)) bitflags|=0x000001; - - // ATAJ for @AJ aspect we need to link the closure with the joinpoint instance - if (munger.getConcreteAspect()!=null && munger.getConcreteAspect().isAnnotationStyleAspect() - && munger.getDeclaringAspect()!=null && munger.getDeclaringAspect().resolve(world).isAnnotationStyleAspect()) { - // stick the bitflags on the stack and call the variant of linkClosureAndJoinPoint that takes an int - closureInstantiation.append(fact.createConstant(Integer.valueOf(bitflags))); - closureInstantiation.append(Utility.createInvoke( - getFactory(), - getWorld(), - new MemberImpl( - Member.METHOD, - UnresolvedType.forName("org.aspectj.runtime.internal.AroundClosure"), - Modifier.PUBLIC, - "linkClosureAndJoinPoint", - "(I)Lorg/aspectj/lang/ProceedingJoinPoint;" - ) - )); - } - - InstructionList advice = new InstructionList(); - advice.append(munger.getAdviceArgSetup(this, null, closureInstantiation)); - - // invoke the advice - advice.append(munger.getNonTestAdviceInstructions(this)); - advice.append(returnConversionCode); - if (getKind()==Shadow.MethodExecution && linenumber>0) { + int bitflags = 0x000000; + if (getKind().isTargetSameAsThis()) + bitflags |= 0x010000; + if (hasThis()) + bitflags |= 0x001000; + if (bindsThis(munger)) + bitflags |= 0x000100; + if (hasTarget()) + bitflags |= 0x000010; + if (bindsTarget(munger)) + bitflags |= 0x000001; + + // ATAJ for @AJ aspect we need to link the closure with the joinpoint instance + if (munger.getConcreteAspect() != null && munger.getConcreteAspect().isAnnotationStyleAspect() + && munger.getDeclaringAspect() != null && munger.getDeclaringAspect().resolve(world).isAnnotationStyleAspect()) { + // stick the bitflags on the stack and call the variant of linkClosureAndJoinPoint that takes an int + closureInstantiation.append(fact.createConstant(Integer.valueOf(bitflags))); + closureInstantiation.append(Utility.createInvoke(getFactory(), getWorld(), new MemberImpl(Member.METHOD, UnresolvedType + .forName("org.aspectj.runtime.internal.AroundClosure"), Modifier.PUBLIC, "linkClosureAndJoinPoint", + "(I)Lorg/aspectj/lang/ProceedingJoinPoint;"))); + } + + InstructionList advice = new InstructionList(); + advice.append(munger.getAdviceArgSetup(this, null, closureInstantiation)); + + // invoke the advice + advice.append(munger.getNonTestAdviceInstructions(this)); + advice.append(returnConversionCode); + if (getKind() == Shadow.MethodExecution && linenumber > 0) { advice.getStart().addTargeter(new LineNumberTag(linenumber)); } - + if (!hasDynamicTest) { range.append(advice); } else { InstructionList callback = makeCallToCallback(callbackMethod); InstructionList postCallback = new InstructionList(); if (terminatesWithReturn()) { - callback.append( - InstructionFactory.createReturn(callbackMethod.getReturnType())); + callback.append(InstructionFactory.createReturn(callbackMethod.getReturnType())); } else { - advice.append( - InstructionFactory.createBranchInstruction( - Constants.GOTO, - postCallback.append(InstructionConstants.NOP))); + advice.append(InstructionFactory.createBranchInstruction(Constants.GOTO, postCallback + .append(InstructionConstants.NOP))); } - range.append( - munger.getTestInstructions( - this, - advice.getStart(), - callback.getStart(), - advice.getStart())); + range.append(munger.getTestInstructions(this, advice.getStart(), callback.getStart(), advice.getStart())); range.append(advice); range.append(callback); range.append(postCallback); } - } - - // exposed for testing - InstructionList makeCallToCallback(LazyMethodGen callbackMethod) { - InstructionFactory fact = getFactory(); - InstructionList callback = new InstructionList(); - if (thisVar != null) { - callback.append(InstructionConstants.ALOAD_0); - } - if (targetVar != null && targetVar != thisVar) { - callback.append(BcelRenderer.renderExpr(fact, world, targetVar)); - } - callback.append(BcelRenderer.renderExprs(fact, world, argVars)); - // remember to render tjps - if (thisJoinPointVar != null) { - callback.append(BcelRenderer.renderExpr(fact, world, thisJoinPointVar)); - } - callback.append(Utility.createInvoke(fact, callbackMethod)); - return callback; - } + } + + // exposed for testing + InstructionList makeCallToCallback(LazyMethodGen callbackMethod) { + InstructionFactory fact = getFactory(); + InstructionList callback = new InstructionList(); + if (thisVar != null) { + callback.append(InstructionConstants.ALOAD_0); + } + if (targetVar != null && targetVar != thisVar) { + callback.append(BcelRenderer.renderExpr(fact, world, targetVar)); + } + callback.append(BcelRenderer.renderExprs(fact, world, argVars)); + // remember to render tjps + if (thisJoinPointVar != null) { + callback.append(BcelRenderer.renderExpr(fact, world, thisJoinPointVar)); + } + callback.append(Utility.createInvoke(fact, callbackMethod)); + return callback; + } /** side-effect-free */ - private InstructionList makeClosureInstantiation(Member constructor, BcelVar holder) { - -// LazyMethodGen constructor) { - InstructionFactory fact = getFactory(); - BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY); - //final Type objectArrayType = new ArrayType(Type.OBJECT, 1); - final InstructionList il = new InstructionList(); - int alen = getArgCount() + (thisVar == null ? 0 : 1) + - ((targetVar != null && targetVar != thisVar) ? 1 : 0) + - (thisJoinPointVar == null ? 0 : 1); - il.append(Utility.createConstant(fact, alen)); - il.append(fact.createNewArray(Type.OBJECT, (short)1)); - arrayVar.appendStore(il, fact); - - int stateIndex = 0; - if (thisVar != null) { - arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisVar); + private InstructionList makeClosureInstantiation(Member constructor, BcelVar holder) { + + // LazyMethodGen constructor) { + InstructionFactory fact = getFactory(); + BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY); + // final Type objectArrayType = new ArrayType(Type.OBJECT, 1); + final InstructionList il = new InstructionList(); + int alen = getArgCount() + (thisVar == null ? 0 : 1) + ((targetVar != null && targetVar != thisVar) ? 1 : 0) + + (thisJoinPointVar == null ? 0 : 1); + il.append(Utility.createConstant(fact, alen)); + il.append(fact.createNewArray(Type.OBJECT, (short) 1)); + arrayVar.appendStore(il, fact); + + int stateIndex = 0; + if (thisVar != null) { + arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisVar); thisVar.setPositionInAroundState(stateIndex); - stateIndex++; - } - if (targetVar != null && targetVar != thisVar) { - arrayVar.appendConvertableArrayStore(il, fact, stateIndex, targetVar); + stateIndex++; + } + if (targetVar != null && targetVar != thisVar) { + arrayVar.appendConvertableArrayStore(il, fact, stateIndex, targetVar); targetVar.setPositionInAroundState(stateIndex); - stateIndex++; - } - for (int i = 0, len = getArgCount(); i<len; i++) { - arrayVar.appendConvertableArrayStore(il, fact, stateIndex, argVars[i]); - argVars[i].setPositionInAroundState(stateIndex); - stateIndex++; - } - if (thisJoinPointVar != null) { - arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisJoinPointVar); - thisJoinPointVar.setPositionInAroundState(stateIndex); - stateIndex++; - } - il.append(fact.createNew(new ObjectType(constructor.getDeclaringType().getName()))); - il.append(InstructionConstants.DUP); - arrayVar.appendLoad(il, fact); - il.append(Utility.createInvoke(fact, world, constructor)); - if (getKind() == PreInitialization) { + stateIndex++; + } + for (int i = 0, len = getArgCount(); i < len; i++) { + arrayVar.appendConvertableArrayStore(il, fact, stateIndex, argVars[i]); + argVars[i].setPositionInAroundState(stateIndex); + stateIndex++; + } + if (thisJoinPointVar != null) { + arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisJoinPointVar); + thisJoinPointVar.setPositionInAroundState(stateIndex); + stateIndex++; + } + il.append(fact.createNew(new ObjectType(constructor.getDeclaringType().getName()))); + il.append(InstructionConstants.DUP); + arrayVar.appendLoad(il, fact); + il.append(Utility.createInvoke(fact, world, constructor)); + if (getKind() == PreInitialization) { il.append(InstructionConstants.DUP); holder.appendStore(il, fact); - } - return il; - } - - - private IntMap makeProceedArgumentMap(BcelVar[] adviceArgs) { - //System.err.println("coming in with " + Arrays.asList(adviceArgs)); - - IntMap ret = new IntMap(); - for(int i = 0, len = adviceArgs.length; i < len; i++) { - BcelVar v = adviceArgs[i]; - if (v == null) continue; // XXX we don't know why this is required - int pos = v.getPositionInAroundState(); - if (pos >= 0) { // need this test to avoid args bound via cflow - ret.put(pos, i); - } - } - //System.err.println("returning " + ret); - - return ret; - } + } + return il; + } + + private IntMap makeProceedArgumentMap(BcelVar[] adviceArgs) { + // System.err.println("coming in with " + Arrays.asList(adviceArgs)); + + IntMap ret = new IntMap(); + for (int i = 0, len = adviceArgs.length; i < len; i++) { + BcelVar v = adviceArgs[i]; + if (v == null) + continue; // XXX we don't know why this is required + int pos = v.getPositionInAroundState(); + if (pos >= 0) { // need this test to avoid args bound via cflow + ret.put(pos, i); + } + } + // System.err.println("returning " + ret); + + return ret; + } /** * * * @param callbackMethod the method we will call back to when our run method gets called. * - * @param proceedMap A map from state position to proceed argument position. May be - * non covering on state position. + * @param proceedMap A map from state position to proceed argument position. May be non covering on state position. */ - private LazyMethodGen makeClosureClassAndReturnConstructor( - String closureClassName, - LazyMethodGen callbackMethod, - IntMap proceedMap) - { + private LazyMethodGen makeClosureClassAndReturnConstructor(String closureClassName, LazyMethodGen callbackMethod, + IntMap proceedMap) { String superClassName = "org.aspectj.runtime.internal.AroundClosure"; - Type objectArrayType = new ArrayType(Type.OBJECT, 1); - - LazyClassGen closureClass = new LazyClassGen(closureClassName, - superClassName, - getEnclosingClass().getFileName(), - Modifier.PUBLIC, - new String[] {}, - getWorld()); - InstructionFactory fact = new InstructionFactory(closureClass.getConstantPool()); - - // constructor - LazyMethodGen constructor = new LazyMethodGen(Modifier.PUBLIC, - Type.VOID, - "<init>", - new Type[] {objectArrayType}, - new String[] {}, - closureClass); - InstructionList cbody = constructor.getBody(); + Type objectArrayType = new ArrayType(Type.OBJECT, 1); + + LazyClassGen closureClass = new LazyClassGen(closureClassName, superClassName, getEnclosingClass().getFileName(), + Modifier.PUBLIC, new String[] {}, getWorld()); + InstructionFactory fact = new InstructionFactory(closureClass.getConstantPool()); + + // constructor + LazyMethodGen constructor = new LazyMethodGen(Modifier.PUBLIC, Type.VOID, "<init>", new Type[] { objectArrayType }, + new String[] {}, closureClass); + InstructionList cbody = constructor.getBody(); cbody.append(InstructionFactory.createLoad(Type.OBJECT, 0)); cbody.append(InstructionFactory.createLoad(objectArrayType, 1)); - cbody.append(fact.createInvoke(superClassName, "<init>", Type.VOID, - new Type[] {objectArrayType}, Constants.INVOKESPECIAL)); + cbody.append(fact + .createInvoke(superClassName, "<init>", Type.VOID, new Type[] { objectArrayType }, Constants.INVOKESPECIAL)); cbody.append(InstructionFactory.createReturn(Type.VOID)); - closureClass.addMethodGen(constructor); - - // method - LazyMethodGen runMethod = new LazyMethodGen(Modifier.PUBLIC, - Type.OBJECT, - "run", - new Type[] {objectArrayType}, - new String[] {}, - closureClass); - InstructionList mbody = runMethod.getBody(); - BcelVar proceedVar = new BcelVar(UnresolvedType.OBJECTARRAY.resolve(world), 1); - // int proceedVarIndex = 1; - BcelVar stateVar = - new BcelVar(UnresolvedType.OBJECTARRAY.resolve(world), runMethod.allocateLocal(1)); - // int stateVarIndex = runMethod.allocateLocal(1); + closureClass.addMethodGen(constructor); + + // method + LazyMethodGen runMethod = new LazyMethodGen(Modifier.PUBLIC, Type.OBJECT, "run", new Type[] { objectArrayType }, + new String[] {}, closureClass); + InstructionList mbody = runMethod.getBody(); + BcelVar proceedVar = new BcelVar(UnresolvedType.OBJECTARRAY.resolve(world), 1); + // int proceedVarIndex = 1; + BcelVar stateVar = new BcelVar(UnresolvedType.OBJECTARRAY.resolve(world), runMethod.allocateLocal(1)); + // int stateVarIndex = runMethod.allocateLocal(1); mbody.append(InstructionFactory.createThis()); mbody.append(fact.createGetField(superClassName, "state", objectArrayType)); - mbody.append(stateVar.createStore(fact)); - // mbody.append(fact.createStore(objectArrayType, stateVarIndex)); - - Type[] stateTypes = callbackMethod.getArgumentTypes(); - - for (int i=0, len=stateTypes.length; i < len; i++) { - Type stateType = stateTypes[i]; - ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world); - if (proceedMap.hasKey(i)) { - mbody.append( - proceedVar.createConvertableArrayLoad(fact, proceedMap.get(i), - stateTypeX)); - } else { - mbody.append( - stateVar.createConvertableArrayLoad(fact, i, - stateTypeX)); - } - } - - + mbody.append(stateVar.createStore(fact)); + // mbody.append(fact.createStore(objectArrayType, stateVarIndex)); + + Type[] stateTypes = callbackMethod.getArgumentTypes(); + + for (int i = 0, len = stateTypes.length; i < len; i++) { + Type stateType = stateTypes[i]; + ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world); + if (proceedMap.hasKey(i)) { + mbody.append(proceedVar.createConvertableArrayLoad(fact, proceedMap.get(i), stateTypeX)); + } else { + mbody.append(stateVar.createConvertableArrayLoad(fact, i, stateTypeX)); + } + } + mbody.append(Utility.createInvoke(fact, callbackMethod)); - + if (getKind() == PreInitialization) { - mbody.append(Utility.createSet( - fact, - AjcMemberMaker.aroundClosurePreInitializationField())); + mbody.append(Utility.createSet(fact, AjcMemberMaker.aroundClosurePreInitializationField())); mbody.append(InstructionConstants.ACONST_NULL); } else { - mbody.append( - Utility.createConversion( - fact, - callbackMethod.getReturnType(), - Type.OBJECT)); + mbody.append(Utility.createConversion(fact, callbackMethod.getReturnType(), Type.OBJECT)); } mbody.append(InstructionFactory.createReturn(Type.OBJECT)); closureClass.addMethodGen(runMethod); - + // class getEnclosingClass().addGeneratedInner(closureClass); - + return constructor; } - - // ---- extraction methods - - public LazyMethodGen extractMethod(String newMethodName, int visibilityModifier, ShadowMunger munger) { + // ---- extraction methods + + public LazyMethodGen extractMethod(String newMethodName, int visibilityModifier, ShadowMunger munger) { LazyMethodGen.assertGoodBody(range.getBody(), newMethodName); - if (!getKind().allowsExtraction()) throw new BCException("Attempt to extract method from a shadow kind that does not support this operation (" + getKind() + ")"); - LazyMethodGen freshMethod = createMethodGen(newMethodName,visibilityModifier); - -// System.err.println("******"); -// System.err.println("ABOUT TO EXTRACT METHOD for" + this); -// enclosingMethod.print(System.err); -// System.err.println("INTO"); -// freshMethod.print(System.err); -// System.err.println("WITH REMAP"); -// System.err.println(makeRemap()); - - range.extractInstructionsInto(freshMethod, makeRemap(), - (getKind() != PreInitialization) && - isFallsThrough()); - if (getKind() == PreInitialization) { - addPreInitializationReturnCode( - freshMethod, - getSuperConstructorParameterTypes()); - } - getEnclosingClass().addMethodGen(freshMethod,munger.getSourceLocation()); - - return freshMethod; - } - - private void addPreInitializationReturnCode( - LazyMethodGen extractedMethod, - Type[] superConstructorTypes) - { + if (!getKind().allowsExtraction()) + throw new BCException("Attempt to extract method from a shadow kind that does not support this operation (" + getKind() + + ")"); + LazyMethodGen freshMethod = createMethodGen(newMethodName, visibilityModifier); + + // System.err.println("******"); + // System.err.println("ABOUT TO EXTRACT METHOD for" + this); + // enclosingMethod.print(System.err); + // System.err.println("INTO"); + // freshMethod.print(System.err); + // System.err.println("WITH REMAP"); + // System.err.println(makeRemap()); + + range.extractInstructionsInto(freshMethod, makeRemap(), (getKind() != PreInitialization) && isFallsThrough()); + if (getKind() == PreInitialization) { + addPreInitializationReturnCode(freshMethod, getSuperConstructorParameterTypes()); + } + getEnclosingClass().addMethodGen(freshMethod, munger.getSourceLocation()); + + return freshMethod; + } + + private void addPreInitializationReturnCode(LazyMethodGen extractedMethod, Type[] superConstructorTypes) { InstructionList body = extractedMethod.getBody(); - final InstructionFactory fact = getFactory(); - - BcelVar arrayVar = new BcelVar( - world.getCoreType(UnresolvedType.OBJECTARRAY), - extractedMethod.allocateLocal(1)); - + final InstructionFactory fact = getFactory(); + + BcelVar arrayVar = new BcelVar(world.getCoreType(UnresolvedType.OBJECTARRAY), extractedMethod.allocateLocal(1)); + int len = superConstructorTypes.length; - - body.append(Utility.createConstant(fact, len)); - body.append(fact.createNewArray(Type.OBJECT, (short)1)); - arrayVar.appendStore(body, fact); + body.append(Utility.createConstant(fact, len)); + + body.append(fact.createNewArray(Type.OBJECT, (short) 1)); + arrayVar.appendStore(body, fact); - for (int i = len - 1; i >= 0; i++) { - // convert thing on top of stack to object - body.append( - Utility.createConversion(fact, superConstructorTypes[i], Type.OBJECT)); + for (int i = len - 1; i >= 0; i++) { + // convert thing on top of stack to object + body.append(Utility.createConversion(fact, superConstructorTypes[i], Type.OBJECT)); // push object array arrayVar.appendLoad(body, fact); // swap body.append(InstructionConstants.SWAP); - // do object array store. + // do object array store. body.append(Utility.createConstant(fact, i)); body.append(InstructionConstants.SWAP); body.append(InstructionFactory.createArrayStore(Type.OBJECT)); - } - arrayVar.appendLoad(body, fact); - body.append(InstructionConstants.ARETURN); + } + arrayVar.appendLoad(body, fact); + body.append(InstructionConstants.ARETURN); } private Type[] getSuperConstructorParameterTypes() { - // assert getKind() == PreInitialization + // assert getKind() == PreInitialization InstructionHandle superCallHandle = getRange().getEnd().getNext(); - InvokeInstruction superCallInstruction = - (InvokeInstruction) superCallHandle.getInstruction(); - return superCallInstruction.getArgumentTypes( - getEnclosingClass().getConstantPool()); + InvokeInstruction superCallInstruction = (InvokeInstruction) superCallHandle.getInstruction(); + return superCallInstruction.getArgumentTypes(getEnclosingClass().getConstantPool()); } - - /** make a map from old frame location to new frame location. Any unkeyed frame - * location picks out a copied local */ - private IntMap makeRemap() { - IntMap ret = new IntMap(5); - int reti = 0; + /** + * make a map from old frame location to new frame location. Any unkeyed frame location picks out a copied local + */ + private IntMap makeRemap() { + IntMap ret = new IntMap(5); + int reti = 0; if (thisVar != null) { - ret.put(0, reti++); // thisVar guaranteed to be 0 - } - if (targetVar != null && targetVar != thisVar) { - ret.put(targetVar.getSlot(), reti++); - } - for (int i = 0, len = argVars.length; i < len; i++) { - ret.put(argVars[i].getSlot(), reti); - reti += argVars[i].getType().getSize(); - } - if (thisJoinPointVar != null) { - ret.put(thisJoinPointVar.getSlot(), reti++); - } - // we not only need to put the arguments, we also need to remap their - // aliases, which we so helpfully put into temps at the beginning of this join - // point. - if (! getKind().argsOnStack()) { - int oldi = 0; - int newi = 0; - // if we're passing in a this and we're not argsOnStack we're always - // passing in a target too - if (arg0HoldsThis()) { ret.put(0, 0); oldi++; newi+=1; } - //assert targetVar == thisVar - for (int i = 0; i < getArgCount(); i++) { - UnresolvedType type = getArgType(i); + ret.put(0, reti++); // thisVar guaranteed to be 0 + } + if (targetVar != null && targetVar != thisVar) { + ret.put(targetVar.getSlot(), reti++); + } + for (int i = 0, len = argVars.length; i < len; i++) { + ret.put(argVars[i].getSlot(), reti); + reti += argVars[i].getType().getSize(); + } + if (thisJoinPointVar != null) { + ret.put(thisJoinPointVar.getSlot(), reti++); + } + // we not only need to put the arguments, we also need to remap their + // aliases, which we so helpfully put into temps at the beginning of this join + // point. + if (!getKind().argsOnStack()) { + int oldi = 0; + int newi = 0; + // if we're passing in a this and we're not argsOnStack we're always + // passing in a target too + if (arg0HoldsThis()) { + ret.put(0, 0); + oldi++; + newi += 1; + } + // assert targetVar == thisVar + for (int i = 0; i < getArgCount(); i++) { + UnresolvedType type = getArgType(i); ret.put(oldi, newi); - oldi += type.getSize(); - newi += type.getSize(); - } - } - -// System.err.println("making remap for : " + this); -// if (targetVar != null) System.err.println("target slot : " + targetVar.getSlot()); -// if (thisVar != null) System.err.println(" this slot : " + thisVar.getSlot()); -// System.err.println(ret); - - return ret; - } - - /** - * The new method always static. - * It may take some extra arguments: this, target. - * If it's argsOnStack, then it must take both this/target - * If it's argsOnFrame, it shares this and target. - * ??? rewrite this to do less array munging, please - */ - private LazyMethodGen createMethodGen(String newMethodName, int visibilityModifier) { - Type[] parameterTypes = BcelWorld.makeBcelTypes(getArgTypes()); - int modifiers = Modifier.FINAL | visibilityModifier; - - // XXX some bug -// if (! isExpressionKind() && getSignature().isStrict(world)) { -// modifiers |= Modifier.STRICT; -// } - modifiers |= Modifier.STATIC; - if (targetVar != null && targetVar != thisVar) { - UnresolvedType targetType = getTargetType(); - targetType = ensureTargetTypeIsCorrect(targetType); - // see pr109728,pr229910 - this fixes the case when the declaring class is sometype 'X' but the (gs)etfield - // in the bytecode refers to a subtype of 'X'. This makes sure we use the type originally - // mentioned in the fieldget instruction as the method parameter and *not* the type upon which the - // field is declared because when the instructions are extracted into the new around body, - // they will still refer to the subtype. - if ((getKind()==FieldGet || getKind()==FieldSet) && getActualTargetType()!=null && - !getActualTargetType().equals(targetType.getName())) { - targetType = UnresolvedType.forName(getActualTargetType()).resolve(world); - } - ResolvedMember resolvedMember = getSignature().resolve(world); - - // pr230075, pr197719 - if (resolvedMember != null && Modifier.isProtected(resolvedMember.getModifiers()) && - !samePackage(resolvedMember.getDeclaringType().getPackageName(), getEnclosingType().getPackageName()) && - !resolvedMember.getName().equals("clone")) - { - if (!hasThis()) { // pr197719 - static accessor has been created to handle the call - if (Modifier.isStatic(enclosingMethod.getAccessFlags()) && enclosingMethod.getName().startsWith("access$")) { - targetType = BcelWorld.fromBcel(enclosingMethod.getArgumentTypes()[0]); - } - } else { - if (!targetType.resolve(world).isAssignableFrom(getThisType().resolve(world))) { - throw new BCException("bad bytecode"); - } - targetType = getThisType(); - } - } - parameterTypes = addType(BcelWorld.makeBcelType(targetType), parameterTypes); - } - if (thisVar != null) { - UnresolvedType thisType = getThisType(); - parameterTypes = addType(BcelWorld.makeBcelType(thisType), parameterTypes); - } - - // We always want to pass down thisJoinPoint in case we have already woven - // some advice in here. If we only have a single piece of around advice on a - // join point, it is unnecessary to accept (and pass) tjp. - if (thisJoinPointVar != null) { - parameterTypes = addTypeToEnd(LazyClassGen.tjpType, parameterTypes); - //FIXME ALEX? which one - //parameterTypes = addTypeToEnd(LazyClassGen.proceedingTjpType, parameterTypes); - } - - UnresolvedType returnType; - if (getKind() == PreInitialization) { - returnType = UnresolvedType.OBJECTARRAY; - } else { - - if (getKind() == ConstructorCall) returnType = getSignature().getDeclaringType(); - else if (getKind() == FieldSet) returnType = ResolvedType.VOID; - else returnType = getSignature().getReturnType().resolve(world); -// returnType = getReturnType(); // for this and above lines, see pr137496 - } - return - new LazyMethodGen( - modifiers, - BcelWorld.makeBcelType(returnType), - newMethodName, - parameterTypes, - new String[0], - // XXX again, we need to look up methods! -// UnresolvedType.getNames(getSignature().getExceptions(world)), - getEnclosingClass()); - } + oldi += type.getSize(); + newi += type.getSize(); + } + } + + // System.err.println("making remap for : " + this); + // if (targetVar != null) System.err.println("target slot : " + targetVar.getSlot()); + // if (thisVar != null) System.err.println(" this slot : " + thisVar.getSlot()); + // System.err.println(ret); + + return ret; + } + + /** + * The new method always static. It may take some extra arguments: this, target. If it's argsOnStack, then it must take both + * this/target If it's argsOnFrame, it shares this and target. ??? rewrite this to do less array munging, please + */ + private LazyMethodGen createMethodGen(String newMethodName, int visibilityModifier) { + Type[] parameterTypes = BcelWorld.makeBcelTypes(getArgTypes()); + int modifiers = Modifier.FINAL | visibilityModifier; + + // XXX some bug + // if (! isExpressionKind() && getSignature().isStrict(world)) { + // modifiers |= Modifier.STRICT; + // } + modifiers |= Modifier.STATIC; + if (targetVar != null && targetVar != thisVar) { + UnresolvedType targetType = getTargetType(); + targetType = ensureTargetTypeIsCorrect(targetType); + // see pr109728,pr229910 - this fixes the case when the declaring class is sometype 'X' but the (gs)etfield + // in the bytecode refers to a subtype of 'X'. This makes sure we use the type originally + // mentioned in the fieldget instruction as the method parameter and *not* the type upon which the + // field is declared because when the instructions are extracted into the new around body, + // they will still refer to the subtype. + if ((getKind() == FieldGet || getKind() == FieldSet) && getActualTargetType() != null + && !getActualTargetType().equals(targetType.getName())) { + targetType = UnresolvedType.forName(getActualTargetType()).resolve(world); + } + ResolvedMember resolvedMember = getSignature().resolve(world); + + // pr230075, pr197719 + if (resolvedMember != null && Modifier.isProtected(resolvedMember.getModifiers()) + && !samePackage(resolvedMember.getDeclaringType().getPackageName(), getEnclosingType().getPackageName()) + && !resolvedMember.getName().equals("clone")) { + if (!hasThis()) { // pr197719 - static accessor has been created to handle the call + if (Modifier.isStatic(enclosingMethod.getAccessFlags()) && enclosingMethod.getName().startsWith("access$")) { + targetType = BcelWorld.fromBcel(enclosingMethod.getArgumentTypes()[0]); + } + } else { + if (!targetType.resolve(world).isAssignableFrom(getThisType().resolve(world))) { + throw new BCException("bad bytecode"); + } + targetType = getThisType(); + } + } + parameterTypes = addType(BcelWorld.makeBcelType(targetType), parameterTypes); + } + if (thisVar != null) { + UnresolvedType thisType = getThisType(); + parameterTypes = addType(BcelWorld.makeBcelType(thisType), parameterTypes); + } + + // We always want to pass down thisJoinPoint in case we have already woven + // some advice in here. If we only have a single piece of around advice on a + // join point, it is unnecessary to accept (and pass) tjp. + if (thisJoinPointVar != null) { + parameterTypes = addTypeToEnd(LazyClassGen.tjpType, parameterTypes); + // FIXME ALEX? which one + // parameterTypes = addTypeToEnd(LazyClassGen.proceedingTjpType, parameterTypes); + } + + UnresolvedType returnType; + if (getKind() == PreInitialization) { + returnType = UnresolvedType.OBJECTARRAY; + } else { + + if (getKind() == ConstructorCall) + returnType = getSignature().getDeclaringType(); + else if (getKind() == FieldSet) + returnType = ResolvedType.VOID; + else + returnType = getSignature().getReturnType().resolve(world); + // returnType = getReturnType(); // for this and above lines, see pr137496 + } + return new LazyMethodGen(modifiers, BcelWorld.makeBcelType(returnType), newMethodName, parameterTypes, new String[0], + // XXX again, we need to look up methods! + // UnresolvedType.getNames(getSignature().getExceptions(world)), + getEnclosingClass()); + } private boolean samePackage(String p1, String p2) { - if (p1 == null) return p2 == null; - if (p2 == null) return false; + if (p1 == null) + return p2 == null; + if (p2 == null) + return false; return p1.equals(p2); } - - private Type[] addType(Type type, Type[] types) { - int len = types.length; - Type[] ret = new Type[len+1]; - ret[0] = type; - System.arraycopy(types, 0, ret, 1, len); - return ret; - } - - private Type[] addTypeToEnd(Type type, Type[] types) { - int len = types.length; - Type[] ret = new Type[len+1]; - ret[len] = type; - System.arraycopy(types, 0, ret, 0, len); - return ret; - } - - public BcelVar genTempVar(UnresolvedType typeX) { - return new BcelVar(typeX.resolve(world), genTempVarIndex(typeX.getSize())); - } - -// public static final boolean CREATE_TEMP_NAMES = true; - - public BcelVar genTempVar(UnresolvedType typeX, String localName) { + private Type[] addType(Type type, Type[] types) { + int len = types.length; + Type[] ret = new Type[len + 1]; + ret[0] = type; + System.arraycopy(types, 0, ret, 1, len); + return ret; + } + + private Type[] addTypeToEnd(Type type, Type[] types) { + int len = types.length; + Type[] ret = new Type[len + 1]; + ret[len] = type; + System.arraycopy(types, 0, ret, 0, len); + return ret; + } + + public BcelVar genTempVar(UnresolvedType typeX) { + return new BcelVar(typeX.resolve(world), genTempVarIndex(typeX.getSize())); + } + + // public static final boolean CREATE_TEMP_NAMES = true; + + public BcelVar genTempVar(UnresolvedType typeX, String localName) { BcelVar tv = genTempVar(typeX); -// if (CREATE_TEMP_NAMES) { -// for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) { -// if (Range.isRangeHandle(ih)) continue; -// ih.addTargeter(new LocalVariableTag(typeX, localName, tv.getSlot())); -// } -// } + // if (CREATE_TEMP_NAMES) { + // for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) { + // if (Range.isRangeHandle(ih)) continue; + // ih.addTargeter(new LocalVariableTag(typeX, localName, tv.getSlot())); + // } + // } return tv; - } - - // eh doesn't think we need to garbage collect these (64K is a big number...) - private int genTempVarIndex(int size) { - return enclosingMethod.allocateLocal(size); - } - - public InstructionFactory getFactory() { - return getEnclosingClass().getFactory(); - } - + } + + // eh doesn't think we need to garbage collect these (64K is a big number...) + private int genTempVarIndex(int size) { + return enclosingMethod.allocateLocal(size); + } + + public InstructionFactory getFactory() { + return getEnclosingClass().getFactory(); + } + public ISourceLocation getSourceLocation() { int sourceLine = getSourceLine(); if (sourceLine == 0 || sourceLine == -1) { -// Thread.currentThread().dumpStack(); -// System.err.println(this + ": " + range); + // Thread.currentThread().dumpStack(); + // System.err.println(this + ": " + range); return getEnclosingClass().getType().getSourceLocation(); } else { - // For staticinitialization, if we have a nice offset, don't build a new source loc - if (getKind()==Shadow.StaticInitialization && getEnclosingClass().getType().getSourceLocation().getOffset()!=0) { + // For staticinitialization, if we have a nice offset, don't build a new source loc + if (getKind() == Shadow.StaticInitialization && getEnclosingClass().getType().getSourceLocation().getOffset() != 0) { return getEnclosingClass().getType().getSourceLocation(); } else { int offset = 0; Kind kind = getKind(); - if ( (kind == MethodExecution) || - (kind == ConstructorExecution) || - (kind == AdviceExecution) || - (kind == StaticInitialization) || - (kind == PreInitialization) || - (kind == Initialization)) { - if (getEnclosingMethod().hasDeclaredLineNumberInfo()) { - offset = getEnclosingMethod().getDeclarationOffset(); - } - } - return getEnclosingClass().getType().getSourceContext().makeSourceLocation(sourceLine, offset); + if ((kind == MethodExecution) || (kind == ConstructorExecution) || (kind == AdviceExecution) + || (kind == StaticInitialization) || (kind == PreInitialization) || (kind == Initialization)) { + if (getEnclosingMethod().hasDeclaredLineNumberInfo()) { + offset = getEnclosingMethod().getDeclarationOffset(); + } + } + return getEnclosingClass().getType().getSourceContext().makeSourceLocation(sourceLine, offset); } } } @@ -3570,7 +3160,7 @@ public class BcelShadow extends Shadow { public void setActualTargetType(String className) { this.actualInstructionTargetType = className; } - + public String getActualTargetType() { return actualInstructionTargetType; } diff --git a/weaver/src/org/aspectj/weaver/bcel/IfFinder.java b/weaver/src/org/aspectj/weaver/bcel/IfFinder.java index e1125edc7..c66aa8939 100644 --- a/weaver/src/org/aspectj/weaver/bcel/IfFinder.java +++ b/weaver/src/org/aspectj/weaver/bcel/IfFinder.java @@ -11,8 +11,8 @@ * ******************************************************************/ package org.aspectj.weaver.bcel; +import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor; import org.aspectj.weaver.patterns.AndPointcut; -import org.aspectj.weaver.patterns.IdentityPointcutVisitor; import org.aspectj.weaver.patterns.IfPointcut; import org.aspectj.weaver.patterns.NotPointcut; import org.aspectj.weaver.patterns.OrPointcut; @@ -20,31 +20,37 @@ import org.aspectj.weaver.patterns.OrPointcut; /** * Look for an if() pointcut */ -class IfFinder extends IdentityPointcutVisitor { - boolean hasIf = false; - public Object visit(IfPointcut node, Object data) { - if (node.alwaysFalse() || node.alwaysTrue()) { - //IfFalse / IfTrue - } else { - hasIf = true; - } - return node; - } +class IfFinder extends AbstractPatternNodeVisitor { + boolean hasIf = false; - public Object visit(AndPointcut node, Object data) { - if (!hasIf) node.getLeft().accept(this, data); - if (!hasIf) node.getRight().accept(this, data); - return node; - } + public Object visit(IfPointcut node, Object data) { + if (node.alwaysFalse() || node.alwaysTrue()) { + // IfFalse / IfTrue + } else { + hasIf = true; + } + return node; + } - public Object visit(NotPointcut node, Object data) { - if (!hasIf) node.getNegatedPointcut().accept(this, data); - return node; - } + public Object visit(AndPointcut node, Object data) { + if (!hasIf) + node.getLeft().accept(this, data); + if (!hasIf) + node.getRight().accept(this, data); + return node; + } - public Object visit(OrPointcut node, Object data) { - if (!hasIf) node.getLeft().accept(this, data); - if (!hasIf) node.getRight().accept(this, data); - return node; - } + public Object visit(NotPointcut node, Object data) { + if (!hasIf) + node.getNegatedPointcut().accept(this, data); + return node; + } + + public Object visit(OrPointcut node, Object data) { + if (!hasIf) + node.getLeft().accept(this, data); + if (!hasIf) + node.getRight().accept(this, data); + return node; + } } diff --git a/weaver/src/org/aspectj/weaver/bcel/PoliceExtensionUse.java b/weaver/src/org/aspectj/weaver/bcel/PoliceExtensionUse.java index f10e8d123..5323c77f6 100644 --- a/weaver/src/org/aspectj/weaver/bcel/PoliceExtensionUse.java +++ b/weaver/src/org/aspectj/weaver/bcel/PoliceExtensionUse.java @@ -14,68 +14,69 @@ import org.aspectj.bridge.IMessage; import org.aspectj.bridge.MessageUtil; import org.aspectj.weaver.Shadow; import org.aspectj.weaver.World; +import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor; import org.aspectj.weaver.patterns.AndPointcut; -import org.aspectj.weaver.patterns.IdentityPointcutVisitor; import org.aspectj.weaver.patterns.KindedPointcut; import org.aspectj.weaver.patterns.NotPointcut; import org.aspectj.weaver.patterns.OrPointcut; import org.aspectj.weaver.patterns.Pointcut; /** - * Walks a pointcut and determines if the synchronization related designators have been - * used: lock() or unlock() + * Walks a pointcut and determines if the synchronization related designators have been used: lock() or unlock() */ -public class PoliceExtensionUse extends IdentityPointcutVisitor { - +public class PoliceExtensionUse extends AbstractPatternNodeVisitor { + private boolean synchronizationDesignatorEncountered; - private World world; - private Pointcut p; - - public PoliceExtensionUse(World w,Pointcut p) { - this.world = w; - this.p = p; - this.synchronizationDesignatorEncountered = false; - } - - public boolean synchronizationDesignatorEncountered() { - return synchronizationDesignatorEncountered; - } + private World world; + private Pointcut p; + + public PoliceExtensionUse(World w, Pointcut p) { + this.world = w; + this.p = p; + this.synchronizationDesignatorEncountered = false; + } + + public boolean synchronizationDesignatorEncountered() { + return synchronizationDesignatorEncountered; + } public Object visit(KindedPointcut node, Object data) { - if (world==null) return super.visit(node,data); // error scenario can sometimes lead to this LazyClassGen.toLongString() - if (node.getKind()==Shadow.SynchronizationLock || - node.getKind()==Shadow.SynchronizationUnlock) - synchronizationDesignatorEncountered=true; + if (world == null) + return super.visit(node, data); // error scenario can sometimes lead to this LazyClassGen.toLongString() + if (node.getKind() == Shadow.SynchronizationLock || node.getKind() == Shadow.SynchronizationUnlock) + synchronizationDesignatorEncountered = true; // Check it! if (!world.isJoinpointSynchronizationEnabled()) { - if (node.getKind()==Shadow.SynchronizationLock) { - IMessage m = MessageUtil.warn("lock() pointcut designator cannot be used without the option -Xjoinpoints:synchronization", - p.getSourceLocation()); + if (node.getKind() == Shadow.SynchronizationLock) { + IMessage m = MessageUtil.warn( + "lock() pointcut designator cannot be used without the option -Xjoinpoints:synchronization", p + .getSourceLocation()); world.getMessageHandler().handleMessage(m); - } else if (node.getKind()==Shadow.SynchronizationUnlock) { - IMessage m = MessageUtil.warn("unlock() pointcut designator cannot be used without the option -Xjoinpoints:synchronization", - p.getSourceLocation()); + } else if (node.getKind() == Shadow.SynchronizationUnlock) { + IMessage m = MessageUtil.warn( + "unlock() pointcut designator cannot be used without the option -Xjoinpoints:synchronization", p + .getSourceLocation()); world.getMessageHandler().handleMessage(m); } } return super.visit(node, data); } - - public Object visit(AndPointcut node, Object data) { - node.getLeft().accept(this, data); - node.getRight().accept(this, data); - return node; - } - public Object visit(NotPointcut node, Object data) { - node.getNegatedPointcut().accept(this, data); - return node; - } + public Object visit(AndPointcut node, Object data) { + node.getLeft().accept(this, data); + node.getRight().accept(this, data); + return node; + } + + public Object visit(NotPointcut node, Object data) { + node.getNegatedPointcut().accept(this, data); + return node; + } + + public Object visit(OrPointcut node, Object data) { + node.getLeft().accept(this, data); + node.getRight().accept(this, data); + return node; + } - public Object visit(OrPointcut node, Object data) { - node.getLeft().accept(this, data); - node.getRight().accept(this, data); - return node; - } - }
\ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java b/weaver/src/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java index 22eac78bb..14234438c 100644 --- a/weaver/src/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java +++ b/weaver/src/org/aspectj/weaver/patterns/AbstractPatternNodeVisitor.java @@ -15,383 +15,439 @@ import org.aspectj.weaver.patterns.Pointcut.MatchesNothingPointcut; /** * @author colyer - * + * */ public abstract class AbstractPatternNodeVisitor implements PatternNodeVisitor { - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.AnyTypePattern, java.lang.Object) - */ public Object visit(AnyTypePattern node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.NoTypePattern, java.lang.Object) - */ public Object visit(NoTypePattern node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.EllipsisTypePattern, java.lang.Object) - */ public Object visit(EllipsisTypePattern node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.AnyWithAnnotationTypePattern, java.lang.Object) - */ public Object visit(AnyWithAnnotationTypePattern node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.AnyAnnotationTypePattern, java.lang.Object) - */ public Object visit(AnyAnnotationTypePattern node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.EllipsisAnnotationTypePattern, java.lang.Object) - */ public Object visit(EllipsisAnnotationTypePattern node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.AndAnnotationTypePattern, java.lang.Object) - */ public Object visit(AndAnnotationTypePattern node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.AndPointcut, java.lang.Object) - */ public Object visit(AndPointcut node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.AndTypePattern, java.lang.Object) - */ public Object visit(AndTypePattern node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.AnnotationPatternList, java.lang.Object) - */ public Object visit(AnnotationPatternList node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.AnnotationPointcut, java.lang.Object) - */ public Object visit(AnnotationPointcut node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.ArgsAnnotationPointcut, java.lang.Object) - */ public Object visit(ArgsAnnotationPointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.ArgsPointcut, java.lang.Object) */ public Object visit(ArgsPointcut node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.BindingAnnotationTypePattern, java.lang.Object) + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.BindingAnnotationTypePattern, + * java.lang.Object) */ public Object visit(BindingAnnotationTypePattern node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.BindingTypePattern, java.lang.Object) */ public Object visit(BindingTypePattern node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.CflowPointcut, java.lang.Object) */ public Object visit(CflowPointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.ConcreteCflowPointcut, java.lang.Object) */ public Object visit(ConcreteCflowPointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.DeclareAnnotation, java.lang.Object) */ public Object visit(DeclareAnnotation node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.DeclareErrorOrWarning, java.lang.Object) */ public Object visit(DeclareErrorOrWarning node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.DeclareParents, java.lang.Object) */ public Object visit(DeclareParents node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.DeclarePrecedence, java.lang.Object) */ public Object visit(DeclarePrecedence node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.DeclareSoft, java.lang.Object) */ public Object visit(DeclareSoft node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.ExactAnnotationTypePattern, java.lang.Object) + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.ExactAnnotationTypePattern, + * java.lang.Object) */ public Object visit(ExactAnnotationTypePattern node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.ExactTypePattern, java.lang.Object) */ public Object visit(ExactTypePattern node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.HandlerPointcut, java.lang.Object) */ public Object visit(HandlerPointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.IfPointcut, java.lang.Object) */ public Object visit(IfPointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.KindedPointcut, java.lang.Object) */ public Object visit(KindedPointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.ModifiersPattern, java.lang.Object) */ public Object visit(ModifiersPattern node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.NamePattern, java.lang.Object) */ public Object visit(NamePattern node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.NotAnnotationTypePattern, java.lang.Object) + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.NotAnnotationTypePattern, + * java.lang.Object) */ public Object visit(NotAnnotationTypePattern node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.NotPointcut, java.lang.Object) */ public Object visit(NotPointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.NotTypePattern, java.lang.Object) */ public Object visit(NotTypePattern node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.OrAnnotationTypePattern, java.lang.Object) */ public Object visit(OrAnnotationTypePattern node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.OrPointcut, java.lang.Object) */ public Object visit(OrPointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.OrTypePattern, java.lang.Object) */ public Object visit(OrTypePattern node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.PerCflow, java.lang.Object) */ public Object visit(PerCflow node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.PerFromSuper, java.lang.Object) */ public Object visit(PerFromSuper node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.PerObject, java.lang.Object) */ public Object visit(PerObject node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.PerSingleton, java.lang.Object) */ public Object visit(PerSingleton node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.PerTypeWithin, java.lang.Object) */ public Object visit(PerTypeWithin node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.PatternNode, java.lang.Object) */ public Object visit(PatternNode node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.ReferencePointcut, java.lang.Object) */ public Object visit(ReferencePointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.SignaturePattern, java.lang.Object) */ public Object visit(SignaturePattern node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut, java.lang.Object) + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut, + * java.lang.Object) */ public Object visit(ThisOrTargetAnnotationPointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.ThisOrTargetPointcut, java.lang.Object) */ public Object visit(ThisOrTargetPointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.ThrowsPattern, java.lang.Object) */ public Object visit(ThrowsPattern node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.TypePatternList, java.lang.Object) */ public Object visit(TypePatternList node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.WildAnnotationTypePattern, java.lang.Object) + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.WildAnnotationTypePattern, + * java.lang.Object) */ public Object visit(WildAnnotationTypePattern node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.WildTypePattern, java.lang.Object) */ public Object visit(WildTypePattern node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.WithinAnnotationPointcut, java.lang.Object) + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.WithinAnnotationPointcut, + * java.lang.Object) */ public Object visit(WithinAnnotationPointcut node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.WithinCodeAnnotationPointcut, java.lang.Object) + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.WithinCodeAnnotationPointcut, + * java.lang.Object) */ public Object visit(WithinCodeAnnotationPointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.WithinPointcut, java.lang.Object) */ public Object visit(WithinPointcut node, Object data) { return node; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.WithincodePointcut, java.lang.Object) */ public Object visit(WithincodePointcut node, Object data) { return node; } - /* (non-Javadoc) - * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.Pointcut.MatchesNothingPointcut, java.lang.Object) + /* + * (non-Javadoc) + * + * @see org.aspectj.weaver.patterns.PointcutVisitor#visit(org.aspectj.weaver.patterns.Pointcut.MatchesNothingPointcut, + * java.lang.Object) */ public Object visit(MatchesNothingPointcut node, Object data) { return node; @@ -400,11 +456,11 @@ public abstract class AbstractPatternNodeVisitor implements PatternNodeVisitor { public Object visit(TypeVariablePattern node, Object data) { return node; } - + public Object visit(TypeVariablePatternList node, Object data) { return node; } - + public Object visit(HasMemberTypePattern node, Object data) { return node; } diff --git a/weaver/src/org/aspectj/weaver/patterns/IdentityPointcutVisitor.java b/weaver/src/org/aspectj/weaver/patterns/IdentityPointcutVisitor.java deleted file mode 100644 index 1042ddcc2..000000000 --- a/weaver/src/org/aspectj/weaver/patterns/IdentityPointcutVisitor.java +++ /dev/null @@ -1,246 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 Contributors. - * All rights reserved. - * This program and the accompanying materials are made available - * under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution and is available at - * http://eclipse.org/legal/epl-v10.html - * - * Contributors: - * Alexandre Vasseur initial implementation - *******************************************************************************/ -package org.aspectj.weaver.patterns; - -/** - * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> - */ -public class IdentityPointcutVisitor implements PatternNodeVisitor { - - public Object visit(AnyTypePattern node, Object data) { - return node; - } - - public Object visit(NoTypePattern node, Object data) { - return node; - } - - public Object visit(EllipsisTypePattern node, Object data) { - return node; - } - - public Object visit(AnyWithAnnotationTypePattern node, Object data) { - return node; - } - - public Object visit(AnyAnnotationTypePattern node, Object data) { - return node; - } - - public Object visit(EllipsisAnnotationTypePattern node, Object data) { - return node; - } - - public Object visit(AndAnnotationTypePattern node, Object data) { - return node; - } - - public Object visit(AndPointcut node, Object data) { - return node; - } - - public Object visit(AndTypePattern node, Object data) { - return node; - } - - public Object visit(AnnotationPatternList node, Object data) { - return node; - } - - public Object visit(AnnotationPointcut node, Object data) { - return node; - } - - public Object visit(ArgsAnnotationPointcut node, Object data) { - return node; - } - - public Object visit(ArgsPointcut node, Object data) { - return node; - } - - public Object visit(BindingAnnotationTypePattern node, Object data) { - return node; - } - - public Object visit(BindingTypePattern node, Object data) { - return node; - } - - public Object visit(CflowPointcut node, Object data) { - return node; - } - - public Object visit(ConcreteCflowPointcut node, Object data) { - return node; - } - - public Object visit(DeclareAnnotation node, Object data) { - return node; - } - - public Object visit(DeclareErrorOrWarning node, Object data) { - return node; - } - - public Object visit(DeclareParents node, Object data) { - return node; - } - - public Object visit(DeclarePrecedence node, Object data) { - return node; - } - - public Object visit(DeclareSoft node, Object data) { - return node; - } - - public Object visit(ExactAnnotationTypePattern node, Object data) { - return node; - } - - public Object visit(ExactTypePattern node, Object data) { - return node; - } - - public Object visit(HandlerPointcut node, Object data) { - return node; - } - - public Object visit(IfPointcut node, Object data) { - return node; - } - - public Object visit(KindedPointcut node, Object data) { - return node; - } - - public Object visit(ModifiersPattern node, Object data) { - return node; - } - - public Object visit(NamePattern node, Object data) { - return node; - } - - public Object visit(NotAnnotationTypePattern node, Object data) { - return node; - } - - public Object visit(NotPointcut node, Object data) { - return node; - } - - public Object visit(NotTypePattern node, Object data) { - return node; - } - - public Object visit(OrAnnotationTypePattern node, Object data) { - return node; - } - - public Object visit(OrPointcut node, Object data) { - return node; - } - - public Object visit(OrTypePattern node, Object data) { - return node; - } - - public Object visit(PerCflow node, Object data) { - return node; - } - - public Object visit(PerFromSuper node, Object data) { - return node; - } - - public Object visit(PerObject node, Object data) { - return node; - } - - public Object visit(PerSingleton node, Object data) { - return node; - } - - public Object visit(PerTypeWithin node, Object data) { - return node; - } - - public Object visit(PatternNode node, Object data) { - throw new ParserException("Should implement for " + node.getClass(), null); - } - - public Object visit(ReferencePointcut node, Object data) { - return node; - } - - public Object visit(SignaturePattern node, Object data) { - return node; - } - - public Object visit(ThisOrTargetAnnotationPointcut node, Object data) { - return node; - } - - public Object visit(ThisOrTargetPointcut node, Object data) { - return node; - } - - public Object visit(ThrowsPattern node, Object data) { - return node; - } - - public Object visit(TypePatternList node, Object data) { - return node; - } - - public Object visit(WildAnnotationTypePattern node, Object data) { - return node; - } - - public Object visit(WildTypePattern node, Object data) { - return node; - } - - public Object visit(WithinAnnotationPointcut node, Object data) { - return node; - } - - public Object visit(WithinCodeAnnotationPointcut node, Object data) { - return node; - } - - public Object visit(WithinPointcut node, Object data) { - return node; - } - - public Object visit(WithincodePointcut node, Object data) { - return node; - } - - public Object visit(Pointcut.MatchesNothingPointcut node, Object data) { - return node; - } - - public Object visit(TypeVariablePattern node, Object data) { - return node; - } - - public Object visit(TypeVariablePatternList node, Object data) { - return node; - } - - public Object visit(HasMemberTypePattern node, Object data) { - return node; - } -} diff --git a/weaver/src/org/aspectj/weaver/patterns/PerThisOrTargetPointcutVisitor.java b/weaver/src/org/aspectj/weaver/patterns/PerThisOrTargetPointcutVisitor.java index 8a6665df2..7d62ae8ab 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerThisOrTargetPointcutVisitor.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerThisOrTargetPointcutVisitor.java @@ -11,213 +11,206 @@ *******************************************************************************/ package org.aspectj.weaver.patterns; -import org.aspectj.weaver.Shadow; import org.aspectj.weaver.ResolvedPointcutDefinition; import org.aspectj.weaver.ResolvedType; +import org.aspectj.weaver.Shadow; /** - * A visitor that turns a pointcut into a type pattern equivalent for a perthis or pertarget matching: - * - pertarget(target(Foo)) => Foo+ (this one is a special case..) - * - pertarget(execution(* Foo.do()) => Foo - * - perthis(call(* Foo.do()) => * - * - perthis(!call(* Foo.do()) => * (see how the ! has been absorbed here..) - * + * A visitor that turns a pointcut into a type pattern equivalent for a perthis or pertarget matching: - pertarget(target(Foo)) => + * Foo+ (this one is a special case..) - pertarget(execution(* Foo.do()) => Foo - perthis(call(* Foo.do()) => * - perthis(!call(* + * Foo.do()) => * (see how the ! has been absorbed here..) + * * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> */ -public class PerThisOrTargetPointcutVisitor extends IdentityPointcutVisitor { - - /** A maybe marker */ - private final static TypePattern MAYBE = new TypePatternMayBe(); - - private final boolean m_isTarget; - private final ResolvedType m_fromAspectType; - - public PerThisOrTargetPointcutVisitor(boolean isTarget, ResolvedType fromAspectType) { - m_isTarget = isTarget; - m_fromAspectType = fromAspectType; - } - - public TypePattern getPerTypePointcut(Pointcut perClausePointcut) { - return (TypePattern) perClausePointcut.accept(this, perClausePointcut); - } - - //-- visitor methods, all is like Identity visitor except when it comes to transform pointcuts - - public Object visit(WithinPointcut node, Object data) { - if (m_isTarget) { - //pertarget(.. && within(Foo)) => true - //pertarget(.. && !within(Foo)) => true as well ! - return MAYBE; - } else { - return node.getTypePattern(); - } - } - - public Object visit(WithincodePointcut node, Object data) { - if (m_isTarget) { - //pertarget(.. && withincode(* Foo.do())) => true - //pertarget(.. && !withincode(* Foo.do())) => true as well ! - return MAYBE; - } else { - return node.getSignature().getDeclaringType(); - } - } - - public Object visit(WithinAnnotationPointcut node, Object data) { - if (m_isTarget) { - return MAYBE; - } else { - return new AnyWithAnnotationTypePattern( node.getAnnotationTypePattern()); - } - } - - public Object visit(WithinCodeAnnotationPointcut node, Object data) { - if (m_isTarget) { - return MAYBE; - } else { - return MAYBE;//FIXME AV - can we optimize ? perthis(@withincode(Foo)) = hasmethod(..) - } - } - - public Object visit(KindedPointcut node, Object data) { - if (node.getKind().equals(Shadow.AdviceExecution)) { - return MAYBE;//TODO AV - can we do better ? - } else if (node.getKind().equals(Shadow.ConstructorExecution) - || node.getKind().equals(Shadow.Initialization) - || node.getKind().equals(Shadow.MethodExecution) - || node.getKind().equals(Shadow.PreInitialization) - || node.getKind().equals(Shadow.StaticInitialization)) { - return node.getSignature().getDeclaringType(); - } else if (node.getKind().equals(Shadow.ConstructorCall) - || node.getKind().equals(Shadow.FieldGet) - || node.getKind().equals(Shadow.FieldSet) - || node.getKind().equals(Shadow.MethodCall)) { - if (m_isTarget) { - return node.getSignature().getDeclaringType(); - } else { - return MAYBE; - } - } else if (node.getKind().equals(Shadow.ExceptionHandler)) { - return MAYBE; - } else { - throw new ParserException("Undetermined - should not happen: " + node.getKind().getSimpleName(), null); - } - } - - public Object visit(AndPointcut node, Object data) { - return new AndTypePattern(getPerTypePointcut(node.left), getPerTypePointcut(node.right)); - } - - public Object visit(OrPointcut node, Object data) { - return new OrTypePattern(getPerTypePointcut(node.left), getPerTypePointcut(node.right)); - } - - public Object visit(NotPointcut node, Object data) { -// TypePattern negated = getPerTypePointcut(node.getNegatedPointcut()); -// if (MAYBE.equals(negated)) { -// return MAYBE; -// } -// return new NotTypePattern(negated); - // AMC - the only safe thing to return here is maybe... - // see for example pr114054 - return MAYBE; - } - - public Object visit(ThisOrTargetAnnotationPointcut node, Object data) { - if (m_isTarget && !node.isThis()) { - return new AnyWithAnnotationTypePattern( node.getAnnotationTypePattern()); - } else if (!m_isTarget && node.isThis()) { - return new AnyWithAnnotationTypePattern( node.getAnnotationTypePattern()); - } else { - // perthis(@target(Foo)) - return MAYBE; - } - } - - public Object visit(ThisOrTargetPointcut node, Object data) { - if ((m_isTarget && !node.isThis()) - || (!m_isTarget && node.isThis())) { - String pointcutString = node.getType().toString(); - // see pr115788 "<nothing>" means there was a problem resolving types - that will be reported so dont blow up - // the parser here.. - if (pointcutString.equals("<nothing>")) { - return new NoTypePattern(); - } - //pertarget(target(Foo)) => Foo+ for type pattern matching - //perthis(this(Foo)) => Foo+ for type pattern matching - // TODO AV - we do like a deep copy by parsing it again.. quite dirty, would need a clean deep copy - TypePattern copy = new PatternParser(pointcutString.replace('$', '.')).parseTypePattern(); - // TODO AV - see dirty replace from $ to . here as inner classes are with $ instead (#108488) - copy.includeSubtypes = true; - return copy; - } else { - // perthis(target(Foo)) => maybe - return MAYBE; - } - } - - public Object visit(ReferencePointcut node, Object data) { - // && pc_ref() - // we know there is no support for binding in perClause: perthis(pc_ref(java.lang.String)) - // TODO AV - may need some work for generics.. - - ResolvedPointcutDefinition pointcutDec; - ResolvedType searchStart = m_fromAspectType; - if (node.onType != null) { - searchStart = node.onType.resolve(m_fromAspectType.getWorld()); - if (searchStart.isMissing()) { - return MAYBE;// this should not happen since concretize will fails but just in case.. - } - } - pointcutDec = searchStart.findPointcut(node.name); - - return getPerTypePointcut(pointcutDec.getPointcut()); - } - - public Object visit(IfPointcut node, Object data) { - return TypePattern.ANY; - } - - public Object visit(HandlerPointcut node, Object data) { - // quiet unexpected since a KindedPointcut but do as if... - return MAYBE; - } - - public Object visit(CflowPointcut node, Object data) { - return MAYBE; - } - - public Object visit(ConcreteCflowPointcut node, Object data) { - return MAYBE; - } - - public Object visit(ArgsPointcut node, Object data) { - return MAYBE; - } - - public Object visit(ArgsAnnotationPointcut node, Object data) { - return MAYBE; - } - - public Object visit(AnnotationPointcut node, Object data) { - return MAYBE; - } - - public Object visit(Pointcut.MatchesNothingPointcut node, Object data) { - // a small hack since the usual MatchNothing has its toString = "<nothing>" which is not parseable back - // while I use back parsing for check purpose. - return new NoTypePattern() { - public String toString() { - return "false"; - } - }; - } - - /** - * A MayBe type pattern that acts as ANY except that !MAYBE = MAYBE - * - * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> - */ - private static class TypePatternMayBe extends AnyTypePattern { - } +public class PerThisOrTargetPointcutVisitor extends AbstractPatternNodeVisitor { + + /** A maybe marker */ + private final static TypePattern MAYBE = new TypePatternMayBe(); + + private final boolean m_isTarget; + private final ResolvedType m_fromAspectType; + + public PerThisOrTargetPointcutVisitor(boolean isTarget, ResolvedType fromAspectType) { + m_isTarget = isTarget; + m_fromAspectType = fromAspectType; + } + + public TypePattern getPerTypePointcut(Pointcut perClausePointcut) { + return (TypePattern) perClausePointcut.accept(this, perClausePointcut); + } + + // -- visitor methods, all is like Identity visitor except when it comes to transform pointcuts + + public Object visit(WithinPointcut node, Object data) { + if (m_isTarget) { + // pertarget(.. && within(Foo)) => true + // pertarget(.. && !within(Foo)) => true as well ! + return MAYBE; + } else { + return node.getTypePattern(); + } + } + + public Object visit(WithincodePointcut node, Object data) { + if (m_isTarget) { + // pertarget(.. && withincode(* Foo.do())) => true + // pertarget(.. && !withincode(* Foo.do())) => true as well ! + return MAYBE; + } else { + return node.getSignature().getDeclaringType(); + } + } + + public Object visit(WithinAnnotationPointcut node, Object data) { + if (m_isTarget) { + return MAYBE; + } else { + return new AnyWithAnnotationTypePattern(node.getAnnotationTypePattern()); + } + } + + public Object visit(WithinCodeAnnotationPointcut node, Object data) { + if (m_isTarget) { + return MAYBE; + } else { + return MAYBE;// FIXME AV - can we optimize ? perthis(@withincode(Foo)) = hasmethod(..) + } + } + + public Object visit(KindedPointcut node, Object data) { + if (node.getKind().equals(Shadow.AdviceExecution)) { + return MAYBE;// TODO AV - can we do better ? + } else if (node.getKind().equals(Shadow.ConstructorExecution) || node.getKind().equals(Shadow.Initialization) + || node.getKind().equals(Shadow.MethodExecution) || node.getKind().equals(Shadow.PreInitialization) + || node.getKind().equals(Shadow.StaticInitialization)) { + return node.getSignature().getDeclaringType(); + } else if (node.getKind().equals(Shadow.ConstructorCall) || node.getKind().equals(Shadow.FieldGet) + || node.getKind().equals(Shadow.FieldSet) || node.getKind().equals(Shadow.MethodCall)) { + if (m_isTarget) { + return node.getSignature().getDeclaringType(); + } else { + return MAYBE; + } + } else if (node.getKind().equals(Shadow.ExceptionHandler)) { + return MAYBE; + } else { + throw new ParserException("Undetermined - should not happen: " + node.getKind().getSimpleName(), null); + } + } + + public Object visit(AndPointcut node, Object data) { + return new AndTypePattern(getPerTypePointcut(node.left), getPerTypePointcut(node.right)); + } + + public Object visit(OrPointcut node, Object data) { + return new OrTypePattern(getPerTypePointcut(node.left), getPerTypePointcut(node.right)); + } + + public Object visit(NotPointcut node, Object data) { + // TypePattern negated = getPerTypePointcut(node.getNegatedPointcut()); + // if (MAYBE.equals(negated)) { + // return MAYBE; + // } + // return new NotTypePattern(negated); + // AMC - the only safe thing to return here is maybe... + // see for example pr114054 + return MAYBE; + } + + public Object visit(ThisOrTargetAnnotationPointcut node, Object data) { + if (m_isTarget && !node.isThis()) { + return new AnyWithAnnotationTypePattern(node.getAnnotationTypePattern()); + } else if (!m_isTarget && node.isThis()) { + return new AnyWithAnnotationTypePattern(node.getAnnotationTypePattern()); + } else { + // perthis(@target(Foo)) + return MAYBE; + } + } + + public Object visit(ThisOrTargetPointcut node, Object data) { + if ((m_isTarget && !node.isThis()) || (!m_isTarget && node.isThis())) { + String pointcutString = node.getType().toString(); + // see pr115788 "<nothing>" means there was a problem resolving types - that will be reported so dont blow up + // the parser here.. + if (pointcutString.equals("<nothing>")) { + return new NoTypePattern(); + } + // pertarget(target(Foo)) => Foo+ for type pattern matching + // perthis(this(Foo)) => Foo+ for type pattern matching + // TODO AV - we do like a deep copy by parsing it again.. quite dirty, would need a clean deep copy + TypePattern copy = new PatternParser(pointcutString.replace('$', '.')).parseTypePattern(); + // TODO AV - see dirty replace from $ to . here as inner classes are with $ instead (#108488) + copy.includeSubtypes = true; + return copy; + } else { + // perthis(target(Foo)) => maybe + return MAYBE; + } + } + + public Object visit(ReferencePointcut node, Object data) { + // && pc_ref() + // we know there is no support for binding in perClause: perthis(pc_ref(java.lang.String)) + // TODO AV - may need some work for generics.. + + ResolvedPointcutDefinition pointcutDec; + ResolvedType searchStart = m_fromAspectType; + if (node.onType != null) { + searchStart = node.onType.resolve(m_fromAspectType.getWorld()); + if (searchStart.isMissing()) { + return MAYBE;// this should not happen since concretize will fails but just in case.. + } + } + pointcutDec = searchStart.findPointcut(node.name); + + return getPerTypePointcut(pointcutDec.getPointcut()); + } + + public Object visit(IfPointcut node, Object data) { + return TypePattern.ANY; + } + + public Object visit(HandlerPointcut node, Object data) { + // quiet unexpected since a KindedPointcut but do as if... + return MAYBE; + } + + public Object visit(CflowPointcut node, Object data) { + return MAYBE; + } + + public Object visit(ConcreteCflowPointcut node, Object data) { + return MAYBE; + } + + public Object visit(ArgsPointcut node, Object data) { + return MAYBE; + } + + public Object visit(ArgsAnnotationPointcut node, Object data) { + return MAYBE; + } + + public Object visit(AnnotationPointcut node, Object data) { + return MAYBE; + } + + public Object visit(Pointcut.MatchesNothingPointcut node, Object data) { + // a small hack since the usual MatchNothing has its toString = "<nothing>" which is not parseable back + // while I use back parsing for check purpose. + return new NoTypePattern() { + public String toString() { + return "false"; + } + }; + } + + /** + * A MayBe type pattern that acts as ANY except that !MAYBE = MAYBE + * + * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> + */ + private static class TypePatternMayBe extends AnyTypePattern { + } } |