]> source.dussan.org Git - aspectj.git/commitdiff
Declare annotation: Does weaving of @field, @method, @ctor - copes with recursive...
authoraclement <aclement>
Thu, 10 Mar 2005 17:56:52 +0000 (17:56 +0000)
committeraclement <aclement>
Thu, 10 Mar 2005 17:56:52 +0000 (17:56 +0000)
weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java

index e7b6b93c2bdee11434767b084da697d949ac96cd..2eff5161258c0c2cba044679b4af91a91e7294d6 100644 (file)
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.aspectj.apache.bcel.Constants;
+import org.aspectj.apache.bcel.classfile.Field;
 import org.aspectj.apache.bcel.generic.BranchInstruction;
 import org.aspectj.apache.bcel.generic.CPInstruction;
 import org.aspectj.apache.bcel.generic.ConstantPoolGen;
@@ -48,16 +49,17 @@ import org.aspectj.apache.bcel.generic.ReturnInstruction;
 import org.aspectj.apache.bcel.generic.Select;
 import org.aspectj.apache.bcel.generic.Type;
 import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.ISourceLocation;
 import org.aspectj.util.FuzzyBoolean;
 import org.aspectj.util.PartialOrder;
 import org.aspectj.weaver.AjAttribute;
 import org.aspectj.weaver.AjcMemberMaker;
+import org.aspectj.weaver.AsmRelationshipProvider;
 import org.aspectj.weaver.BCException;
 import org.aspectj.weaver.ConcreteTypeMunger;
 import org.aspectj.weaver.IClassWeaver;
 import org.aspectj.weaver.IntMap;
 import org.aspectj.weaver.Member;
-import org.aspectj.weaver.WeaverMetrics;
 import org.aspectj.weaver.NameMangler;
 import org.aspectj.weaver.NewFieldTypeMunger;
 import org.aspectj.weaver.ResolvedMember;
@@ -65,8 +67,10 @@ import org.aspectj.weaver.ResolvedTypeX;
 import org.aspectj.weaver.Shadow;
 import org.aspectj.weaver.ShadowMunger;
 import org.aspectj.weaver.WeaverMessages;
+import org.aspectj.weaver.WeaverMetrics;
 import org.aspectj.weaver.WeaverStateInfo;
 import org.aspectj.weaver.Shadow.Kind;
+import org.aspectj.weaver.patterns.DeclareAnnotation;
 import org.aspectj.weaver.patterns.FastMatchInfo;
 
 class BcelClassWeaver implements IClassWeaver {
@@ -301,7 +305,6 @@ class BcelClassWeaver implements IClassWeaver {
     // ----
     
     public boolean weave() {
-
         if (clazz.isWoven() && !clazz.isReweavable()) {
                world.showMessage(IMessage.ERROR, 
                          WeaverMessages.format(WeaverMessages.ALREADY_WOVEN,clazz.getType().getName()),
@@ -332,6 +335,10 @@ class BcelClassWeaver implements IClassWeaver {
                        if (inReweavableMode) aspectsAffectingType.add(munger.getAspectType().getName());
                }
         }
+
+        // Weave special half type/half shadow mungers... 
+        isChanged = weaveDeclareAtMethodCtor(clazz) || isChanged;
+        isChanged = weaveDeclareAtField(clazz)      || isChanged;
         
         // XXX do major sort of stuff
         // sort according to:  Major:  type hierarchy
@@ -365,7 +372,6 @@ class BcelClassWeaver implements IClassWeaver {
         }
         if (! isChanged) return false;
         
-        
         // now we weave all but the initialization shadows
                for (Iterator i = methodGens.iterator(); i.hasNext();) {
                        LazyMethodGen mg = (LazyMethodGen)i.next();
@@ -387,7 +393,7 @@ class BcelClassWeaver implements IClassWeaver {
                // finally, if we changed, we add in the introduced methods.
         if (isChanged) {
                clazz.getOrCreateWeaverStateInfo();
-                       weaveInAddedMethods();
+                       weaveInAddedMethods(); // FIXME asc are these potentially affected by declare annotation?
         }
         
         if (inReweavableMode) {
@@ -402,6 +408,160 @@ class BcelClassWeaver implements IClassWeaver {
         return isChanged;
     }
 
+
+    
+    
+    /**
+     * Weave any declare @method/@ctor statements into the members of the supplied class
+     */
+    private boolean weaveDeclareAtMethodCtor(LazyClassGen clazz) {
+               
+               boolean isChanged = false;
+        List decaMs = getMatchingSubset(world.getDeclareAnnotationOnMethods(),clazz.getType());
+        List members = clazz.getMethodGens();
+               if (!members.isEmpty() && !decaMs.isEmpty()) {
+          // go through all the fields
+          for (int memberCounter = 0;memberCounter<members.size();memberCounter++) {
+            LazyMethodGen mg = (LazyMethodGen)members.get(memberCounter);
+            
+            // Single first pass
+            List worthRetrying = new ArrayList();
+            boolean modificationOccured = false;
+            // go through all the declare @field statements
+            for (Iterator iter = decaMs.iterator(); iter.hasNext();) {
+                               DeclareAnnotation decaM = (DeclareAnnotation) iter.next();
+                               
+                               if (decaM.matches(mg.getMemberView(),world)) {
+                                       if (doesAlreadyHaveAnnotation(mg.getMemberView(),decaM,true)) continue; // skip this one...
+                                       mg.addAnnotation(decaM.getAnnotationX());
+                                       //System.err.println("Mloc ("+mg+") ="+mg.getSourceLocation());
+                                       AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaM.getSourceLocation(),clazz.getName(),mg.getMethod());
+                                       isChanged = true;
+                                       modificationOccured = true;
+                               } else {
+                                       if (!decaM.isStarredAnnotationPattern()) 
+                                               worthRetrying.add(decaM); // an annotation is specified that might be put on by a subsequent decaf
+                               }
+                       }
+                       
+            // Multiple secondary passes
+            while (!worthRetrying.isEmpty() && modificationOccured) {
+              modificationOccured = false;
+              // lets have another go
+              List forRemoval = new ArrayList();
+              for (Iterator iter = worthRetrying.iterator(); iter.hasNext();) {
+                               DeclareAnnotation decaM = (DeclareAnnotation) iter.next();
+                               if (decaM.matches(mg.getMemberView(),world)) {
+                                       if (doesAlreadyHaveAnnotation(mg.getMemberView(),decaM,false)) continue; // skip this one...
+                                       mg.addAnnotation(decaM.getAnnotationX());
+                                       AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaM.getSourceLocation(),mg.getSourceLocation());
+                                       isChanged = true;
+                                       modificationOccured = true;
+                                       forRemoval.add(decaM);
+                               }
+                         }
+                         worthRetrying.removeAll(forRemoval);
+            }
+          }
+        }
+               return isChanged;
+    }
+    
+       /**
+        * Looks through a list of declare annotation statements and only returns
+        * those that could possibly match on a field/method/ctor in type.
+        */
+       private List getMatchingSubset(List declareAnnotations, ResolvedTypeX type) {
+           List subset = new ArrayList();
+           //System.err.println("For type="+type+"\nPrior set: "+declareAnnotations);
+           for (Iterator iter = declareAnnotations.iterator(); iter.hasNext();) {
+                       DeclareAnnotation da = (DeclareAnnotation) iter.next();
+                       if (da.couldEverMatch(type)) {
+                               subset.add(da);
+                       }
+               }
+               //System.err.println("After set: "+subset);
+               return subset;
+       }
+
+       /**
+        * Weave any declare @field statements into the fields of the supplied class
+        */
+       private boolean weaveDeclareAtField(LazyClassGen clazz) {
+         
+        // BUGWARNING not getting enough warnings out on declare @field ?
+        // There is a potential problem here with warnings not coming out - this
+        // will occur if they are created on the second iteration round this loop.
+        // We currently deactivate error reporting for the second time round.
+        // A possible solution is to record what annotations were added by what
+        // 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());
+               boolean isChanged = false;
+               Field[] fields = clazz.getFieldGens();
+               if (fields!=null && !decaFs.isEmpty()) {
+          // go through all the fields
+          for (int fieldCounter = 0;fieldCounter<fields.length;fieldCounter++) {
+            BcelField aBcelField = new BcelField(clazz.getBcelObjectType(),fields[fieldCounter]);
+           
+            // Single first pass
+            List worthRetrying = new ArrayList();
+            boolean modificationOccured = false;
+            // go through all the declare @field statements
+            for (Iterator iter = decaFs.iterator(); iter.hasNext();) {
+                               DeclareAnnotation decaF = (DeclareAnnotation) iter.next();
+                               if (decaF.matches(aBcelField,world)) {
+                                       if (doesAlreadyHaveAnnotation(aBcelField,decaF,true)) continue; // skip this one...
+                                       aBcelField.addAnnotation(decaF.getAnnotationX());
+                                       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
+                               }
+                       }
+                       
+            // Multiple secondary passes
+            while (!worthRetrying.isEmpty() && modificationOccured) {
+              modificationOccured = false;
+              // lets have another go
+              List forRemoval = new ArrayList();
+              for (Iterator iter = worthRetrying.iterator(); iter.hasNext();) {
+                               DeclareAnnotation decaF = (DeclareAnnotation) iter.next();
+                               if (decaF.matches(aBcelField,world)) {
+                                       if (doesAlreadyHaveAnnotation(aBcelField,decaF,false)) continue; // skip this one...
+                                       aBcelField.addAnnotation(decaF.getAnnotationX());
+                                       AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]);
+                                       isChanged = true;
+                                       modificationOccured = true;
+                                       forRemoval.add(decaF);
+                               }
+                         }
+                         worthRetrying.removeAll(forRemoval);
+            }
+          }
+        }
+               return isChanged;
+       }
+    
+    /**
+     * 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,boolean reportProblems) {
+         if (rm.hasAnnotation(deca.getAnnotationTypeX())) {
+           if (reportProblems) {
+        world.getLint().elementAlreadyAnnotated.signal(
+               new String[]{rm.toString(),deca.getAnnotationTypeX().toString()},
+               rm.getSourceLocation(),new ISourceLocation[]{deca.getSourceLocation()});
+           }
+       return true;
+         }
+         return false;
+       }
+       
        private Set findAspectsForMungers(LazyMethodGen mg) {
                Set aspectsAffectingType = new HashSet();
                for (Iterator iter = mg.matchedShadows.iterator(); iter.hasNext();) {