From 2314eaf48a35a249e63fae12151ce926ea98c97c Mon Sep 17 00:00:00 2001 From: Andy Clement Date: Tue, 1 Oct 2013 10:00:14 -0700 Subject: [PATCH] 418129: annos on top most implementor method --- tests/bugs174/pr418129/Target.java | 27 +++++ tests/bugs174/pr418129/Target2.java | 27 +++++ tests/bugs174/pr418129/Target3.java | 27 +++++ tests/bugs174/pr418129/Target4.java | 25 +++++ .../systemtest/ajc174/Ajc174Tests.java | 16 +++ .../org/aspectj/systemtest/ajc174/ajc174.xml | 61 +++++++++++ .../aspectj/weaver/bcel/BcelClassWeaver.java | 100 +++++++++++++++--- .../org/aspectj/weaver/bcel/BcelWorld.java | 17 +++ .../aspectj/weaver/bcel/LazyMethodGen.java | 30 ++++++ 9 files changed, 318 insertions(+), 12 deletions(-) create mode 100644 tests/bugs174/pr418129/Target.java create mode 100644 tests/bugs174/pr418129/Target2.java create mode 100644 tests/bugs174/pr418129/Target3.java create mode 100644 tests/bugs174/pr418129/Target4.java 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 members = clazz.getMethodGens(); List decaMs = getMatchingSubset(allDecams, clazz.getType()); if (decaMs.isEmpty()) { return false; // nothing to do } + + Set unusedDecams = new HashSet(); + 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 worthRetrying = new ArrayList(); + 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 forRemoval = new ArrayList(); + 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 members = clazz.getMethodGens(); if (!members.isEmpty()) { - Set unusedDecams = new HashSet(); - 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 forRemoval = new ArrayList(); 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 reportedProblems) { + private boolean doesAlreadyHaveAnnotation(ResolvedMember rm, DeclareAnnotation deca, List 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 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