<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.<init>(java.lang.String, int)')"/>
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;
// 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) {
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)) {
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);
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
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;
} 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());
/**
* 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);