]> source.dussan.org Git - aspectj.git/commitdiff
418129: annos on top most implementor method
authorAndy Clement <aclement@gopivotal.com>
Tue, 1 Oct 2013 17:00:14 +0000 (10:00 -0700)
committerAndy Clement <aclement@gopivotal.com>
Fri, 18 Oct 2013 18:36:29 +0000 (11:36 -0700)
tests/bugs174/pr418129/Target.java [new file with mode: 0644]
tests/bugs174/pr418129/Target2.java [new file with mode: 0644]
tests/bugs174/pr418129/Target3.java [new file with mode: 0644]
tests/bugs174/pr418129/Target4.java [new file with mode: 0644]
tests/src/org/aspectj/systemtest/ajc174/Ajc174Tests.java
tests/src/org/aspectj/systemtest/ajc174/ajc174.xml
weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java
weaver/src/org/aspectj/weaver/bcel/BcelWorld.java
weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java

diff --git a/tests/bugs174/pr418129/Target.java b/tests/bugs174/pr418129/Target.java
new file mode 100644 (file)
index 0000000..a3d1b2e
--- /dev/null
@@ -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 (file)
index 0000000..cc8b9e8
--- /dev/null
@@ -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 (file)
index 0000000..cba8689
--- /dev/null
@@ -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 (file)
index 0000000..4bae09c
--- /dev/null
@@ -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;}
index 06af6a53bea16de4f9c32e3b28cfbb56d18790a2..1e300dd0a58681b1b4c787244563ba9ad8e90c4a 100644 (file)
@@ -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");
        }
index 85ff2af8bb9b2b0e7e3a4bc2847990255342ce0f..5b47cf4d35c495d9f6ee54ae401812b7945e4e95 100644 (file)
@@ -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.&lt;init&gt;(java.lang.String, int)')"/>
index fbb4d92923c064f6433a76644c9c496ca5509df4..2c352a258d7956b0d6eb3010d3e67680f72fe66e 100644 (file)
@@ -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);
index 9fce00cd476e7c8958a32813d243e3c2c2055e31..4dfb30e682d677d9860245bd0310f7974724c4aa 100644 (file)
@@ -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);
        }
+
 }
index b66c6106d0d098ad7561e77588f22c2f368f6e36..ea0248335c7dfb79b43941ad9e9b21da7d2271d0 100644 (file)
@@ -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();