From 0d14ccfa4ce92c9adc2f849a4ee4f22c5b3a5ef7 Mon Sep 17 00:00:00 2001 From: aclement Date: Wed, 23 Mar 2005 21:31:49 +0000 Subject: [PATCH] Enhancement 88862: declare annotation hitting ITDs. --- .../systemtest/ajc150/AnnotationBinding.java | 32 ++ .../systemtest/ajc150/Annotations.java | 4 + .../org/aspectj/systemtest/ajc150/ajc150.xml | 146 ++++++-- .../aspectj/weaver/NewFieldTypeMunger.java | 1 + .../org/aspectj/weaver/ResolvedMember.java | 50 ++- .../aspectj/weaver/bcel/BcelClassWeaver.java | 342 ++++++++++++++++-- .../org/aspectj/weaver/bcel/BcelShadow.java | 197 ++++++---- .../org/aspectj/weaver/bcel/BcelWeaver.java | 2 +- .../aspectj/weaver/bcel/LazyMethodGen.java | 52 ++- .../weaver/patterns/AnnotationPointcut.java | 52 ++- .../weaver/patterns/SignaturePattern.java | 36 +- 11 files changed, 754 insertions(+), 160 deletions(-) diff --git a/tests/src/org/aspectj/systemtest/ajc150/AnnotationBinding.java b/tests/src/org/aspectj/systemtest/ajc150/AnnotationBinding.java index fb013fbd7..b8055c706 100644 --- a/tests/src/org/aspectj/systemtest/ajc150/AnnotationBinding.java +++ b/tests/src/org/aspectj/systemtest/ajc150/AnnotationBinding.java @@ -267,4 +267,36 @@ public class AnnotationBinding extends XMLBasedAjcTestCase { public void testCallsAndExecutionsOfStaticMethods() { runTest("binding with static methods"); } + + ///////////////////////////////////////////////////////////////////////////////// + // annotation binding with ITDs + + public void testAnnotationBindingAndITDs1() { + runTest("simple binding annotation values where itd method is annotated"); + } + + public void testAnnotationBindingAndITDs2() { + runTest("simple binding annotation values where itd field is annotated"); + } + + public void testAnnotationBindingAndITDs3() { + runTest("simple binding annotation values where itd ctor is annotated"); + } + + public void testAnnotationBindingAndITDs4() { + runTest("simple binding annotation values where itd method is annotated via declare"); + } + + public void testAnnotationBindingAndITDs5() { + runTest("simple binding annotation values where itd field is annotated via declare"); + } + + public void testAnnotationBindingAndITDs6() { + runTest("simple binding annotation values where itd field is annotated multiple times via declare"); + } + + public void testAnnotationBindingAndITDs7() { + runTest("simple binding annotation values where itd ctor is annotated via declare"); + } + } \ No newline at end of file diff --git a/tests/src/org/aspectj/systemtest/ajc150/Annotations.java b/tests/src/org/aspectj/systemtest/ajc150/Annotations.java index 3a099a2ab..b0efd8949 100644 --- a/tests/src/org/aspectj/systemtest/ajc150/Annotations.java +++ b/tests/src/org/aspectj/systemtest/ajc150/Annotations.java @@ -76,7 +76,11 @@ public class Annotations extends XMLBasedAjcTestCase { // more implementation work needed before this test passes public void testAnnotatedITDs() { + try { runTest("annotated itds"); + } finally { + System.err.println(ajc.getLastCompilationResult().getStandardError()); + } } public void testAnnotatedITDsWithWrongAnnotationType() { diff --git a/tests/src/org/aspectj/systemtest/ajc150/ajc150.xml b/tests/src/org/aspectj/systemtest/ajc150/ajc150.xml index c80d5f681..46d57ee6a 100644 --- a/tests/src/org/aspectj/systemtest/ajc150/ajc150.xml +++ b/tests/src/org/aspectj/systemtest/ajc150/ajc150.xml @@ -486,39 +486,57 @@ - - - - + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -1066,6 +1084,7 @@ + @@ -2022,9 +2041,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/weaver/src/org/aspectj/weaver/NewFieldTypeMunger.java b/weaver/src/org/aspectj/weaver/NewFieldTypeMunger.java index 3ef81e57b..91951118f 100644 --- a/weaver/src/org/aspectj/weaver/NewFieldTypeMunger.java +++ b/weaver/src/org/aspectj/weaver/NewFieldTypeMunger.java @@ -21,6 +21,7 @@ import java.util.Set; public class NewFieldTypeMunger extends ResolvedTypeMunger { public NewFieldTypeMunger(ResolvedMember signature, Set superMethodsCalled) { super(Field, signature); + signature.setAnnotatedElsewhere(true); this.setSuperMethodsCalled(superMethodsCalled); } diff --git a/weaver/src/org/aspectj/weaver/ResolvedMember.java b/weaver/src/org/aspectj/weaver/ResolvedMember.java index 21385a7f2..e4e7eae29 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedMember.java +++ b/weaver/src/org/aspectj/weaver/ResolvedMember.java @@ -17,6 +17,9 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; import org.aspectj.bridge.ISourceLocation; @@ -28,6 +31,12 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle public String[] parameterNames = null; protected TypeX[] checkedExceptions = TypeX.NONE; + private Set annotationTypes = null; + // Some members are 'created' to represent other things (for example ITDs). These + // members have their annotations stored elsewhere, and this flag indicates that is + // the case. It is up to the caller to work out where that is! + // Once determined the caller may choose to stash the annotations in this member... + private boolean isAnnotatedElsewhere = false; // this field is not serialized. // these three fields hold the source location of this member @@ -101,13 +110,18 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle public boolean isAjSynthetic() { return true; } + + public boolean hasAnnotations() { + return (annotationTypes==null); + } public boolean hasAnnotation(TypeX ofType) { // The ctors don't allow annotations to be specified ... yet - but // that doesn't mean it is an error to call this method. // Normally the weaver will be working with subtypes of // this type - BcelField/BcelMethod - return false; + if (annotationTypes==null) return false; + return annotationTypes.contains(ofType); } public ResolvedTypeX[] getAnnotationTypes() { @@ -115,9 +129,24 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle // that doesn't mean it is an error to call this method. // Normally the weaver will be working with subtypes of // this type - BcelField/BcelMethod - return null; + if (annotationTypes == null) return null; + return (ResolvedTypeX[])annotationTypes.toArray(new ResolvedTypeX[]{}); } + public void setAnnotationTypes(TypeX[] annotationtypes) { + if (annotationTypes == null) annotationTypes = new HashSet(); + for (int i = 0; i < annotationtypes.length; i++) { + TypeX typeX = annotationtypes[i]; + annotationTypes.add(typeX); + } + } + + public void addAnnotation(AnnotationX annotation) { + // FIXME asc only allows for annotation types, not instances - should it? + if (annotationTypes == null) annotationTypes = new HashSet(); + annotationTypes.add(annotation.getSignature()); + } + public boolean isBridgeMethod() { return (modifiers & Constants.ACC_BRIDGE)!=0; } @@ -172,6 +201,15 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle public ResolvedMember resolve(World world) { + // FIXME asc guard with a check on resolution having happened ! + if (annotationTypes!=null) { + Set r = new HashSet(); + for (Iterator iter = annotationTypes.iterator(); iter.hasNext();) { + TypeX element = (TypeX) iter.next(); + r.add(world.resolve(element)); + } + annotationTypes = r; + } return this; } @@ -244,5 +282,13 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle public void setCheckedExceptions(TypeX[] checkedExceptions) { this.checkedExceptions = checkedExceptions; } + + public void setAnnotatedElsewhere(boolean b) { + isAnnotatedElsewhere = b; + } + + public boolean isAnnotatedElsewhere() { + return isAnnotatedElsewhere; + } } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java index 0581840eb..e2906bcd2 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java @@ -15,6 +15,7 @@ package org.aspectj.weaver.bcel; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -61,11 +62,15 @@ import org.aspectj.weaver.IClassWeaver; import org.aspectj.weaver.IntMap; import org.aspectj.weaver.Member; import org.aspectj.weaver.NameMangler; +import org.aspectj.weaver.NewConstructorTypeMunger; import org.aspectj.weaver.NewFieldTypeMunger; +import org.aspectj.weaver.NewMethodTypeMunger; import org.aspectj.weaver.ResolvedMember; +import org.aspectj.weaver.ResolvedTypeMunger; import org.aspectj.weaver.ResolvedTypeX; import org.aspectj.weaver.Shadow; import org.aspectj.weaver.ShadowMunger; +import org.aspectj.weaver.TypeX; import org.aspectj.weaver.WeaverMessages; import org.aspectj.weaver.WeaverMetrics; import org.aspectj.weaver.WeaverStateInfo; @@ -115,6 +120,8 @@ class BcelClassWeaver implements IClassWeaver { private final Map addedSuperInitializers = new HashMap(); // Interface -> IfaceInitList private List addedThisInitializers = new ArrayList(); // List private List addedClassInitializers = new ArrayList(); // List + + private Map mapToAnnotations = new HashMap(); private BcelShadow clinitShadow = null; @@ -415,26 +422,40 @@ class BcelClassWeaver implements IClassWeaver { * Weave any declare @method/@ctor statements into the members of the supplied class */ private boolean weaveDeclareAtMethodCtor(LazyClassGen clazz) { + List reportedProblems = new ArrayList(); + + List allDecams = world.getDeclareAnnotationOnMethods(); + if (allDecams.isEmpty()) return false; // nothing to do boolean isChanged = false; - List decaMs = getMatchingSubset(world.getDeclareAnnotationOnMethods(),clazz.getType()); + + // deal with ITDs + List itdMethodsCtors = getITDSubset(clazz,ResolvedTypeMunger.Method); + itdMethodsCtors.addAll(getITDSubset(clazz,ResolvedTypeMunger.Constructor)); + if (!itdMethodsCtors.isEmpty()) { + // Can't use the subset called 'decaMs' as it won't be right for ITDs... + isChanged = weaveAtMethodOnITDSRepeatedly(allDecams,itdMethodsCtors,reportedProblems); + } + + // deal with all the other methods... List members = clazz.getMethodGens(); - if (!members.isEmpty() && !decaMs.isEmpty()) { - // go through all the fields + List decaMs = getMatchingSubset(allDecams,clazz.getType()); + if (decaMs.isEmpty()) return false; // nothing to do + if (!members.isEmpty()) { for (int memberCounter = 0;memberCounter) to some bunch + * of ITDfields (List. It will iterate over the fields repeatedly until + * everything has been applied. + * + */ + private boolean weaveAtFieldRepeatedly(List decaFs, List itdFields,List reportedErrors) { + boolean isChanged = false; + for (Iterator iter = itdFields.iterator(); iter.hasNext();) { + BcelTypeMunger fieldMunger = (BcelTypeMunger) iter.next(); + ResolvedMember itdIsActually = fieldMunger.getSignature(); + List worthRetrying = new ArrayList(); + boolean modificationOccured = false; + + for (Iterator iter2 = decaFs.iterator(); iter2.hasNext();) { + DeclareAnnotation decaF = (DeclareAnnotation) iter2.next(); + + if (decaF.matches(itdIsActually,world)) { + LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,fieldMunger); + if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaF,reportedErrors)) continue; // skip this one... + annotationHolder.addAnnotation(decaF.getAnnotationX()); + //FIXME asc you need to add relationships for these things + // AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]); + isChanged = true; + modificationOccured = true; + + } else { + if (!decaF.isStarredAnnotationPattern()) + worthRetrying.add(decaF); // an annotation is specified that might be put on by a subsequent decaf + } + } + + while (!worthRetrying.isEmpty() && modificationOccured) { + modificationOccured = false; + List forRemoval = new ArrayList(); + for (Iterator iter2 = worthRetrying.iterator(); iter.hasNext();) { + DeclareAnnotation decaF = (DeclareAnnotation) iter2.next(); + if (decaF.matches(itdIsActually,world)) { + LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,fieldMunger); + if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaF,reportedErrors)) continue; // skip this one... + annotationHolder.addAnnotation(decaF.getAnnotationX()); + //FIXME asc you need to add relationships for these things + // AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]); + isChanged = true; + modificationOccured = true; + forRemoval.add(decaF); + } + worthRetrying.removeAll(forRemoval); + } + } + } + return isChanged; + } + + + /** + * Applies some set of declare @method/@ctor constructs (List) to some bunch + * of ITDmembers (List. It will iterate over the fields repeatedly until + * everything has been applied. + */ + private boolean weaveAtMethodOnITDSRepeatedly(List decaMCs, List itdMethodsCtors,List reportedErrors) { + boolean isChanged = false; + for (Iterator iter = itdMethodsCtors.iterator(); iter.hasNext();) { + BcelTypeMunger methodctorMunger = (BcelTypeMunger) iter.next(); + ResolvedMember itdIsActually = methodctorMunger.getSignature(); + List worthRetrying = new ArrayList(); + boolean modificationOccured = false; + + for (Iterator iter2 = decaMCs.iterator(); iter2.hasNext();) { + DeclareAnnotation decaMC = (DeclareAnnotation) iter2.next(); + + if (decaMC.matches(itdIsActually,world)) { + LazyMethodGen annotationHolder = locateAnnotationHolderForMethodCtorMunger(clazz,methodctorMunger); + if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaMC,reportedErrors)) continue; // skip this one... + annotationHolder.addAnnotation(decaMC.getAnnotationX()); + itdIsActually.addAnnotation(decaMC.getAnnotationX()); + isChanged=true; + //FIXME asc you need to add relationships for these things + // AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]); + isChanged = true; + modificationOccured = true; + + } else { + if (!decaMC.isStarredAnnotationPattern()) + worthRetrying.add(decaMC); // an annotation is specified that might be put on by a subsequent decaf + } + } + + while (!worthRetrying.isEmpty() && modificationOccured) { + modificationOccured = false; + List forRemoval = new ArrayList(); + for (Iterator iter2 = worthRetrying.iterator(); iter.hasNext();) { + DeclareAnnotation decaF = (DeclareAnnotation) iter2.next(); + if (decaF.matches(itdIsActually,world)) { + LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,methodctorMunger); + if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaF,reportedErrors)) continue; // skip this one... + annotationHolder.addAnnotation(decaF.getAnnotationX()); + //FIXME asc you need to add relationships for these things + // AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]); + isChanged = true; + modificationOccured = true; + forRemoval.add(decaF); + } + worthRetrying.removeAll(forRemoval); + } + } + } + return isChanged; + } + + /** * Weave any declare @field statements into the fields of the supplied class + * + * Interesting case relating to public ITDd fields. The annotations are really stored against + * the interfieldinit method in the aspect, but the public field is placed in the target + * type and then is processed in the 2nd pass over fields that occurs. I think it would be + * more expensive to avoid putting the annotation on that inserted public field than just to + * have it put there as well as on the interfieldinit method. */ private boolean weaveDeclareAtField(LazyClassGen clazz) { @@ -498,14 +685,26 @@ class BcelClassWeaver implements IClassWeaver { // decafs and check that to see if an error needs to be reported - this // would be expensive so lets skip it for now - List decaFs = getMatchingSubset(world.getDeclareAnnotationOnFields(),clazz.getType()); + List reportedProblems = new ArrayList(); + + List allDecafs = world.getDeclareAnnotationOnFields(); + if (allDecafs.isEmpty()) return false; // nothing to do + + boolean isChanged = false; + List itdFields = getITDSubset(clazz,ResolvedTypeMunger.Field); + if (itdFields!=null) { + isChanged = weaveAtFieldRepeatedly(allDecafs,itdFields,reportedProblems); + } + + List decaFs = getMatchingSubset(allDecafs,clazz.getType()); + if (decaFs.isEmpty()) return false; // nothing more to do Field[] fields = clazz.getFieldGens(); - if (fields!=null && !decaFs.isEmpty()) { - // go through all the fields + if (fields!=null) { + for (int fieldCounter = 0;fieldCounterShould only be used when the resolvedmember is the contents of an effective signature + * attribute, as thats the only time when the annotations aren't stored directly in the + * resolvedMember + * @param rm the sig we want it to pretend to be 'int A.m()' or somesuch ITD like thing + * @param declaredSig the real sig 'blah.ajc$xxx' + */ + private void fixAnnotationsForResolvedMember(ResolvedMember rm,ResolvedMember declaredSig) { + try { + TypeX memberHostType = declaredSig.getDeclaringType(); + ResolvedTypeX[] annotations = (ResolvedTypeX[])mapToAnnotations.get(rm); + String methodName = declaredSig.getName(); + // FIXME asc shouldnt really rely on string names ! + if (annotations == null) { + if (rm.getKind()==Member.FIELD) { + if (methodName.startsWith("ajc$inlineAccessField")) { + ResolvedMember resolvedDooberry = world.resolve(rm); + annotations = resolvedDooberry.getAnnotationTypes(); + } else { + ResolvedMember realthing = AjcMemberMaker.interFieldInitializer(rm,memberHostType); + ResolvedMember resolvedDooberry = world.resolve(realthing); + annotations = resolvedDooberry.getAnnotationTypes(); + } + } else if (rm.getKind()==Member.METHOD && !rm.isAbstract()) { + if (methodName.startsWith("ajc$inlineAccessMethod")) { + ResolvedMember resolvedDooberry = world.resolve(declaredSig); + annotations = resolvedDooberry.getAnnotationTypes(); + } else { + ResolvedMember realthing = AjcMemberMaker.interMethodBody(rm,memberHostType); + ResolvedMember resolvedDooberry = world.resolve(realthing); + annotations = resolvedDooberry.getAnnotationTypes(); + } + } else if (rm.getKind()==Member.CONSTRUCTOR) { + ResolvedMember realThing = AjcMemberMaker.postIntroducedConstructor(memberHostType.resolve(world),rm.getDeclaringType(),rm.getParameterTypes()); + ResolvedMember resolvedDooberry = world.resolve(realThing); + annotations = resolvedDooberry.getAnnotationTypes(); + } + if (annotations == null) + annotations = new ResolvedTypeX[0]; + mapToAnnotations.put(rm,annotations); + } + rm.setAnnotationTypes(annotations); + } catch (Throwable t) { + //FIXME asc remove this catch after more testing has confirmed the above stuff is OK + throw new RuntimeException("Unexpectedly went bang when searching for annotations on "+rm,t); + } + } + private void matchInvokeInstruction(LazyMethodGen mg, InstructionHandle ih, @@ -1292,10 +1567,15 @@ class BcelClassWeaver implements IClassWeaver { if (effectiveSig == null) return; //System.err.println("call to inter-type member: " + effectiveSig); if (effectiveSig.isWeaveBody()) return; - if (canMatch(effectiveSig.getShadowKind())) + + + ResolvedMember rm = effectiveSig.getEffectiveSignature(); + + fixAnnotationsForResolvedMember(rm,declaredSig); // abracadabra + + if (canMatch(effectiveSig.getShadowKind())) match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow, - effectiveSig.getShadowKind(), effectiveSig.getEffectiveSignature()), - shadowAccumulator); + effectiveSig.getShadowKind(), rm), shadowAccumulator); } } else { if (canMatch(Shadow.MethodCall)) diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java index ab5be0f71..b015f6d3f 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java @@ -59,6 +59,9 @@ import org.aspectj.weaver.BCException; import org.aspectj.weaver.IntMap; import org.aspectj.weaver.Member; import org.aspectj.weaver.NameMangler; +import org.aspectj.weaver.NewConstructorTypeMunger; +import org.aspectj.weaver.NewFieldTypeMunger; +import org.aspectj.weaver.NewMethodTypeMunger; import org.aspectj.weaver.ResolvedMember; import org.aspectj.weaver.ResolvedTypeX; import org.aspectj.weaver.Shadow; @@ -1283,6 +1286,7 @@ public class BcelShadow extends Shadow { thisAnnotationVars = new HashMap(); // populate.. } + public void initializeTargetAnnotationVars() { if (targetAnnotationVars != null) return; if (getKind().isTargetSameAsThis()) { @@ -1308,6 +1312,7 @@ public class BcelShadow extends Shadow { // what the full set of annotations could be (due to static/dynamic type differences...) } } + public void initializeKindedAnnotationVars() { if (kindedAnnotationVars != null) return; kindedAnnotationVars = new HashMap(); @@ -1316,100 +1321,156 @@ public class BcelShadow extends Shadow { // Then create one BcelVar entry in the map for each annotation, keyed by // annotation type (TypeX). - // FIXME asc Refactor these once all shadow kinds added - there is lots of commonality + // FIXME asc Refactor this code, there is duplication ResolvedTypeX[] annotations = null; - TypeX relevantType = null; + ResolvedMember itdMember =null; + Member relevantMember = getSignature(); + TypeX relevantType = null; + TypeX aspect = null; if (getKind() == Shadow.StaticInitialization) { relevantType = getSignature().getDeclaringType(); annotations = relevantType.resolve(world).getAnnotationTypes(); - } - if (getKind() == Shadow.ExceptionHandler) { - relevantType = getSignature().getParameterTypes()[0]; - annotations = relevantType.resolve(world).getAnnotationTypes(); - } - if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) { + + } else if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) { relevantType = getSignature().getDeclaringType(); - ResolvedMember rm[] = relevantType.getDeclaredMethods(world); - ResolvedMember found = null; - String searchString = getSignature().getName()+getSignature().getParameterSignature(); - for (int i = 0; i < rm.length && found==null; i++) { - ResolvedMember member = rm[i]; - if ((member.getName()+member.getParameterSignature()).equals(searchString)) { - found = member; + relevantMember = findMethod2(relevantType.getDeclaredMethods(world),getSignature()); + + if (relevantMember == 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.interMethodBody(fakerm,typeMunger.getAspectType())); + ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod); + if (fakerm.getName().equals(getSignature().getName()) && + fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) { + relevantType = typeMunger.getAspectType(); + relevantMember = rmm; + } + } } } - annotations = found.getAnnotationTypes(); - } - if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution || - getKind() == Shadow.AdviceExecution) { + annotations = relevantMember.getAnnotationTypes(); + + } else if (getKind() == Shadow.FieldSet || getKind() == Shadow.FieldGet) { relevantType = getSignature().getDeclaringType(); - ResolvedMember rm[] = relevantType.getDeclaredMethods(world); - ResolvedMember found = null; - String searchString = getSignature().getName()+getSignature().getParameterSignature(); - for (int i = 0; i < rm.length && found==null; i++) { - ResolvedMember member = rm[i]; - if ((member.getName()+member.getParameterSignature()).equals(searchString)) { - found = member; - } + relevantMember = findField(relevantType.getDeclaredFields(world),getSignature()); + + if (relevantMember==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(); + relevantMember = rmm; + } + } + } } - annotations = found.getAnnotationTypes(); - } - if (getKind() == Shadow.PreInitialization || getKind() == Shadow.Initialization) { + annotations = relevantMember.getAnnotationTypes(); + + } else if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution || + getKind() == Shadow.AdviceExecution) { relevantType = getSignature().getDeclaringType(); ResolvedMember rm[] = relevantType.getDeclaredMethods(world); - ResolvedMember found = null; - String searchString = getSignature().getName()+getSignature().getParameterSignature(); - for (int i = 0; i < rm.length && found==null; i++) { - ResolvedMember member = rm[i]; - if ((member.getName()+member.getParameterSignature()).equals(searchString)) { - found = member; - } - } - annotations = found.getAnnotationTypes(); - } - if (getKind() == Shadow.FieldSet) { - relevantType = getSignature().getDeclaringType(); - ResolvedMember rm[] = relevantType.getDeclaredFields(world); - ResolvedMember found = null; - for (int i = 0; i < rm.length && found==null; i++) { - ResolvedMember member = rm[i]; - if ( member.getName().equals(getSignature().getName()) && - member.getType().equals(getSignature().getType())) { - found = member; + relevantMember = findMethod2(relevantType.getDeclaredMethods(world),getSignature()); + + if (relevantMember == 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.interMethodBody(fakerm,typeMunger.getAspectType())); + ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod); + if (fakerm.getName().equals(getSignature().getName()) && + fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) { + relevantType = typeMunger.getAspectType(); + relevantMember = rmm; + } + } } } - annotations = found.getAnnotationTypes(); - } - if (getKind() == Shadow.FieldGet) { + annotations = relevantMember.getAnnotationTypes(); + + } else if (getKind() == Shadow.ExceptionHandler) { + relevantType = getSignature().getParameterTypes()[0]; + annotations = relevantType.resolve(world).getAnnotationTypes(); + + } else if (getKind() == Shadow.PreInitialization || getKind() == Shadow.Initialization) { relevantType = getSignature().getDeclaringType(); - ResolvedMember rm[] = relevantType.getDeclaredFields(world); - ResolvedMember found = null; - for (int i = 0; i < rm.length && found==null; i++) { - ResolvedMember member = rm[i]; - if ( member.getName().equals(getSignature().getName()) && - member.getType().equals(getSignature().getType())) { - found = member; - } - } + ResolvedMember found = findMethod2(relevantType.getDeclaredMethods(world),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("Didn't recognize shadow: "+getKind()); + throw new BCException("Couldn't discover annotations for shadow: "+getKind()); } for (int i = 0; i < annotations.length; i++) { ResolvedTypeX aTX = annotations[i]; - kindedAnnotationVars.put(aTX, - new KindedAnnotationAccessVar(getKind(),aTX.resolve(world),relevantType,getSignature())); + KindedAnnotationAccessVar kaav = new KindedAnnotationAccessVar(getKind(),aTX.resolve(world),relevantType,relevantMember); + kindedAnnotationVars.put(aTX,kaav); } - - - } - public void initializeWithinAnnotationVars() { + +//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++) { + ResolvedMember member = rm[i]; + if (member.getName().equals(sig.getName()) && member.getParameterSignature().equals(sig.getParameterSignature())) + found = member; + } + return found; + } + + private ResolvedMember findMethod(ResolvedTypeX 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; + } + } + return null; + } + + + public void initializeWithinAnnotationVars() { if (withinAnnotationVars != null) return; withinAnnotationVars = new HashMap(); diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java index 3f1134b6f..7d4bd8d59 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java @@ -1134,7 +1134,7 @@ public class BcelWeaver implements IWeaver { boolean didSomething = false; if (decA.matches(onType)) { - //FIXME asc CRITICAL this should be guarded by the 'already has annotation' check below but isn't since the compiler is producing classfiles with deca affected things in... + //FIXME asc important this should be guarded by the 'already has annotation' check below but isn't since the compiler is producing classfiles with deca affected things in... AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decA.getSourceLocation(),onType.getSourceLocation()); if (onType.hasAnnotation(decA.getAnnotationX().getSignature())) { diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java index d97fefac6..f465bc2f1 100644 --- a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java +++ b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java @@ -32,6 +32,7 @@ import org.aspectj.apache.bcel.classfile.Attribute; import org.aspectj.apache.bcel.classfile.ConstantPool; import org.aspectj.apache.bcel.classfile.Method; import org.aspectj.apache.bcel.classfile.Synthetic; +import org.aspectj.apache.bcel.classfile.annotation.Annotation; import org.aspectj.apache.bcel.generic.BranchHandle; import org.aspectj.apache.bcel.generic.BranchInstruction; import org.aspectj.apache.bcel.generic.CPInstruction; @@ -58,6 +59,7 @@ import org.aspectj.weaver.BCException; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.Member; import org.aspectj.weaver.ResolvedTypeX; +import org.aspectj.weaver.TypeX; import org.aspectj.weaver.WeaverMessages; @@ -84,7 +86,7 @@ public final class LazyMethodGen { private String[] declaredExceptions; private InstructionList body; // leaving null for abstracts private Attribute[] attributes; - private AnnotationGen[] annotations; + // private AnnotationGen[] annotations; /* private */ final LazyClassGen enclosingClass; private final BcelMethod memberView; int highestLineNumber = 0; @@ -181,19 +183,25 @@ public final class LazyMethodGen { public void addAnnotation(AnnotationX ax) { initialize(); -// if (!hasAnnotation(TypeX.forSignature(a.getTypeSignature()))) { - AnnotationGen ag = new AnnotationGen(ax.getBcelAnnotation(),enclosingClass.getConstantPoolGen(),true); - AnnotationGen[] newAnnotations = new AnnotationGen[annotations.length+1]; - System.arraycopy(annotations,0,newAnnotations,0,annotations.length); - newAnnotations[annotations.length]=ag; - annotations = newAnnotations; - // FIXME asc does this mean we are managing two levels of annotations again? - // one here and one in the memberView??!? - memberView.addAnnotation(ax); + if (memberView==null) { + System.err.println("REPORT THIS! 01: Lost annotation: "+ax+" cant be put onto "+this); + return; + } + memberView.addAnnotation(ax); } - + + + public boolean hasAnnotation(TypeX annotationTypeX) { + initialize(); + if (memberView==null) { + System.err.println("REPORT THIS! 02: Can't determine if "+this+" has annotation "+annotationTypeX); + return false; + } + return memberView.hasAnnotation(annotationTypeX); + } + private void initialize() { - if (returnType != null) return; + if (returnType != null) return; //System.err.println("initializing: " + getName() + ", " + enclosingClass.getName() + ", " + returnType + ", " + savedMethod); @@ -204,7 +212,7 @@ public final class LazyMethodGen { this.declaredExceptions = gen.getExceptions(); this.attributes = gen.getAttributes(); - this.annotations = gen.getAnnotations(); + //this.annotations = gen.getAnnotations(); this.maxLocals = gen.getMaxLocals(); // this.returnType = BcelWorld.makeBcelType(memberView.getReturnType()); @@ -799,9 +807,21 @@ public final class LazyMethodGen { gen.addAttribute(attributes[i]); } - if (annotations!=null) { - for (int i = 0, len = annotations.length; i < len; i++) { - gen.addAnnotation(annotations[i]); +// We don't manage our own set of annotations... +// if (annotations!=null) { +// for (int i = 0, len = annotations.length; i < len; i++) { +// gen.addAnnotation(annotations[i]); +// } +// } + + // work with the annotations from the memberView rather + // than any set we know about. This assumes we only work with + // annotations on LazyMethodGens that represent real members. + if (memberView!=null && memberView.getAnnotations()!=null && memberView.getAnnotations().length!=0) { + AnnotationX[] ans = memberView.getAnnotations(); + for (int i = 0, len = ans.length; i < len; i++) { + Annotation a= ans[i].getBcelAnnotation(); + gen.addAnnotation(new AnnotationGen(a,gen.getConstantPool(),true)); } } diff --git a/weaver/src/org/aspectj/weaver/patterns/AnnotationPointcut.java b/weaver/src/org/aspectj/weaver/patterns/AnnotationPointcut.java index e396576de..b7c8ed7b4 100644 --- a/weaver/src/org/aspectj/weaver/patterns/AnnotationPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/AnnotationPointcut.java @@ -14,18 +14,19 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Set; -import org.aspectj.bridge.IMessage; -import org.aspectj.bridge.MessageUtil; import org.aspectj.util.FuzzyBoolean; +import org.aspectj.weaver.AjcMemberMaker; import org.aspectj.weaver.AnnotatedElement; import org.aspectj.weaver.BCException; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.IntMap; import org.aspectj.weaver.Member; import org.aspectj.weaver.NameMangler; +import org.aspectj.weaver.NewFieldTypeMunger; import org.aspectj.weaver.ResolvedMember; import org.aspectj.weaver.ResolvedTypeX; import org.aspectj.weaver.Shadow; @@ -35,6 +36,7 @@ import org.aspectj.weaver.VersionedDataInputStream; import org.aspectj.weaver.ast.Literal; import org.aspectj.weaver.ast.Test; import org.aspectj.weaver.ast.Var; +import org.aspectj.weaver.bcel.BcelTypeMunger; /** * @annotation(@Foo) or @annotation(foo) @@ -110,12 +112,39 @@ public class AnnotationPointcut extends NameBindingPointcut { toMatchAgainst = rMember.getParameterTypes()[0].resolve(shadow.getIWorld()); } else { toMatchAgainst = rMember; + // FIXME asc I'd like to get rid of this bit of logic altogether, shame ITD fields don't have an effective sig attribute + // FIXME asc perf cache the result of discovering the member that contains the real annotations + if (rMember.isAnnotatedElsewhere()) { + if (kind==Shadow.FieldGet || kind==Shadow.FieldSet) { + List mungers = rMember.getDeclaringType().resolve(shadow.getIWorld()).getInterTypeMungers(); // FIXME asc should include supers with getInterTypeMungersIncludingSupers? + for (Iterator iter = mungers.iterator(); iter.hasNext();) { + BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); + if (typeMunger.getMunger() instanceof NewFieldTypeMunger) { + ResolvedMember fakerm = typeMunger.getSignature(); + if (fakerm.equals(member)) { + ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm,typeMunger.getAspectType()); + ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod); + toMatchAgainst = rmm; + } + } + } + } + } } annotationTypePattern.resolve(shadow.getIWorld()); return annotationTypePattern.matches(toMatchAgainst); } + private ResolvedMember findMethod(ResolvedTypeX 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; + } + /* (non-Javadoc) * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(org.aspectj.weaver.patterns.IScope, org.aspectj.weaver.patterns.Bindings) @@ -148,24 +177,7 @@ public class AnnotationPointcut extends NameBindingPointcut { */ protected Test findResidueInternal(Shadow shadow, ExposedState state) { - if (shadow.getKind()!=Shadow.MethodCall && - shadow.getKind()!=Shadow.ConstructorCall && - shadow.getKind()!=Shadow.ConstructorExecution && - shadow.getKind()!=Shadow.MethodExecution && - shadow.getKind()!=Shadow.FieldSet && - shadow.getKind()!=Shadow.FieldGet && - shadow.getKind()!=Shadow.StaticInitialization && - shadow.getKind()!=Shadow.PreInitialization && - shadow.getKind()!=Shadow.AdviceExecution && - shadow.getKind()!=Shadow.Initialization && - shadow.getKind()!=Shadow.ExceptionHandler - ) { - IMessage lim = MessageUtil.error("Binding not supported in @pcds (1.5.0 M2 limitation) for "+shadow.getKind()+" join points, see: " + - getSourceLocation()); - shadow.getIWorld().getMessageHandler().handleMessage(lim); - throw new BCException("Binding not supported in @pcds (1.5.0 M2 limitation) for "+shadow.getKind()+" join points, see: " + - getSourceLocation()); - } + if (annotationTypePattern instanceof BindingAnnotationTypePattern) { diff --git a/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java b/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java index 633e15748..13f8be048 100644 --- a/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java +++ b/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java @@ -30,15 +30,18 @@ import org.aspectj.lang.reflect.ConstructorSignature; import org.aspectj.lang.reflect.FieldSignature; import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.weaver.AjAttribute; +import org.aspectj.weaver.AjcMemberMaker; import org.aspectj.weaver.Constants; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.Member; import org.aspectj.weaver.NameMangler; +import org.aspectj.weaver.NewFieldTypeMunger; import org.aspectj.weaver.ResolvedMember; import org.aspectj.weaver.ResolvedTypeX; import org.aspectj.weaver.TypeX; import org.aspectj.weaver.VersionedDataInputStream; import org.aspectj.weaver.World; +import org.aspectj.weaver.bcel.BcelTypeMunger; public class SignaturePattern extends PatternNode { @@ -132,9 +135,41 @@ public class SignaturePattern extends PatternNode { return false; } annotationPattern.resolve(world); + + // optimization before we go digging around for annotations on ITDs + if (annotationPattern instanceof AnyAnnotationTypePattern) return true; + + // fake members represent ITD'd fields - for their annotations we should go and look up the + // relevant member in the original aspect + if (rMember.isAnnotatedElsewhere() && member.getKind()==Member.FIELD) { + // FIXME asc duplicate of code in AnnotationPattern.matchInternal()? same fixmes apply here. + ResolvedMember [] mems = rMember.getDeclaringType().resolve(world).getDeclaredFields(); // FIXME asc should include supers with getInterTypeMungersIncludingSupers? + List mungers = rMember.getDeclaringType().resolve(world).getInterTypeMungers(); + for (Iterator iter = mungers.iterator(); iter.hasNext();) { + BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); + if (typeMunger.getMunger() instanceof NewFieldTypeMunger) { + ResolvedMember fakerm = typeMunger.getSignature(); + ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm,typeMunger.getAspectType()); + ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod); + if (fakerm.equals(member)) { + rMember = rmm; + } + } + } + } + return annotationPattern.matches(rMember).alwaysTrue(); } + private ResolvedMember findMethod(ResolvedTypeX 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; + } + public boolean matchesIgnoringAnnotations(Member member, World world) { //XXX performance gains would come from matching on name before resolving // to fail fast. ASC 30th Nov 04 => Not necessarily, it didn't make it faster for me. @@ -143,7 +178,6 @@ public class SignaturePattern extends PatternNode { // String n2 = this.getName().maybeGetSimpleName(); // if (n2!=null && !n1.equals(n2)) return false; - // FIXME ASC : if (member == null) return false; ResolvedMember sig = member.resolve(world); -- 2.39.5