diff options
author | Andy Clement <aclement@gopivotal.com> | 2013-10-01 10:00:14 -0700 |
---|---|---|
committer | Andy Clement <aclement@gopivotal.com> | 2013-10-18 11:36:29 -0700 |
commit | 2314eaf48a35a249e63fae12151ce926ea98c97c (patch) | |
tree | 27fb10ca8254958b652f22e8adf229c506fb1e47 | |
parent | aba10968da43b517e68308e14681a14311a76d42 (diff) | |
download | aspectj-2314eaf48a35a249e63fae12151ce926ea98c97c.tar.gz aspectj-2314eaf48a35a249e63fae12151ce926ea98c97c.zip |
418129: annos on top most implementor method
-rw-r--r-- | tests/bugs174/pr418129/Target.java | 27 | ||||
-rw-r--r-- | tests/bugs174/pr418129/Target2.java | 27 | ||||
-rw-r--r-- | tests/bugs174/pr418129/Target3.java | 27 | ||||
-rw-r--r-- | tests/bugs174/pr418129/Target4.java | 25 | ||||
-rw-r--r-- | tests/src/org/aspectj/systemtest/ajc174/Ajc174Tests.java | 16 | ||||
-rw-r--r-- | tests/src/org/aspectj/systemtest/ajc174/ajc174.xml | 61 | ||||
-rw-r--r-- | weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java | 100 | ||||
-rw-r--r-- | weaver/src/org/aspectj/weaver/bcel/BcelWorld.java | 17 | ||||
-rw-r--r-- | weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java | 30 |
9 files changed, 318 insertions, 12 deletions
diff --git a/tests/bugs174/pr418129/Target.java b/tests/bugs174/pr418129/Target.java new file mode 100644 index 000000000..a3d1b2e97 --- /dev/null +++ b/tests/bugs174/pr418129/Target.java @@ -0,0 +1,27 @@ +import java.lang.annotation.*; + +interface Behavior { +String hello(); +} + +aspect Trait { + // public String Behavior.name; + + public String Behavior.hello() { + return "hello"; + } +} + +public class Target implements Behavior { + public static aspect A { +// declare @field: * Target.name: @Tagged; // NO WORKY + declare @method: * Target.hello(..): @Tagged; // NO WORKY + } + + public static void main(String []argv) throws Exception { + System.out.println(Target.class.getDeclaredMethod("hello").getDeclaredAnnotations()[0]); + } +} + +@Retention(RetentionPolicy.RUNTIME) +@interface Tagged {} diff --git a/tests/bugs174/pr418129/Target2.java b/tests/bugs174/pr418129/Target2.java new file mode 100644 index 000000000..cc8b9e839 --- /dev/null +++ b/tests/bugs174/pr418129/Target2.java @@ -0,0 +1,27 @@ +import java.lang.annotation.*; + +interface Behavior { + String hello(); +} + +aspect Trait { +// public String Behavior.name; + + public String Behavior.hello() throws java.io.IOException { + return "hello"; + } +} + +public class Target2 implements Behavior { + public static aspect A { +// declare @field: * Target2.name: @Tagged; // NO WORKY + declare @method: * Target2.hello(..): @Tagged; // NO WORKY + } + + public static void main(String []argv) throws Exception { + System.out.println(Target2.class.getDeclaredMethod("hello").getDeclaredAnnotations()[0]); + } +} + +@Retention(RetentionPolicy.RUNTIME) +@interface Tagged {} diff --git a/tests/bugs174/pr418129/Target3.java b/tests/bugs174/pr418129/Target3.java new file mode 100644 index 000000000..cba868929 --- /dev/null +++ b/tests/bugs174/pr418129/Target3.java @@ -0,0 +1,27 @@ +import java.lang.annotation.*; + +interface Behavior { + String hello(); +} + +aspect Trait { + @Wibble + public String Behavior.hello() throws java.io.IOException { + return "hello"; + } +} + +public class Target3 implements Behavior { + public static aspect A { + declare @method: * Target3.hello(..): @Tagged; + } + + public static void main(String []argv) throws Exception { + System.out.println(Target3.class.getDeclaredMethod("hello").getDeclaredAnnotations().length); + System.out.println(Target3.class.getDeclaredMethod("hello").getDeclaredAnnotations()[0]); + System.out.println(Target3.class.getDeclaredMethod("hello").getDeclaredAnnotations()[1]); + } +} + +@Retention(RetentionPolicy.RUNTIME) @interface Tagged {} +@Retention(RetentionPolicy.RUNTIME) @interface Wibble {} diff --git a/tests/bugs174/pr418129/Target4.java b/tests/bugs174/pr418129/Target4.java new file mode 100644 index 000000000..4bae09c1f --- /dev/null +++ b/tests/bugs174/pr418129/Target4.java @@ -0,0 +1,25 @@ +import java.lang.annotation.*; + +interface Behavior { + String hello(); +} + +aspect Trait { + @Tagged(31) + public String Behavior.hello() throws java.io.IOException { + return "hello"; + } +} + +public class Target4 implements Behavior { + public static aspect A { + declare @method: * Target4.hello(..): @Tagged; + } + + public static void main(String []argv) throws Exception { + System.out.println(Target4.class.getDeclaredMethod("hello").getDeclaredAnnotations().length); + System.out.println(Target4.class.getDeclaredMethod("hello").getDeclaredAnnotations()[0]); + } +} + +@Retention(RetentionPolicy.RUNTIME) @interface Tagged { int value() default 42;} diff --git a/tests/src/org/aspectj/systemtest/ajc174/Ajc174Tests.java b/tests/src/org/aspectj/systemtest/ajc174/Ajc174Tests.java index 06af6a53b..1e300dd0a 100644 --- a/tests/src/org/aspectj/systemtest/ajc174/Ajc174Tests.java +++ b/tests/src/org/aspectj/systemtest/ajc174/Ajc174Tests.java @@ -21,6 +21,22 @@ import org.aspectj.testing.XMLBasedAjcTestCase; */ public class Ajc174Tests extends org.aspectj.testing.XMLBasedAjcTestCase { + public void testAnnotatedItd_418129() throws Exception { + runTest("annotated itd"); + } + + public void testAnnotatedItd_418129_2() throws Exception { + runTest("annotated itd 2"); + } + + public void testAnnotatedItd_418129_3() throws Exception { + runTest("annotated itd 3"); + } + + public void testAnnotatedItd_418129_4() throws Exception { + runTest("annotated itd 4"); + } + public void testSuperItdCtor_413378() throws Exception { runTest("super itd ctor"); } diff --git a/tests/src/org/aspectj/systemtest/ajc174/ajc174.xml b/tests/src/org/aspectj/systemtest/ajc174/ajc174.xml index 85ff2af8b..5b47cf4d3 100644 --- a/tests/src/org/aspectj/systemtest/ajc174/ajc174.xml +++ b/tests/src/org/aspectj/systemtest/ajc174/ajc174.xml @@ -2,6 +2,67 @@ <suite> + <ajc-test dir="bugs174/pr418129" title="annotated itd"> + <compile files="Target.java" options="-1.5 -showWeaveInfo"> + <message kind="weave" text="Type 'Behavior' (Target.java) has intertyped method from 'Trait' (Target.java:'java.lang.String Behavior.hello()')"/> + <message kind="weave" text="Type 'Target' (Target.java) has intertyped method from 'Trait' (Target.java:'java.lang.String Behavior.hello()')"/> + <message kind="weave" text="'public java.lang.String Target.hello()' (Target.java) is annotated with @Tagged method annotation from 'Target$A' (Target.java:18)"/> + </compile> + <run class="Target"> + <stdout> + <line text="@Tagged()"/> + </stdout> + </run> + </ajc-test> + + <!-- declared with throws exception --> + <ajc-test dir="bugs174/pr418129" title="annotated itd 2"> + <compile files="Target2.java" options="-1.5 -showWeaveInfo"> + <message kind="weave" text="Type 'Behavior' (Target2.java) has intertyped method from 'Trait' (Target2.java:'java.lang.String Behavior.hello()')"/> + <message kind="weave" text="Type 'Target2' (Target2.java) has intertyped method from 'Trait' (Target2.java:'java.lang.String Behavior.hello()')"/> + <message kind="weave" text="'public java.lang.String Target2.hello()' (Target2.java) is annotated with @Tagged method annotation from 'Target2$A' (Target2.java:18)"/> + </compile> + <run class="Target2"> + <stdout> + <line text="@Tagged()"/> + </stdout> + </run> + </ajc-test> + + <!-- already annotated with another annotation --> + <ajc-test dir="bugs174/pr418129" title="annotated itd 3"> + <compile files="Target3.java" options="-1.5 -showWeaveInfo"> + <message kind="weave" text="Type 'Behavior' (Target3.java) has intertyped method from 'Trait' (Target3.java:'java.lang.String Behavior.hello()')"/> + <message kind="weave" text="Type 'Target3' (Target3.java) has intertyped method from 'Trait' (Target3.java:'java.lang.String Behavior.hello()')"/> + <message kind="weave" text="'public java.lang.String Target3.hello()' (Target3.java) is annotated with @Tagged method annotation from 'Target3$A' (Target3.java:16)"/> + </compile> + <run class="Target3"> + <stdout> + <line text="2"/> + <line text="@Wibble()"/> + <line text="@Tagged()"/> + </stdout> + </run> + </ajc-test> + + <!-- already annotated with the same annotation --> + <ajc-test dir="bugs174/pr418129" title="annotated itd 4"> + <compile files="Target4.java" options="-1.5 -showWeaveInfo"> + <message kind="weave" text="Type 'Behavior' (Target4.java) has intertyped method from 'Trait' (Target4.java:'java.lang.String Behavior.hello()')"/> + <message kind="weave" text="Type 'Target4' (Target4.java) has intertyped method from 'Trait' (Target4.java:'java.lang.String Behavior.hello()')"/> + <!-- warning turned off as it gets confusing - when the itd on the interface is hit by a deca --> + <!-- + <message kind="warning" text="java.lang.String Target4.hello() - already has an annotation of type Tagged, cannot add a second instance [Xlint:elementAlreadyAnnotated]"/> + --> + </compile> + <run class="Target4"> + <stdout> + <line text="1"/> + <line text="@Tagged(value=31)"/> + </stdout> + </run> + </ajc-test> + <ajc-test dir="bugs174/pr413378" title="super itd ctor"> <compile files="Code.java" options="-1.5 -showWeaveInfo"> <message kind="weave" text="Type 'Child' (Code.java) has intertyped constructor from 'MyTest' (Code.java:'void Child.<init>(java.lang.String, int)')"/> diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java index fbb4d9292..2c352a258 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java @@ -68,6 +68,7 @@ import org.aspectj.weaver.ConcreteTypeMunger; import org.aspectj.weaver.IClassWeaver; import org.aspectj.weaver.IntMap; import org.aspectj.weaver.Member; +import org.aspectj.weaver.MemberKind; import org.aspectj.weaver.MissingResolvedTypeWithKnownSignature; import org.aspectj.weaver.NameMangler; import org.aspectj.weaver.NewConstructorTypeMunger; @@ -532,8 +533,7 @@ class BcelClassWeaver implements IClassWeaver { // finally, if we changed, we add in the introduced methods. if (isChanged) { clazz.getOrCreateWeaverStateInfo(inReweavableMode); - weaveInAddedMethods(); // FIXME asc are these potentially affected - // by declare annotation? + weaveInAddedMethods(); } if (inReweavableMode) { @@ -893,15 +893,91 @@ class BcelClassWeaver implements IClassWeaver { isChanged = weaveAtMethodOnITDSRepeatedly(allDecams, itdMethodsCtors, reportedProblems); } - // deal with all the other methods... - List<LazyMethodGen> members = clazz.getMethodGens(); List<DeclareAnnotation> decaMs = getMatchingSubset(allDecams, clazz.getType()); if (decaMs.isEmpty()) { return false; // nothing to do } + + Set<DeclareAnnotation> unusedDecams = new HashSet<DeclareAnnotation>(); + unusedDecams.addAll(decaMs); + + // These methods may have been targeted with declare annotation. Example: ITD on an interface + // where the top most implementor gets a real method. The top most implementor method + // is an 'addedLazyMethodGen' + if (addedLazyMethodGens!=null) { + for (LazyMethodGen method: addedLazyMethodGens) { + // They have no resolvedmember of their own, conjure one up for matching purposes + ResolvedMember resolvedmember = + new ResolvedMemberImpl(ResolvedMember.METHOD,method.getEnclosingClass().getType(),method.getAccessFlags(), + BcelWorld.fromBcel(method.getReturnType()),method.getName(), + BcelWorld.fromBcel(method.getArgumentTypes()),UnresolvedType.forNames(method.getDeclaredExceptions())); + resolvedmember.setAnnotationTypes(method.getAnnotationTypes()); + resolvedmember.setAnnotations(method.getAnnotations()); + + List<DeclareAnnotation> worthRetrying = new ArrayList<DeclareAnnotation>(); + boolean modificationOccured = false; + for (DeclareAnnotation decam: decaMs) { + if (decam.matches(resolvedmember, world)) { + if (doesAlreadyHaveAnnotation(resolvedmember, decam, reportedProblems,false)) { + // remove the declare @method since don't want an error when the annotation is already there + unusedDecams.remove(decam); + continue; + } + + AnnotationGen a = ((BcelAnnotation) decam.getAnnotation()).getBcelAnnotation(); + // create copy to get the annotation type into the right constant pool + AnnotationAJ aj = new BcelAnnotation(new AnnotationGen(a, clazz.getConstantPool(), true),world); + method.addAnnotation(aj); + resolvedmember.addAnnotation(decam.getAnnotation()); + + AsmRelationshipProvider.addDeclareAnnotationMethodRelationship(decam.getSourceLocation(), + clazz.getName(), resolvedmember, world.getModelAsAsmManager()); + reportMethodCtorWeavingMessage(clazz, resolvedmember, decam, method.getDeclarationLineNumber()); + isChanged = true; + modificationOccured = true; + unusedDecams.remove(decam); + } else if (!decam.isStarredAnnotationPattern()) { + // an annotation is specified that might be put on by a subsequent decaf + worthRetrying.add(decam); + } + } + + // Multiple secondary passes + while (!worthRetrying.isEmpty() && modificationOccured) { + modificationOccured = false; + // lets have another go + List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>(); + for (DeclareAnnotation decam : worthRetrying) { + if (decam.matches(resolvedmember, world)) { + if (doesAlreadyHaveAnnotation(resolvedmember, decam, reportedProblems,false)) { + // remove the declare @method since don't + // want an error when + // the annotation is already there + unusedDecams.remove(decam); + continue; // skip this one... + } + AnnotationGen a = ((BcelAnnotation) decam.getAnnotation()).getBcelAnnotation(); + // create copy to get the annotation type into the right constant pool + AnnotationAJ aj = new BcelAnnotation(new AnnotationGen(a, clazz.getConstantPool(), true),world); + method.addAnnotation(aj); + resolvedmember.addAnnotation(decam.getAnnotation()); + AsmRelationshipProvider.addDeclareAnnotationMethodRelationship(decam.getSourceLocation(), + clazz.getName(), resolvedmember, world.getModelAsAsmManager());// getMethod()); + isChanged = true; + modificationOccured = true; + forRemoval.add(decam); + unusedDecams.remove(decam); + } + } + worthRetrying.removeAll(forRemoval); + } + } + } + + + // deal with all the other methods... + List<LazyMethodGen> members = clazz.getMethodGens(); if (!members.isEmpty()) { - Set<DeclareAnnotation> unusedDecams = new HashSet<DeclareAnnotation>(); - unusedDecams.addAll(decaMs); for (int memberCounter = 0; memberCounter < members.size(); memberCounter++) { LazyMethodGen mg = members.get(memberCounter); if (!mg.getName().startsWith(NameMangler.PREFIX)) { @@ -913,7 +989,7 @@ class BcelClassWeaver implements IClassWeaver { for (DeclareAnnotation decaM : decaMs) { if (decaM.matches(mg.getMemberView(), world)) { - if (doesAlreadyHaveAnnotation(mg.getMemberView(), decaM, reportedProblems)) { + if (doesAlreadyHaveAnnotation(mg.getMemberView(), decaM, reportedProblems,true)) { // remove the declare @method since don't want // an error when the annotation is already there unusedDecams.remove(decaM); @@ -954,7 +1030,7 @@ class BcelClassWeaver implements IClassWeaver { List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>(); for (DeclareAnnotation decaM : worthRetrying) { if (decaM.matches(mg.getMemberView(), world)) { - if (doesAlreadyHaveAnnotation(mg.getMemberView(), decaM, reportedProblems)) { + if (doesAlreadyHaveAnnotation(mg.getMemberView(), decaM, reportedProblems,true)) { // remove the declare @method since don't // want an error when // the annotation is already there @@ -1347,7 +1423,7 @@ class BcelClassWeaver implements IClassWeaver { unusedDecafs.remove(decaf); } else { if (!dontAddTwice(decaf, dontAddMeTwice)) { - if (doesAlreadyHaveAnnotation(field, decaf, reportedProblems)) { + if (doesAlreadyHaveAnnotation(field, decaf, reportedProblems,true )) { // remove the declare @field since don't want an error when the annotation is already there unusedDecafs.remove(decaf); continue; @@ -1389,7 +1465,7 @@ class BcelClassWeaver implements IClassWeaver { } else { // below code is for recursive things unusedDecafs.remove(decaF); - if (doesAlreadyHaveAnnotation(field, decaF, reportedProblems)) { + if (doesAlreadyHaveAnnotation(field, decaF, reportedProblems,true)) { continue; } field.addAnnotation(decaF.getAnnotation()); @@ -1486,9 +1562,9 @@ class BcelClassWeaver implements IClassWeaver { /** * Check if a resolved member (field/method/ctor) already has an annotation, if it does then put out a warning and return true */ - private boolean doesAlreadyHaveAnnotation(ResolvedMember rm, DeclareAnnotation deca, List<Integer> reportedProblems) { + private boolean doesAlreadyHaveAnnotation(ResolvedMember rm, DeclareAnnotation deca, List<Integer> reportedProblems, boolean reportError) { if (rm.hasAnnotation(deca.getAnnotationType())) { - if (world.getLint().elementAlreadyAnnotated.isEnabled()) { + if (reportError && world.getLint().elementAlreadyAnnotated.isEnabled()) { Integer uniqueID = new Integer(rm.hashCode() * deca.hashCode()); if (!reportedProblems.contains(uniqueID)) { reportedProblems.add(uniqueID); diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java index 9fce00cd4..4dfb30e68 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java @@ -345,6 +345,22 @@ public class BcelWorld extends World implements Repository { return ret; } + public static Type[] makeBcelTypes(String[] types) { + if (types == null || types.length==0 ) { + return null; + } + Type[] ret = new Type[types.length]; + for (int i=0, len=types.length; i<len; i++) { + ret[i] = makeBcelType(types[i]); + } + return ret; + } + + public static Type makeBcelType(String type) { + return Type.getType(type); + } + + static String[] makeBcelTypesAsClassNames(UnresolvedType[] types) { String[] ret = new String[types.length]; for (int i = 0, len = types.length; i < len; i++) { @@ -1239,4 +1255,5 @@ public class BcelWorld extends World implements Repository { public void demote(ResolvedType type) { typeMap.demote(type); } + } diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java index b66c6106d..ea0248335 100644 --- a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java +++ b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java @@ -124,6 +124,15 @@ public final class LazyMethodGen implements Traceable { List<BcelShadow> matchedShadows; // Used for interface introduction - this is the type of the interface the method is technically on public ResolvedType definingType = null; + + static class LightweightBcelMethod extends BcelMethod { + + LightweightBcelMethod(BcelObjectType declaringType, Method method) { + super(declaringType, method); + // TODO Auto-generated constructor stub + } + + } public LazyMethodGen(int modifiers, Type returnType, String name, Type[] paramTypes, String[] declaredExceptions, LazyClassGen enclosingClass) { @@ -304,6 +313,27 @@ public final class LazyMethodGen implements Traceable { memberView.addParameterAnnotation(parameterNumber, anno); } } + + public ResolvedType[] getAnnotationTypes() { + initialize(); + if (memberView == null && newAnnotations!=null && newAnnotations.size()!=0) { + // TODO Ignoring removed annotations for now + ResolvedType[] annotationTypes = new ResolvedType[newAnnotations.size()]; + for (int a=0,len=newAnnotations.size();a<len;a++) { + annotationTypes[a] = newAnnotations.get(a).getType(); + } + return annotationTypes; + } + return null; + } + + public AnnotationAJ[] getAnnotations() { + initialize(); + if (memberView == null && newAnnotations!=null && newAnnotations.size()!=0) { + return newAnnotations.toArray(new AnnotationAJ[newAnnotations.size()]); + } + return null; + } public boolean hasAnnotation(UnresolvedType annotationType) { initialize(); |