@@ -267,4 +267,36 @@ public class AnnotationBinding extends XMLBasedAjcTestCase { | |||
public void testCallsAndExecutionsOfStaticMethods() { | |||
runTest("binding with static methods"); | |||
} | |||
///////////////////////////////////////////////////////////////////////////////// | |||
// annotation binding with ITDs | |||
public void testAnnotationBindingAndITDs1() { | |||
runTest("simple binding annotation values where itd method is annotated"); | |||
} | |||
public void testAnnotationBindingAndITDs2() { | |||
runTest("simple binding annotation values where itd field is annotated"); | |||
} | |||
public void testAnnotationBindingAndITDs3() { | |||
runTest("simple binding annotation values where itd ctor is annotated"); | |||
} | |||
public void testAnnotationBindingAndITDs4() { | |||
runTest("simple binding annotation values where itd method is annotated via declare"); | |||
} | |||
public void testAnnotationBindingAndITDs5() { | |||
runTest("simple binding annotation values where itd field is annotated via declare"); | |||
} | |||
public void testAnnotationBindingAndITDs6() { | |||
runTest("simple binding annotation values where itd field is annotated multiple times via declare"); | |||
} | |||
public void testAnnotationBindingAndITDs7() { | |||
runTest("simple binding annotation values where itd ctor is annotated via declare"); | |||
} | |||
} |
@@ -76,7 +76,11 @@ public class Annotations extends XMLBasedAjcTestCase { | |||
// more implementation work needed before this test passes | |||
public void testAnnotatedITDs() { | |||
try { | |||
runTest("annotated itds"); | |||
} finally { | |||
System.err.println(ajc.getLastCompilationResult().getStandardError()); | |||
} | |||
} | |||
public void testAnnotatedITDsWithWrongAnnotationType() { |
@@ -486,39 +486,57 @@ | |||
<ajc-test dir="java5/annotations/itds" vm="1.5" title="nasty annotation and itds test"> | |||
<compile files="AnnotationsAndITDs.aj" options="-1.5"> | |||
<message kind="warning" line="25" text="execution(@SomeAnnotation ...)"/> | |||
<message kind="warning" line="28" text="execution(@SomeAnnotation ...)"/> | |||
<message kind="warning" line="52" text="execution(@SomeAnnotation ...)"/> | |||
<message kind="warning" line="53" text="execution(@SomeAnnotation ...)"/> | |||
<!-- first two are ITCs, second two are ITCs annotated via declare @ctor, third is default ctor --> | |||
<message kind="warning" line="17" text="execution(@SomeAnnotation ...new(..)"/> | |||
<message kind="warning" line="20" text="execution(@SomeAnnotation ...new(..)"/> | |||
<message kind="warning" line="45" text="execution(@SomeAnnotation ...new(..)"/> | |||
<message kind="warning" line="46" text="execution(@SomeAnnotation ...new(..)"/> | |||
<message kind="warning" line="180" text="execution(@SomeAnnotation ...new(..)"/> | |||
<!-- first four are fields annotated via declare, last two are directly annotated ITDs --> | |||
<message kind="warning" line="59" text="set(@SomeAnnotation...)"/> | |||
<message kind="warning" line="60" text="set(@SomeAnnotation...)"/> | |||
<message kind="warning" line="70" text="set(@SomeAnnotation...)"/> | |||
<message kind="warning" line="71" text="set(@SomeAnnotation...)"/> | |||
<message kind="warning" line="76" text="set(@SomeAnnotation...)"/> | |||
<message kind="warning" line="77" text="set(@SomeAnnotation...)"/> | |||
<!-- annotations added via declare --> | |||
<message kind="warning" line="175" text="si(@SomeAnnotation...)"/> | |||
<message kind="warning" line="180" text="si(@SomeAnnotation...)"/> | |||
<message kind="warning" line="25" text="execution(@SomeAnnotation ...)"/> | |||
<message kind="warning" line="28" text="execution(@SomeAnnotation ...)"/> | |||
<message kind="warning" line="52" text="execution(@SomeAnnotation ...)"/> | |||
<message kind="warning" line="53" text="execution(@SomeAnnotation ...)"/> | |||
<!--message kind="warning" line="70" text="set(@SomeAnnotation...)"/> | |||
<message kind="warning" line="71" text="set(@SomeAnnotation...)"/--> | |||
</compile> | |||
<run class="AnnotationsAndITDs"> | |||
<stdout> | |||
<line text="@type System"/> | |||
<line text="hello AnnotationsAndITDs"/> | |||
<line text="goodbye String"/> | |||
<line text="x Object"/> | |||
<line text="y Integer"/> | |||
<stderr> | |||
<line text="@type java.lang.System (AnnotationsAndITDs.aj:0)"/> | |||
<line text="hello AnnotationsAndITDs (AnnotationsAndITDs.aj:17)"/> | |||
<line text="goodbye java.lang.String (AnnotationsAndITDs.aj:20)"/> | |||
<line text="goodbye java.lang.String (AnnotationsAndITDs.aj:20)"/> | |||
<line text="y java.lang.Integer (AnnotationsAndITDs.aj:28)"/> | |||
<line text="d java.lang.Double (AnnotationsAndITDs.aj:70)"/> | |||
<line text="f java.lang.Double (AnnotationsAndITDs.aj:71)"/> | |||
<line text="@type java.lang.System (AnnotationsAndITDs.aj:0)"/> | |||
<line text="@field ITDMe2 (AnnotationsAndITDs.aj:59)"/> | |||
<line text="@field ITDMe2 (AnnotationsAndITDs.aj:60)"/> | |||
<line text="@cons java.lang.String (AnnotationsAndITDs.aj:45)"/> | |||
<line text="@field ITDMe2 (AnnotationsAndITDs.aj:59)"/> | |||
<line text="@field ITDMe2 (AnnotationsAndITDs.aj:60)"/> | |||
<line text="@cons java.lang.String (AnnotationsAndITDs.aj:46)"/> | |||
<line text="@cons java.lang.String (AnnotationsAndITDs.aj:46)"/> | |||
<line text="@method ITDMe2 (AnnotationsAndITDs.aj:53)"/> | |||
<line text="@field ITDMe2 (AnnotationsAndITDs.aj:76)"/> | |||
<line text="@field ITDMe2 (AnnotationsAndITDs.aj:77)"/> | |||
<!-- | |||
<line text="method bar has 1 params, first param annotation is @ParamAnnotation"/> | |||
<line text="d Double"/> | |||
<line text="f Double"/> | |||
<line text="@type System"/> | |||
<line text="@cons String"/> | |||
<line text="@cons String"/> | |||
<line text="@method ITDMe2"/> | |||
<line text="@method ITDMe2"/> | |||
<line text="@field ITDMe2"/> | |||
<line text="@field ITDMe2"/> | |||
</stdout> | |||
--> | |||
</stderr> | |||
</run> | |||
</ajc-test> | |||
@@ -1066,6 +1084,7 @@ | |||
<message kind="warning" line="8" text="annotated field"/> | |||
<message kind="warning" line="10" text="annotated method"/> | |||
<message kind="warning" line="12" text="annotated constructor"/> | |||
<message kind="warning" line="12" text="annotated field"/> | |||
</compile> | |||
</ajc-test> | |||
@@ -2022,9 +2041,94 @@ | |||
<compile files="DeathByAnnotations.aj" options="-1.5,-emacssym" xlintfile="ignoreTypeNotExposed.properties"/> | |||
<run class="p.q.DeathByAnnotations"/> | |||
</ajc-test> | |||
<!-- ======================================================================================= --> | |||
<!-- annotation binding with ITDs --> | |||
<!-- ======================================================================================= --> | |||
<ajc-test dir="java5/annotations/binding" title="simple binding annotation values where itd method is annotated"> | |||
<compile files="BindingWithAnnotatedItds1.aj" options="-1.5"/> | |||
<run class="BindingWithAnnotatedItds1"> | |||
<stderr> | |||
<line text="Found apple at jp execution(int A.m()) (BindingWithAnnotatedItds1.aj:8)"/> | |||
</stderr> | |||
</run> | |||
</ajc-test> | |||
<ajc-test dir="java5/annotations/binding" title="simple binding annotation values where itd field is annotated"> | |||
<compile files="BindingWithAnnotatedItds2.aj" options="-1.5"/> | |||
<run class="BindingWithAnnotatedItds2"> | |||
<stderr> | |||
<line text="Found banana at jp set(int A.i) (BindingWithAnnotatedItds2.aj:16)"/> | |||
<line text="Found apple at jp set(String A.j) (BindingWithAnnotatedItds2.aj:17)"/> | |||
<line text="Found orange at jp set(int[] A.k) (BindingWithAnnotatedItds2.aj:18)"/> | |||
</stderr> | |||
</run> | |||
</ajc-test> | |||
<ajc-test dir="java5/annotations/binding" title="simple binding annotation values where itd ctor is annotated"> | |||
<compile files="BindingWithAnnotatedItds3.aj" options="-1.5"/> | |||
<run class="BindingWithAnnotatedItds3"> | |||
<stderr> | |||
<line text="Found pear at jp execution(A(String)) (BindingWithAnnotatedItds3.aj:8)"/> | |||
<line text="Found orange at jp execution(A(int)) (BindingWithAnnotatedItds3.aj:10)"/> | |||
<line text="Found tomato at jp execution(A(boolean)) (BindingWithAnnotatedItds3.aj:12)"/> | |||
</stderr> | |||
</run> | |||
</ajc-test> | |||
<!-- ======================================================================================= --> | |||
<!-- declare annotation targetting ITDs --> | |||
<!-- ======================================================================================= --> | |||
<ajc-test dir="java5/annotations/binding" title="simple binding annotation values where itd method is annotated via declare"> | |||
<compile files="BindingWithDeclaredAnnotationItds1.aj" options="-1.5"/> | |||
<run class="BindingWithDeclaredAnnotationItds1"> | |||
<stderr> | |||
<line text="Found orange at jp call(int A.m()) (BindingWithDeclaredAnnotationItds1.aj:16)"/> | |||
<line text="Found orange at jp execution(int A.m()) (BindingWithDeclaredAnnotationItds1.aj:8)"/> | |||
<line text="Found banana at jp call(int A.n()) (BindingWithDeclaredAnnotationItds1.aj:17)"/> | |||
<line text="Found banana at jp execution(int A.n()) (BindingWithDeclaredAnnotationItds1.aj:10)"/> | |||
<line text="Found tomato at jp call(int A.o()) (BindingWithDeclaredAnnotationItds1.aj:18)"/> | |||
<line text="Found tomato at jp execution(int A.o()) (BindingWithDeclaredAnnotationItds1.aj:12)"/> | |||
</stderr> | |||
</run> | |||
</ajc-test> | |||
<ajc-test dir="java5/annotations/binding" title="simple binding annotation values where itd field is annotated via declare"> | |||
<compile files="BindingWithDeclaredAnnotationItds2.aj" options="-1.5"/> | |||
<run class="BindingWithDeclaredAnnotationItds2"> | |||
<stderr> | |||
<line text="Found orange at jp set(int A.i) (BindingWithDeclaredAnnotationItds2.aj:16)"/> | |||
<line text="Found banana at jp set(String A.j) (BindingWithDeclaredAnnotationItds2.aj:17)"/> | |||
<line text="Found apple at jp set(boolean[] A.k) (BindingWithDeclaredAnnotationItds2.aj:18)"/> | |||
</stderr> | |||
</run> | |||
</ajc-test> | |||
<ajc-test dir="java5/annotations/binding" title="simple binding annotation values where itd field is annotated multiple times via declare"> | |||
<compile files="BindingWithDeclaredAnnotationItds3.aj" options="-1.5"/> | |||
<run class="BindingWithDeclaredAnnotationItds3"> | |||
<stderr> | |||
<line text="Found fruit orange at jp set(int A.i) (BindingWithDeclaredAnnotationItds3.aj:13)"/> | |||
<line text="Found drink margarita at jp set(int A.i) (BindingWithDeclaredAnnotationItds3.aj:13)"/> | |||
</stderr> | |||
</run> | |||
</ajc-test> | |||
<ajc-test dir="java5/annotations/binding" title="simple binding annotation values where itd ctor is annotated via declare"> | |||
<compile files="BindingWithDeclaredAnnotationItds4.aj" options="-1.5"/> | |||
<run class="BindingWithDeclaredAnnotationItds4"> | |||
<stderr> | |||
<line text="Found pear at jp execution(A(String)) (BindingWithDeclaredAnnotationItds4.aj:8)"/> | |||
<line text="Found orange at jp execution(A(int)) (BindingWithDeclaredAnnotationItds4.aj:10)"/> | |||
<line text="Found tomato at jp execution(A(boolean)) (BindingWithDeclaredAnnotationItds4.aj:12)"/> | |||
</stderr> | |||
</run> | |||
</ajc-test> | |||
<!-- ============================================================== --> | |||
<!-- ============================================================== --> | |||
<ajc-test dir="options/aspectpath" title="dirs on aspectpath"> | |||
<compile files="MyAspect.aj" options="-d out"/> |
@@ -21,6 +21,7 @@ import java.util.Set; | |||
public class NewFieldTypeMunger extends ResolvedTypeMunger { | |||
public NewFieldTypeMunger(ResolvedMember signature, Set superMethodsCalled) { | |||
super(Field, signature); | |||
signature.setAnnotatedElsewhere(true); | |||
this.setSuperMethodsCalled(superMethodsCalled); | |||
} | |||
@@ -17,6 +17,9 @@ import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.lang.reflect.Modifier; | |||
import java.util.HashSet; | |||
import java.util.Iterator; | |||
import java.util.Set; | |||
import org.aspectj.bridge.ISourceLocation; | |||
@@ -28,6 +31,12 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle | |||
public String[] parameterNames = null; | |||
protected TypeX[] checkedExceptions = TypeX.NONE; | |||
private Set annotationTypes = null; | |||
// Some members are 'created' to represent other things (for example ITDs). These | |||
// members have their annotations stored elsewhere, and this flag indicates that is | |||
// the case. It is up to the caller to work out where that is! | |||
// Once determined the caller may choose to stash the annotations in this member... | |||
private boolean isAnnotatedElsewhere = false; // this field is not serialized. | |||
// these three fields hold the source location of this member | |||
@@ -101,13 +110,18 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle | |||
public boolean isAjSynthetic() { | |||
return true; | |||
} | |||
public boolean hasAnnotations() { | |||
return (annotationTypes==null); | |||
} | |||
public boolean hasAnnotation(TypeX ofType) { | |||
// The ctors don't allow annotations to be specified ... yet - but | |||
// that doesn't mean it is an error to call this method. | |||
// Normally the weaver will be working with subtypes of | |||
// this type - BcelField/BcelMethod | |||
return false; | |||
if (annotationTypes==null) return false; | |||
return annotationTypes.contains(ofType); | |||
} | |||
public ResolvedTypeX[] getAnnotationTypes() { | |||
@@ -115,9 +129,24 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle | |||
// that doesn't mean it is an error to call this method. | |||
// Normally the weaver will be working with subtypes of | |||
// this type - BcelField/BcelMethod | |||
return null; | |||
if (annotationTypes == null) return null; | |||
return (ResolvedTypeX[])annotationTypes.toArray(new ResolvedTypeX[]{}); | |||
} | |||
public void setAnnotationTypes(TypeX[] annotationtypes) { | |||
if (annotationTypes == null) annotationTypes = new HashSet(); | |||
for (int i = 0; i < annotationtypes.length; i++) { | |||
TypeX typeX = annotationtypes[i]; | |||
annotationTypes.add(typeX); | |||
} | |||
} | |||
public void addAnnotation(AnnotationX annotation) { | |||
// FIXME asc only allows for annotation types, not instances - should it? | |||
if (annotationTypes == null) annotationTypes = new HashSet(); | |||
annotationTypes.add(annotation.getSignature()); | |||
} | |||
public boolean isBridgeMethod() { | |||
return (modifiers & Constants.ACC_BRIDGE)!=0; | |||
} | |||
@@ -172,6 +201,15 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle | |||
public ResolvedMember resolve(World world) { | |||
// FIXME asc guard with a check on resolution having happened ! | |||
if (annotationTypes!=null) { | |||
Set r = new HashSet(); | |||
for (Iterator iter = annotationTypes.iterator(); iter.hasNext();) { | |||
TypeX element = (TypeX) iter.next(); | |||
r.add(world.resolve(element)); | |||
} | |||
annotationTypes = r; | |||
} | |||
return this; | |||
} | |||
@@ -244,5 +282,13 @@ public class ResolvedMember extends Member implements IHasPosition, AnnotatedEle | |||
public void setCheckedExceptions(TypeX[] checkedExceptions) { | |||
this.checkedExceptions = checkedExceptions; | |||
} | |||
public void setAnnotatedElsewhere(boolean b) { | |||
isAnnotatedElsewhere = b; | |||
} | |||
public boolean isAnnotatedElsewhere() { | |||
return isAnnotatedElsewhere; | |||
} | |||
} | |||
@@ -15,6 +15,7 @@ package org.aspectj.weaver.bcel; | |||
import java.lang.reflect.Modifier; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.Comparator; | |||
import java.util.HashMap; | |||
@@ -61,11 +62,15 @@ import org.aspectj.weaver.IClassWeaver; | |||
import org.aspectj.weaver.IntMap; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.NameMangler; | |||
import org.aspectj.weaver.NewConstructorTypeMunger; | |||
import org.aspectj.weaver.NewFieldTypeMunger; | |||
import org.aspectj.weaver.NewMethodTypeMunger; | |||
import org.aspectj.weaver.ResolvedMember; | |||
import org.aspectj.weaver.ResolvedTypeMunger; | |||
import org.aspectj.weaver.ResolvedTypeX; | |||
import org.aspectj.weaver.Shadow; | |||
import org.aspectj.weaver.ShadowMunger; | |||
import org.aspectj.weaver.TypeX; | |||
import org.aspectj.weaver.WeaverMessages; | |||
import org.aspectj.weaver.WeaverMetrics; | |||
import org.aspectj.weaver.WeaverStateInfo; | |||
@@ -115,6 +120,8 @@ class BcelClassWeaver implements IClassWeaver { | |||
private final Map addedSuperInitializers = new HashMap(); // Interface -> IfaceInitList | |||
private List addedThisInitializers = new ArrayList(); // List<NewFieldMunger> | |||
private List addedClassInitializers = new ArrayList(); // List<NewFieldMunger> | |||
private Map mapToAnnotations = new HashMap(); | |||
private BcelShadow clinitShadow = null; | |||
@@ -415,26 +422,40 @@ class BcelClassWeaver implements IClassWeaver { | |||
* Weave any declare @method/@ctor statements into the members of the supplied class | |||
*/ | |||
private boolean weaveDeclareAtMethodCtor(LazyClassGen clazz) { | |||
List reportedProblems = new ArrayList(); | |||
List allDecams = world.getDeclareAnnotationOnMethods(); | |||
if (allDecams.isEmpty()) return false; // nothing to do | |||
boolean isChanged = false; | |||
List decaMs = getMatchingSubset(world.getDeclareAnnotationOnMethods(),clazz.getType()); | |||
// deal with ITDs | |||
List itdMethodsCtors = getITDSubset(clazz,ResolvedTypeMunger.Method); | |||
itdMethodsCtors.addAll(getITDSubset(clazz,ResolvedTypeMunger.Constructor)); | |||
if (!itdMethodsCtors.isEmpty()) { | |||
// Can't use the subset called 'decaMs' as it won't be right for ITDs... | |||
isChanged = weaveAtMethodOnITDSRepeatedly(allDecams,itdMethodsCtors,reportedProblems); | |||
} | |||
// deal with all the other methods... | |||
List members = clazz.getMethodGens(); | |||
if (!members.isEmpty() && !decaMs.isEmpty()) { | |||
// go through all the fields | |||
List decaMs = getMatchingSubset(allDecams,clazz.getType()); | |||
if (decaMs.isEmpty()) return false; // nothing to do | |||
if (!members.isEmpty()) { | |||
for (int memberCounter = 0;memberCounter<members.size();memberCounter++) { | |||
LazyMethodGen mg = (LazyMethodGen)members.get(memberCounter); | |||
if (!mg.getName().startsWith(NameMangler.PREFIX)) { | |||
// 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... | |||
if (doesAlreadyHaveAnnotation(mg.getMemberView(),decaM,reportedProblems)) 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; | |||
@@ -452,7 +473,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
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... | |||
if (doesAlreadyHaveAnnotation(mg.getMemberView(),decaM,reportedProblems)) continue; // skip this one... | |||
mg.addAnnotation(decaM.getAnnotationX()); | |||
AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaM.getSourceLocation(),clazz.getName(),mg.getMethod()); | |||
isChanged = true; | |||
@@ -474,19 +495,185 @@ class BcelClassWeaver implements IClassWeaver { | |||
*/ | |||
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; | |||
} | |||
/** | |||
* Get a subset of all the type mungers defined on this aspect | |||
*/ | |||
private List getITDSubset(LazyClassGen clazz,ResolvedTypeMunger.Kind wantedKind) { | |||
List subset = new ArrayList(); | |||
Collection c = clazz.getBcelObjectType().getTypeMungers(); | |||
for (Iterator iter = c.iterator();iter.hasNext();) { | |||
BcelTypeMunger typeMunger = (BcelTypeMunger)iter.next(); | |||
if (typeMunger.getMunger().getKind()==wantedKind) | |||
subset.add(typeMunger); | |||
} | |||
return subset; | |||
} | |||
public LazyMethodGen locateAnnotationHolderForFieldMunger(LazyClassGen clazz,BcelTypeMunger fieldMunger) { | |||
NewFieldTypeMunger nftm = (NewFieldTypeMunger)fieldMunger.getMunger(); | |||
ResolvedMember lookingFor =AjcMemberMaker.interFieldInitializer(nftm.getSignature(),clazz.getType()); | |||
List meths = clazz.getMethodGens(); | |||
for (Iterator iter = meths.iterator(); iter.hasNext();) { | |||
LazyMethodGen element = (LazyMethodGen) iter.next(); | |||
if (element.getName().equals(lookingFor.getName())) return element; | |||
} | |||
return null; | |||
} | |||
// FIXME asc refactor this to neaten it up | |||
public LazyMethodGen locateAnnotationHolderForMethodCtorMunger(LazyClassGen clazz,BcelTypeMunger methodCtorMunger) { | |||
if (methodCtorMunger.getMunger() instanceof NewMethodTypeMunger) { | |||
NewMethodTypeMunger nftm = (NewMethodTypeMunger)methodCtorMunger.getMunger(); | |||
ResolvedMember lookingFor =AjcMemberMaker.interMethodBody(nftm.getSignature(),methodCtorMunger.getAspectType()); | |||
List meths = clazz.getMethodGens(); | |||
for (Iterator iter = meths.iterator(); iter.hasNext();) { | |||
LazyMethodGen element = (LazyMethodGen) iter.next(); | |||
if (element.getName().equals(lookingFor.getName()) && element.getParameterSignature().equals(lookingFor.getParameterSignature())) return element; | |||
} | |||
return null; | |||
} else if (methodCtorMunger.getMunger() instanceof NewConstructorTypeMunger) { | |||
NewConstructorTypeMunger nftm = (NewConstructorTypeMunger)methodCtorMunger.getMunger(); | |||
ResolvedMember lookingFor =AjcMemberMaker.postIntroducedConstructor(methodCtorMunger.getAspectType(),nftm.getSignature().getDeclaringType(),nftm.getSignature().getParameterTypes()); | |||
List meths = clazz.getMethodGens(); | |||
for (Iterator iter = meths.iterator(); iter.hasNext();) { | |||
LazyMethodGen element = (LazyMethodGen) iter.next(); | |||
if (element.getName().equals(lookingFor.getName()) && element.getParameterSignature().equals(lookingFor.getParameterSignature())) return element; | |||
} | |||
return null; | |||
} else { | |||
throw new RuntimeException("Not sure what this is: "+methodCtorMunger); | |||
} | |||
} | |||
/** | |||
* Applies some set of declare @field constructs (List<DeclareAnnotation>) to some bunch | |||
* of ITDfields (List<BcelTypeMunger>. It will iterate over the fields repeatedly until | |||
* everything has been applied. | |||
* | |||
*/ | |||
private boolean weaveAtFieldRepeatedly(List decaFs, List itdFields,List reportedErrors) { | |||
boolean isChanged = false; | |||
for (Iterator iter = itdFields.iterator(); iter.hasNext();) { | |||
BcelTypeMunger fieldMunger = (BcelTypeMunger) iter.next(); | |||
ResolvedMember itdIsActually = fieldMunger.getSignature(); | |||
List worthRetrying = new ArrayList(); | |||
boolean modificationOccured = false; | |||
for (Iterator iter2 = decaFs.iterator(); iter2.hasNext();) { | |||
DeclareAnnotation decaF = (DeclareAnnotation) iter2.next(); | |||
if (decaF.matches(itdIsActually,world)) { | |||
LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,fieldMunger); | |||
if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaF,reportedErrors)) continue; // skip this one... | |||
annotationHolder.addAnnotation(decaF.getAnnotationX()); | |||
//FIXME asc you need to add relationships for these things | |||
// 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 | |||
} | |||
} | |||
while (!worthRetrying.isEmpty() && modificationOccured) { | |||
modificationOccured = false; | |||
List forRemoval = new ArrayList(); | |||
for (Iterator iter2 = worthRetrying.iterator(); iter.hasNext();) { | |||
DeclareAnnotation decaF = (DeclareAnnotation) iter2.next(); | |||
if (decaF.matches(itdIsActually,world)) { | |||
LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,fieldMunger); | |||
if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaF,reportedErrors)) continue; // skip this one... | |||
annotationHolder.addAnnotation(decaF.getAnnotationX()); | |||
//FIXME asc you need to add relationships for these things | |||
// AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]); | |||
isChanged = true; | |||
modificationOccured = true; | |||
forRemoval.add(decaF); | |||
} | |||
worthRetrying.removeAll(forRemoval); | |||
} | |||
} | |||
} | |||
return isChanged; | |||
} | |||
/** | |||
* Applies some set of declare @method/@ctor constructs (List<DeclareAnnotation>) to some bunch | |||
* of ITDmembers (List<BcelTypeMunger>. It will iterate over the fields repeatedly until | |||
* everything has been applied. | |||
*/ | |||
private boolean weaveAtMethodOnITDSRepeatedly(List decaMCs, List itdMethodsCtors,List reportedErrors) { | |||
boolean isChanged = false; | |||
for (Iterator iter = itdMethodsCtors.iterator(); iter.hasNext();) { | |||
BcelTypeMunger methodctorMunger = (BcelTypeMunger) iter.next(); | |||
ResolvedMember itdIsActually = methodctorMunger.getSignature(); | |||
List worthRetrying = new ArrayList(); | |||
boolean modificationOccured = false; | |||
for (Iterator iter2 = decaMCs.iterator(); iter2.hasNext();) { | |||
DeclareAnnotation decaMC = (DeclareAnnotation) iter2.next(); | |||
if (decaMC.matches(itdIsActually,world)) { | |||
LazyMethodGen annotationHolder = locateAnnotationHolderForMethodCtorMunger(clazz,methodctorMunger); | |||
if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaMC,reportedErrors)) continue; // skip this one... | |||
annotationHolder.addAnnotation(decaMC.getAnnotationX()); | |||
itdIsActually.addAnnotation(decaMC.getAnnotationX()); | |||
isChanged=true; | |||
//FIXME asc you need to add relationships for these things | |||
// AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]); | |||
isChanged = true; | |||
modificationOccured = true; | |||
} else { | |||
if (!decaMC.isStarredAnnotationPattern()) | |||
worthRetrying.add(decaMC); // an annotation is specified that might be put on by a subsequent decaf | |||
} | |||
} | |||
while (!worthRetrying.isEmpty() && modificationOccured) { | |||
modificationOccured = false; | |||
List forRemoval = new ArrayList(); | |||
for (Iterator iter2 = worthRetrying.iterator(); iter.hasNext();) { | |||
DeclareAnnotation decaF = (DeclareAnnotation) iter2.next(); | |||
if (decaF.matches(itdIsActually,world)) { | |||
LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,methodctorMunger); | |||
if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaF,reportedErrors)) continue; // skip this one... | |||
annotationHolder.addAnnotation(decaF.getAnnotationX()); | |||
//FIXME asc you need to add relationships for these things | |||
// AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]); | |||
isChanged = true; | |||
modificationOccured = true; | |||
forRemoval.add(decaF); | |||
} | |||
worthRetrying.removeAll(forRemoval); | |||
} | |||
} | |||
} | |||
return isChanged; | |||
} | |||
/** | |||
* Weave any declare @field statements into the fields of the supplied class | |||
* | |||
* Interesting case relating to public ITDd fields. The annotations are really stored against | |||
* the interfieldinit method in the aspect, but the public field is placed in the target | |||
* type and then is processed in the 2nd pass over fields that occurs. I think it would be | |||
* more expensive to avoid putting the annotation on that inserted public field than just to | |||
* have it put there as well as on the interfieldinit method. | |||
*/ | |||
private boolean weaveDeclareAtField(LazyClassGen clazz) { | |||
@@ -498,14 +685,26 @@ class BcelClassWeaver implements IClassWeaver { | |||
// 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()); | |||
List reportedProblems = new ArrayList(); | |||
List allDecafs = world.getDeclareAnnotationOnFields(); | |||
if (allDecafs.isEmpty()) return false; // nothing to do | |||
boolean isChanged = false; | |||
List itdFields = getITDSubset(clazz,ResolvedTypeMunger.Field); | |||
if (itdFields!=null) { | |||
isChanged = weaveAtFieldRepeatedly(allDecafs,itdFields,reportedProblems); | |||
} | |||
List decaFs = getMatchingSubset(allDecafs,clazz.getType()); | |||
if (decaFs.isEmpty()) return false; // nothing more to do | |||
Field[] fields = clazz.getFieldGens(); | |||
if (fields!=null && !decaFs.isEmpty()) { | |||
// go through all the fields | |||
if (fields!=null) { | |||
for (int fieldCounter = 0;fieldCounter<fields.length;fieldCounter++) { | |||
BcelField aBcelField = new BcelField(clazz.getBcelObjectType(),fields[fieldCounter]); | |||
if (!aBcelField.getName().startsWith(NameMangler.PREFIX)) { | |||
if (!aBcelField.getName().startsWith(NameMangler.PREFIX)) { | |||
// Single first pass | |||
List worthRetrying = new ArrayList(); | |||
boolean modificationOccured = false; | |||
@@ -513,7 +712,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
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... | |||
if (doesAlreadyHaveAnnotation(aBcelField,decaF,reportedProblems)) continue; // skip this one... | |||
aBcelField.addAnnotation(decaF.getAnnotationX()); | |||
AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]); | |||
isChanged = true; | |||
@@ -532,7 +731,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
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... | |||
if (doesAlreadyHaveAnnotation(aBcelField,decaF,reportedProblems)) continue; // skip this one... | |||
aBcelField.addAnnotation(decaF.getAnnotationX()); | |||
AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]); | |||
isChanged = true; | |||
@@ -552,18 +751,39 @@ 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,boolean reportProblems) { | |||
private boolean doesAlreadyHaveAnnotation(ResolvedMember rm,DeclareAnnotation deca,List reportedProblems) { | |||
if (rm.hasAnnotation(deca.getAnnotationTypeX())) { | |||
if (reportProblems) { | |||
world.getLint().elementAlreadyAnnotated.signal( | |||
new String[]{rm.toString(),deca.getAnnotationTypeX().toString()}, | |||
rm.getSourceLocation(),new ISourceLocation[]{deca.getSourceLocation()}); | |||
if (world.getLint().elementAlreadyAnnotated.isEnabled()) { | |||
Integer uniqueID = new Integer(rm.hashCode()*deca.hashCode()); | |||
if (!reportedProblems.contains(uniqueID)) { | |||
reportedProblems.add(uniqueID); | |||
world.getLint().elementAlreadyAnnotated.signal( | |||
new String[]{rm.toString(),deca.getAnnotationTypeX().toString()}, | |||
rm.getSourceLocation(),new ISourceLocation[]{deca.getSourceLocation()}); | |||
} | |||
} | |||
return true; | |||
return true; | |||
} | |||
return false; | |||
} | |||
private boolean doesAlreadyHaveAnnotation(LazyMethodGen rm,ResolvedMember itdfieldsig,DeclareAnnotation deca,List reportedProblems) { | |||
if (rm.hasAnnotation(deca.getAnnotationTypeX())) { | |||
if (world.getLint().elementAlreadyAnnotated.isEnabled()) { | |||
Integer uniqueID = new Integer(rm.hashCode()*deca.hashCode()); | |||
if (!reportedProblems.contains(uniqueID)) { | |||
reportedProblems.add(uniqueID); | |||
reportedProblems.add(new Integer(itdfieldsig.hashCode()*deca.hashCode())); | |||
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();) { | |||
@@ -982,12 +1202,16 @@ class BcelClassWeaver implements IClassWeaver { | |||
if (effective == null) { | |||
enclosingShadow = BcelShadow.makeMethodExecution(world, mg, !canMatchBodyShadows); | |||
} else if (effective.isWeaveBody()) { | |||
enclosingShadow = | |||
BcelShadow.makeShadowForMethod( | |||
world, | |||
mg, | |||
effective.getShadowKind(), | |||
effective.getEffectiveSignature()); | |||
ResolvedMember rm = effective.getEffectiveSignature(); | |||
// Annotations for things with effective signatures are never stored in the effective | |||
// signature itself - we have to hunt for them. Storing them in the effective signature | |||
// would mean keeping two sets up to date (no way!!) | |||
fixAnnotationsForResolvedMember(rm,mg.getMemberView()); | |||
enclosingShadow = | |||
BcelShadow.makeShadowForMethod(world,mg,effective.getShadowKind(),rm); | |||
} else { | |||
return false; | |||
} | |||
@@ -1000,7 +1224,8 @@ class BcelClassWeaver implements IClassWeaver { | |||
match(mg, h, enclosingShadow, shadowAccumulator); | |||
} | |||
} | |||
if (canMatch(enclosingShadow.getKind())) { | |||
// FIXME asc change from string match if we can, rather brittle. this check actually prevents field-exec jps | |||
if (canMatch(enclosingShadow.getKind()) && !mg.getName().startsWith("ajc$interFieldInit")) { | |||
if (match(enclosingShadow, shadowAccumulator)) { | |||
enclosingShadow.init(); | |||
} | |||
@@ -1259,6 +1484,56 @@ class BcelClassWeaver implements IClassWeaver { | |||
match(BcelShadow.makeFieldGet(world, mg, ih, enclosingShadow), shadowAccumulator); | |||
} | |||
} | |||
/** | |||
* For a given resolvedmember, this will discover the real annotations for it. | |||
* <b>Should only be used when the resolvedmember is the contents of an effective signature | |||
* attribute, as thats the only time when the annotations aren't stored directly in the | |||
* resolvedMember</b> | |||
* @param rm the sig we want it to pretend to be 'int A.m()' or somesuch ITD like thing | |||
* @param declaredSig the real sig 'blah.ajc$xxx' | |||
*/ | |||
private void fixAnnotationsForResolvedMember(ResolvedMember rm,ResolvedMember declaredSig) { | |||
try { | |||
TypeX memberHostType = declaredSig.getDeclaringType(); | |||
ResolvedTypeX[] annotations = (ResolvedTypeX[])mapToAnnotations.get(rm); | |||
String methodName = declaredSig.getName(); | |||
// FIXME asc shouldnt really rely on string names ! | |||
if (annotations == null) { | |||
if (rm.getKind()==Member.FIELD) { | |||
if (methodName.startsWith("ajc$inlineAccessField")) { | |||
ResolvedMember resolvedDooberry = world.resolve(rm); | |||
annotations = resolvedDooberry.getAnnotationTypes(); | |||
} else { | |||
ResolvedMember realthing = AjcMemberMaker.interFieldInitializer(rm,memberHostType); | |||
ResolvedMember resolvedDooberry = world.resolve(realthing); | |||
annotations = resolvedDooberry.getAnnotationTypes(); | |||
} | |||
} else if (rm.getKind()==Member.METHOD && !rm.isAbstract()) { | |||
if (methodName.startsWith("ajc$inlineAccessMethod")) { | |||
ResolvedMember resolvedDooberry = world.resolve(declaredSig); | |||
annotations = resolvedDooberry.getAnnotationTypes(); | |||
} else { | |||
ResolvedMember realthing = AjcMemberMaker.interMethodBody(rm,memberHostType); | |||
ResolvedMember resolvedDooberry = world.resolve(realthing); | |||
annotations = resolvedDooberry.getAnnotationTypes(); | |||
} | |||
} else if (rm.getKind()==Member.CONSTRUCTOR) { | |||
ResolvedMember realThing = AjcMemberMaker.postIntroducedConstructor(memberHostType.resolve(world),rm.getDeclaringType(),rm.getParameterTypes()); | |||
ResolvedMember resolvedDooberry = world.resolve(realThing); | |||
annotations = resolvedDooberry.getAnnotationTypes(); | |||
} | |||
if (annotations == null) | |||
annotations = new ResolvedTypeX[0]; | |||
mapToAnnotations.put(rm,annotations); | |||
} | |||
rm.setAnnotationTypes(annotations); | |||
} catch (Throwable t) { | |||
//FIXME asc remove this catch after more testing has confirmed the above stuff is OK | |||
throw new RuntimeException("Unexpectedly went bang when searching for annotations on "+rm,t); | |||
} | |||
} | |||
private void matchInvokeInstruction(LazyMethodGen mg, | |||
InstructionHandle ih, | |||
@@ -1292,10 +1567,15 @@ class BcelClassWeaver implements IClassWeaver { | |||
if (effectiveSig == null) return; | |||
//System.err.println("call to inter-type member: " + effectiveSig); | |||
if (effectiveSig.isWeaveBody()) return; | |||
if (canMatch(effectiveSig.getShadowKind())) | |||
ResolvedMember rm = effectiveSig.getEffectiveSignature(); | |||
fixAnnotationsForResolvedMember(rm,declaredSig); // abracadabra | |||
if (canMatch(effectiveSig.getShadowKind())) | |||
match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow, | |||
effectiveSig.getShadowKind(), effectiveSig.getEffectiveSignature()), | |||
shadowAccumulator); | |||
effectiveSig.getShadowKind(), rm), shadowAccumulator); | |||
} | |||
} else { | |||
if (canMatch(Shadow.MethodCall)) |
@@ -59,6 +59,9 @@ import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.IntMap; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.NameMangler; | |||
import org.aspectj.weaver.NewConstructorTypeMunger; | |||
import org.aspectj.weaver.NewFieldTypeMunger; | |||
import org.aspectj.weaver.NewMethodTypeMunger; | |||
import org.aspectj.weaver.ResolvedMember; | |||
import org.aspectj.weaver.ResolvedTypeX; | |||
import org.aspectj.weaver.Shadow; | |||
@@ -1283,6 +1286,7 @@ public class BcelShadow extends Shadow { | |||
thisAnnotationVars = new HashMap(); | |||
// populate.. | |||
} | |||
public void initializeTargetAnnotationVars() { | |||
if (targetAnnotationVars != null) return; | |||
if (getKind().isTargetSameAsThis()) { | |||
@@ -1308,6 +1312,7 @@ public class BcelShadow extends Shadow { | |||
// what the full set of annotations could be (due to static/dynamic type differences...) | |||
} | |||
} | |||
public void initializeKindedAnnotationVars() { | |||
if (kindedAnnotationVars != null) return; | |||
kindedAnnotationVars = new HashMap(); | |||
@@ -1316,100 +1321,156 @@ public class BcelShadow extends Shadow { | |||
// Then create one BcelVar entry in the map for each annotation, keyed by | |||
// annotation type (TypeX). | |||
// FIXME asc Refactor these once all shadow kinds added - there is lots of commonality | |||
// FIXME asc Refactor this code, there is duplication | |||
ResolvedTypeX[] annotations = null; | |||
TypeX relevantType = null; | |||
ResolvedMember itdMember =null; | |||
Member relevantMember = getSignature(); | |||
TypeX relevantType = null; | |||
TypeX aspect = null; | |||
if (getKind() == Shadow.StaticInitialization) { | |||
relevantType = getSignature().getDeclaringType(); | |||
annotations = relevantType.resolve(world).getAnnotationTypes(); | |||
} | |||
if (getKind() == Shadow.ExceptionHandler) { | |||
relevantType = getSignature().getParameterTypes()[0]; | |||
annotations = relevantType.resolve(world).getAnnotationTypes(); | |||
} | |||
if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) { | |||
} else if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) { | |||
relevantType = getSignature().getDeclaringType(); | |||
ResolvedMember rm[] = relevantType.getDeclaredMethods(world); | |||
ResolvedMember found = null; | |||
String searchString = getSignature().getName()+getSignature().getParameterSignature(); | |||
for (int i = 0; i < rm.length && found==null; i++) { | |||
ResolvedMember member = rm[i]; | |||
if ((member.getName()+member.getParameterSignature()).equals(searchString)) { | |||
found = member; | |||
relevantMember = findMethod2(relevantType.getDeclaredMethods(world),getSignature()); | |||
if (relevantMember == null) { | |||
// check the ITD'd dooberries | |||
List mungers = relevantType.resolve(world).getInterTypeMungers(); | |||
for (Iterator iter = mungers.iterator(); iter.hasNext();) { | |||
BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); | |||
if (typeMunger.getMunger() instanceof NewMethodTypeMunger || | |||
typeMunger.getMunger() instanceof NewConstructorTypeMunger) { | |||
ResolvedMember fakerm = typeMunger.getSignature(); | |||
//if (fakerm.hasAnnotations()) | |||
ResolvedMember ajcMethod = (getSignature().getKind()==ResolvedMember.CONSTRUCTOR? | |||
AjcMemberMaker.postIntroducedConstructor(typeMunger.getAspectType(),fakerm.getDeclaringType(),fakerm.getParameterTypes()): | |||
AjcMemberMaker.interMethodBody(fakerm,typeMunger.getAspectType())); | |||
ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod); | |||
if (fakerm.getName().equals(getSignature().getName()) && | |||
fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) { | |||
relevantType = typeMunger.getAspectType(); | |||
relevantMember = rmm; | |||
} | |||
} | |||
} | |||
} | |||
annotations = found.getAnnotationTypes(); | |||
} | |||
if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution || | |||
getKind() == Shadow.AdviceExecution) { | |||
annotations = relevantMember.getAnnotationTypes(); | |||
} else if (getKind() == Shadow.FieldSet || getKind() == Shadow.FieldGet) { | |||
relevantType = getSignature().getDeclaringType(); | |||
ResolvedMember rm[] = relevantType.getDeclaredMethods(world); | |||
ResolvedMember found = null; | |||
String searchString = getSignature().getName()+getSignature().getParameterSignature(); | |||
for (int i = 0; i < rm.length && found==null; i++) { | |||
ResolvedMember member = rm[i]; | |||
if ((member.getName()+member.getParameterSignature()).equals(searchString)) { | |||
found = member; | |||
} | |||
relevantMember = findField(relevantType.getDeclaredFields(world),getSignature()); | |||
if (relevantMember==null) { | |||
// check the ITD'd dooberries | |||
List mungers = relevantType.resolve(world).getInterTypeMungers(); | |||
for (Iterator iter = mungers.iterator(); iter.hasNext();) { | |||
BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); | |||
if (typeMunger.getMunger() instanceof NewFieldTypeMunger) { | |||
ResolvedMember fakerm = typeMunger.getSignature(); | |||
//if (fakerm.hasAnnotations()) | |||
ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm,typeMunger.getAspectType()); | |||
ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod); | |||
if (fakerm.equals(getSignature())) { | |||
relevantType = typeMunger.getAspectType(); | |||
relevantMember = rmm; | |||
} | |||
} | |||
} | |||
} | |||
annotations = found.getAnnotationTypes(); | |||
} | |||
if (getKind() == Shadow.PreInitialization || getKind() == Shadow.Initialization) { | |||
annotations = relevantMember.getAnnotationTypes(); | |||
} else if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution || | |||
getKind() == Shadow.AdviceExecution) { | |||
relevantType = getSignature().getDeclaringType(); | |||
ResolvedMember rm[] = relevantType.getDeclaredMethods(world); | |||
ResolvedMember found = null; | |||
String searchString = getSignature().getName()+getSignature().getParameterSignature(); | |||
for (int i = 0; i < rm.length && found==null; i++) { | |||
ResolvedMember member = rm[i]; | |||
if ((member.getName()+member.getParameterSignature()).equals(searchString)) { | |||
found = member; | |||
} | |||
} | |||
annotations = found.getAnnotationTypes(); | |||
} | |||
if (getKind() == Shadow.FieldSet) { | |||
relevantType = getSignature().getDeclaringType(); | |||
ResolvedMember rm[] = relevantType.getDeclaredFields(world); | |||
ResolvedMember found = null; | |||
for (int i = 0; i < rm.length && found==null; i++) { | |||
ResolvedMember member = rm[i]; | |||
if ( member.getName().equals(getSignature().getName()) && | |||
member.getType().equals(getSignature().getType())) { | |||
found = member; | |||
relevantMember = findMethod2(relevantType.getDeclaredMethods(world),getSignature()); | |||
if (relevantMember == null) { | |||
// check the ITD'd dooberries | |||
List mungers = relevantType.resolve(world).getInterTypeMungers(); | |||
for (Iterator iter = mungers.iterator(); iter.hasNext();) { | |||
BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); | |||
if (typeMunger.getMunger() instanceof NewMethodTypeMunger || | |||
typeMunger.getMunger() instanceof NewConstructorTypeMunger) { | |||
ResolvedMember fakerm = typeMunger.getSignature(); | |||
//if (fakerm.hasAnnotations()) | |||
ResolvedMember ajcMethod = (getSignature().getKind()==ResolvedMember.CONSTRUCTOR? | |||
AjcMemberMaker.postIntroducedConstructor(typeMunger.getAspectType(),fakerm.getDeclaringType(),fakerm.getParameterTypes()): | |||
AjcMemberMaker.interMethodBody(fakerm,typeMunger.getAspectType())); | |||
ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod); | |||
if (fakerm.getName().equals(getSignature().getName()) && | |||
fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) { | |||
relevantType = typeMunger.getAspectType(); | |||
relevantMember = rmm; | |||
} | |||
} | |||
} | |||
} | |||
annotations = found.getAnnotationTypes(); | |||
} | |||
if (getKind() == Shadow.FieldGet) { | |||
annotations = relevantMember.getAnnotationTypes(); | |||
} else if (getKind() == Shadow.ExceptionHandler) { | |||
relevantType = getSignature().getParameterTypes()[0]; | |||
annotations = relevantType.resolve(world).getAnnotationTypes(); | |||
} else if (getKind() == Shadow.PreInitialization || getKind() == Shadow.Initialization) { | |||
relevantType = getSignature().getDeclaringType(); | |||
ResolvedMember rm[] = relevantType.getDeclaredFields(world); | |||
ResolvedMember found = null; | |||
for (int i = 0; i < rm.length && found==null; i++) { | |||
ResolvedMember member = rm[i]; | |||
if ( member.getName().equals(getSignature().getName()) && | |||
member.getType().equals(getSignature().getType())) { | |||
found = member; | |||
} | |||
} | |||
ResolvedMember found = findMethod2(relevantType.getDeclaredMethods(world),getSignature()); | |||
annotations = found.getAnnotationTypes(); | |||
} | |||
if (annotations == null) { | |||
// We can't have recognized the shadow - should blow up now to be on the safe side | |||
throw new BCException("Didn't recognize shadow: "+getKind()); | |||
throw new BCException("Couldn't discover annotations for shadow: "+getKind()); | |||
} | |||
for (int i = 0; i < annotations.length; i++) { | |||
ResolvedTypeX aTX = annotations[i]; | |||
kindedAnnotationVars.put(aTX, | |||
new KindedAnnotationAccessVar(getKind(),aTX.resolve(world),relevantType,getSignature())); | |||
KindedAnnotationAccessVar kaav = new KindedAnnotationAccessVar(getKind(),aTX.resolve(world),relevantType,relevantMember); | |||
kindedAnnotationVars.put(aTX,kaav); | |||
} | |||
} | |||
public void initializeWithinAnnotationVars() { | |||
//FIXME asc whats the real diff between this one and the version in findMethod()? | |||
ResolvedMember findMethod2(ResolvedMember rm[], Member sig) { | |||
ResolvedMember found = null; | |||
// String searchString = getSignature().getName()+getSignature().getParameterSignature(); | |||
for (int i = 0; i < rm.length && found==null; i++) { | |||
ResolvedMember member = rm[i]; | |||
if (member.getName().equals(sig.getName()) && member.getParameterSignature().equals(sig.getParameterSignature())) | |||
found = member; | |||
} | |||
return found; | |||
} | |||
private ResolvedMember findMethod(ResolvedTypeX aspectType, ResolvedMember ajcMethod) { | |||
ResolvedMember decMethods[] = aspectType.getDeclaredMethods(); | |||
for (int i = 0; i < decMethods.length; i++) { | |||
ResolvedMember member = decMethods[i]; | |||
if (member.equals(ajcMethod)) return member; | |||
} | |||
return null; | |||
} | |||
private ResolvedMember findField(ResolvedMember[] members,Member lookingFor) { | |||
for (int i = 0; i < members.length; i++) { | |||
ResolvedMember member = members[i]; | |||
if ( member.getName().equals(getSignature().getName()) && | |||
member.getType().equals(getSignature().getType())) { | |||
return member; | |||
} | |||
} | |||
return null; | |||
} | |||
public void initializeWithinAnnotationVars() { | |||
if (withinAnnotationVars != null) return; | |||
withinAnnotationVars = new HashMap(); | |||
@@ -1134,7 +1134,7 @@ public class BcelWeaver implements IWeaver { | |||
boolean didSomething = false; | |||
if (decA.matches(onType)) { | |||
//FIXME asc CRITICAL this should be guarded by the 'already has annotation' check below but isn't since the compiler is producing classfiles with deca affected things in... | |||
//FIXME asc important this should be guarded by the 'already has annotation' check below but isn't since the compiler is producing classfiles with deca affected things in... | |||
AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decA.getSourceLocation(),onType.getSourceLocation()); | |||
if (onType.hasAnnotation(decA.getAnnotationX().getSignature())) { |
@@ -32,6 +32,7 @@ import org.aspectj.apache.bcel.classfile.Attribute; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.classfile.Method; | |||
import org.aspectj.apache.bcel.classfile.Synthetic; | |||
import org.aspectj.apache.bcel.classfile.annotation.Annotation; | |||
import org.aspectj.apache.bcel.generic.BranchHandle; | |||
import org.aspectj.apache.bcel.generic.BranchInstruction; | |||
import org.aspectj.apache.bcel.generic.CPInstruction; | |||
@@ -58,6 +59,7 @@ import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.ResolvedTypeX; | |||
import org.aspectj.weaver.TypeX; | |||
import org.aspectj.weaver.WeaverMessages; | |||
@@ -84,7 +86,7 @@ public final class LazyMethodGen { | |||
private String[] declaredExceptions; | |||
private InstructionList body; // leaving null for abstracts | |||
private Attribute[] attributes; | |||
private AnnotationGen[] annotations; | |||
// private AnnotationGen[] annotations; | |||
/* private */ final LazyClassGen enclosingClass; | |||
private final BcelMethod memberView; | |||
int highestLineNumber = 0; | |||
@@ -181,19 +183,25 @@ public final class LazyMethodGen { | |||
public void addAnnotation(AnnotationX ax) { | |||
initialize(); | |||
// if (!hasAnnotation(TypeX.forSignature(a.getTypeSignature()))) { | |||
AnnotationGen ag = new AnnotationGen(ax.getBcelAnnotation(),enclosingClass.getConstantPoolGen(),true); | |||
AnnotationGen[] newAnnotations = new AnnotationGen[annotations.length+1]; | |||
System.arraycopy(annotations,0,newAnnotations,0,annotations.length); | |||
newAnnotations[annotations.length]=ag; | |||
annotations = newAnnotations; | |||
// FIXME asc does this mean we are managing two levels of annotations again? | |||
// one here and one in the memberView??!? | |||
memberView.addAnnotation(ax); | |||
if (memberView==null) { | |||
System.err.println("REPORT THIS! 01: Lost annotation: "+ax+" cant be put onto "+this); | |||
return; | |||
} | |||
memberView.addAnnotation(ax); | |||
} | |||
public boolean hasAnnotation(TypeX annotationTypeX) { | |||
initialize(); | |||
if (memberView==null) { | |||
System.err.println("REPORT THIS! 02: Can't determine if "+this+" has annotation "+annotationTypeX); | |||
return false; | |||
} | |||
return memberView.hasAnnotation(annotationTypeX); | |||
} | |||
private void initialize() { | |||
if (returnType != null) return; | |||
if (returnType != null) return; | |||
//System.err.println("initializing: " + getName() + ", " + enclosingClass.getName() + ", " + returnType + ", " + savedMethod); | |||
@@ -204,7 +212,7 @@ public final class LazyMethodGen { | |||
this.declaredExceptions = gen.getExceptions(); | |||
this.attributes = gen.getAttributes(); | |||
this.annotations = gen.getAnnotations(); | |||
//this.annotations = gen.getAnnotations(); | |||
this.maxLocals = gen.getMaxLocals(); | |||
// this.returnType = BcelWorld.makeBcelType(memberView.getReturnType()); | |||
@@ -799,9 +807,21 @@ public final class LazyMethodGen { | |||
gen.addAttribute(attributes[i]); | |||
} | |||
if (annotations!=null) { | |||
for (int i = 0, len = annotations.length; i < len; i++) { | |||
gen.addAnnotation(annotations[i]); | |||
// We don't manage our own set of annotations... | |||
// if (annotations!=null) { | |||
// for (int i = 0, len = annotations.length; i < len; i++) { | |||
// gen.addAnnotation(annotations[i]); | |||
// } | |||
// } | |||
// work with the annotations from the memberView rather | |||
// than any set we know about. This assumes we only work with | |||
// annotations on LazyMethodGens that represent real members. | |||
if (memberView!=null && memberView.getAnnotations()!=null && memberView.getAnnotations().length!=0) { | |||
AnnotationX[] ans = memberView.getAnnotations(); | |||
for (int i = 0, len = ans.length; i < len; i++) { | |||
Annotation a= ans[i].getBcelAnnotation(); | |||
gen.addAnnotation(new AnnotationGen(a,gen.getConstantPool(),true)); | |||
} | |||
} | |||
@@ -14,18 +14,19 @@ import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Set; | |||
import org.aspectj.bridge.IMessage; | |||
import org.aspectj.bridge.MessageUtil; | |||
import org.aspectj.util.FuzzyBoolean; | |||
import org.aspectj.weaver.AjcMemberMaker; | |||
import org.aspectj.weaver.AnnotatedElement; | |||
import org.aspectj.weaver.BCException; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.IntMap; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.NameMangler; | |||
import org.aspectj.weaver.NewFieldTypeMunger; | |||
import org.aspectj.weaver.ResolvedMember; | |||
import org.aspectj.weaver.ResolvedTypeX; | |||
import org.aspectj.weaver.Shadow; | |||
@@ -35,6 +36,7 @@ import org.aspectj.weaver.VersionedDataInputStream; | |||
import org.aspectj.weaver.ast.Literal; | |||
import org.aspectj.weaver.ast.Test; | |||
import org.aspectj.weaver.ast.Var; | |||
import org.aspectj.weaver.bcel.BcelTypeMunger; | |||
/** | |||
* @annotation(@Foo) or @annotation(foo) | |||
@@ -110,12 +112,39 @@ public class AnnotationPointcut extends NameBindingPointcut { | |||
toMatchAgainst = rMember.getParameterTypes()[0].resolve(shadow.getIWorld()); | |||
} else { | |||
toMatchAgainst = rMember; | |||
// FIXME asc I'd like to get rid of this bit of logic altogether, shame ITD fields don't have an effective sig attribute | |||
// FIXME asc perf cache the result of discovering the member that contains the real annotations | |||
if (rMember.isAnnotatedElsewhere()) { | |||
if (kind==Shadow.FieldGet || kind==Shadow.FieldSet) { | |||
List mungers = rMember.getDeclaringType().resolve(shadow.getIWorld()).getInterTypeMungers(); // FIXME asc should include supers with getInterTypeMungersIncludingSupers? | |||
for (Iterator iter = mungers.iterator(); iter.hasNext();) { | |||
BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); | |||
if (typeMunger.getMunger() instanceof NewFieldTypeMunger) { | |||
ResolvedMember fakerm = typeMunger.getSignature(); | |||
if (fakerm.equals(member)) { | |||
ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm,typeMunger.getAspectType()); | |||
ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod); | |||
toMatchAgainst = rmm; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
annotationTypePattern.resolve(shadow.getIWorld()); | |||
return annotationTypePattern.matches(toMatchAgainst); | |||
} | |||
private ResolvedMember findMethod(ResolvedTypeX aspectType, ResolvedMember ajcMethod) { | |||
ResolvedMember decMethods[] = aspectType.getDeclaredMethods(); | |||
for (int i = 0; i < decMethods.length; i++) { | |||
ResolvedMember member = decMethods[i]; | |||
if (member.equals(ajcMethod)) return member; | |||
} | |||
return null; | |||
} | |||
/* (non-Javadoc) | |||
* @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(org.aspectj.weaver.patterns.IScope, org.aspectj.weaver.patterns.Bindings) | |||
@@ -148,24 +177,7 @@ public class AnnotationPointcut extends NameBindingPointcut { | |||
*/ | |||
protected Test findResidueInternal(Shadow shadow, ExposedState state) { | |||
if (shadow.getKind()!=Shadow.MethodCall && | |||
shadow.getKind()!=Shadow.ConstructorCall && | |||
shadow.getKind()!=Shadow.ConstructorExecution && | |||
shadow.getKind()!=Shadow.MethodExecution && | |||
shadow.getKind()!=Shadow.FieldSet && | |||
shadow.getKind()!=Shadow.FieldGet && | |||
shadow.getKind()!=Shadow.StaticInitialization && | |||
shadow.getKind()!=Shadow.PreInitialization && | |||
shadow.getKind()!=Shadow.AdviceExecution && | |||
shadow.getKind()!=Shadow.Initialization && | |||
shadow.getKind()!=Shadow.ExceptionHandler | |||
) { | |||
IMessage lim = MessageUtil.error("Binding not supported in @pcds (1.5.0 M2 limitation) for "+shadow.getKind()+" join points, see: " + | |||
getSourceLocation()); | |||
shadow.getIWorld().getMessageHandler().handleMessage(lim); | |||
throw new BCException("Binding not supported in @pcds (1.5.0 M2 limitation) for "+shadow.getKind()+" join points, see: " + | |||
getSourceLocation()); | |||
} | |||
if (annotationTypePattern instanceof BindingAnnotationTypePattern) { |
@@ -30,15 +30,18 @@ import org.aspectj.lang.reflect.ConstructorSignature; | |||
import org.aspectj.lang.reflect.FieldSignature; | |||
import org.aspectj.lang.reflect.MethodSignature; | |||
import org.aspectj.weaver.AjAttribute; | |||
import org.aspectj.weaver.AjcMemberMaker; | |||
import org.aspectj.weaver.Constants; | |||
import org.aspectj.weaver.ISourceContext; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.NameMangler; | |||
import org.aspectj.weaver.NewFieldTypeMunger; | |||
import org.aspectj.weaver.ResolvedMember; | |||
import org.aspectj.weaver.ResolvedTypeX; | |||
import org.aspectj.weaver.TypeX; | |||
import org.aspectj.weaver.VersionedDataInputStream; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.bcel.BcelTypeMunger; | |||
public class SignaturePattern extends PatternNode { | |||
@@ -132,9 +135,41 @@ public class SignaturePattern extends PatternNode { | |||
return false; | |||
} | |||
annotationPattern.resolve(world); | |||
// optimization before we go digging around for annotations on ITDs | |||
if (annotationPattern instanceof AnyAnnotationTypePattern) return true; | |||
// fake members represent ITD'd fields - for their annotations we should go and look up the | |||
// relevant member in the original aspect | |||
if (rMember.isAnnotatedElsewhere() && member.getKind()==Member.FIELD) { | |||
// FIXME asc duplicate of code in AnnotationPattern.matchInternal()? same fixmes apply here. | |||
ResolvedMember [] mems = rMember.getDeclaringType().resolve(world).getDeclaredFields(); // FIXME asc should include supers with getInterTypeMungersIncludingSupers? | |||
List mungers = rMember.getDeclaringType().resolve(world).getInterTypeMungers(); | |||
for (Iterator iter = mungers.iterator(); iter.hasNext();) { | |||
BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next(); | |||
if (typeMunger.getMunger() instanceof NewFieldTypeMunger) { | |||
ResolvedMember fakerm = typeMunger.getSignature(); | |||
ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm,typeMunger.getAspectType()); | |||
ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod); | |||
if (fakerm.equals(member)) { | |||
rMember = rmm; | |||
} | |||
} | |||
} | |||
} | |||
return annotationPattern.matches(rMember).alwaysTrue(); | |||
} | |||
private ResolvedMember findMethod(ResolvedTypeX aspectType, ResolvedMember ajcMethod) { | |||
ResolvedMember decMethods[] = aspectType.getDeclaredMethods(); | |||
for (int i = 0; i < decMethods.length; i++) { | |||
ResolvedMember member = decMethods[i]; | |||
if (member.equals(ajcMethod)) return member; | |||
} | |||
return null; | |||
} | |||
public boolean matchesIgnoringAnnotations(Member member, World world) { | |||
//XXX performance gains would come from matching on name before resolving | |||
// to fail fast. ASC 30th Nov 04 => Not necessarily, it didn't make it faster for me. | |||
@@ -143,7 +178,6 @@ public class SignaturePattern extends PatternNode { | |||
// String n2 = this.getName().maybeGetSimpleName(); | |||
// if (n2!=null && !n1.equals(n2)) return false; | |||
// FIXME ASC : | |||
if (member == null) return false; | |||
ResolvedMember sig = member.resolve(world); | |||