Browse Source

Declare annotation: Does weaving of @field, @method, @ctor - copes with recursive application.

tags/V1_5_0M2
aclement 19 years ago
parent
commit
66b847129d
1 changed files with 164 additions and 4 deletions
  1. 164
    4
      weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java

+ 164
- 4
weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java View 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();) {

Loading…
Cancel
Save