@@ -0,0 +1,27 @@ | |||
import java.lang.annotation.*; | |||
interface Behavior { | |||
String hello(); | |||
} | |||
aspect Trait { | |||
// public String Behavior.name; | |||
public String Behavior.hello() { | |||
return "hello"; | |||
} | |||
} | |||
public class Target implements Behavior { | |||
public static aspect A { | |||
// declare @field: * Target.name: @Tagged; // NO WORKY | |||
declare @method: * Target.hello(..): @Tagged; // NO WORKY | |||
} | |||
public static void main(String []argv) throws Exception { | |||
System.out.println(Target.class.getDeclaredMethod("hello").getDeclaredAnnotations()[0]); | |||
} | |||
} | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@interface Tagged {} |
@@ -0,0 +1,27 @@ | |||
import java.lang.annotation.*; | |||
interface Behavior { | |||
String hello(); | |||
} | |||
aspect Trait { | |||
// public String Behavior.name; | |||
public String Behavior.hello() throws java.io.IOException { | |||
return "hello"; | |||
} | |||
} | |||
public class Target2 implements Behavior { | |||
public static aspect A { | |||
// declare @field: * Target2.name: @Tagged; // NO WORKY | |||
declare @method: * Target2.hello(..): @Tagged; // NO WORKY | |||
} | |||
public static void main(String []argv) throws Exception { | |||
System.out.println(Target2.class.getDeclaredMethod("hello").getDeclaredAnnotations()[0]); | |||
} | |||
} | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@interface Tagged {} |
@@ -0,0 +1,27 @@ | |||
import java.lang.annotation.*; | |||
interface Behavior { | |||
String hello(); | |||
} | |||
aspect Trait { | |||
@Wibble | |||
public String Behavior.hello() throws java.io.IOException { | |||
return "hello"; | |||
} | |||
} | |||
public class Target3 implements Behavior { | |||
public static aspect A { | |||
declare @method: * Target3.hello(..): @Tagged; | |||
} | |||
public static void main(String []argv) throws Exception { | |||
System.out.println(Target3.class.getDeclaredMethod("hello").getDeclaredAnnotations().length); | |||
System.out.println(Target3.class.getDeclaredMethod("hello").getDeclaredAnnotations()[0]); | |||
System.out.println(Target3.class.getDeclaredMethod("hello").getDeclaredAnnotations()[1]); | |||
} | |||
} | |||
@Retention(RetentionPolicy.RUNTIME) @interface Tagged {} | |||
@Retention(RetentionPolicy.RUNTIME) @interface Wibble {} |
@@ -0,0 +1,25 @@ | |||
import java.lang.annotation.*; | |||
interface Behavior { | |||
String hello(); | |||
} | |||
aspect Trait { | |||
@Tagged(31) | |||
public String Behavior.hello() throws java.io.IOException { | |||
return "hello"; | |||
} | |||
} | |||
public class Target4 implements Behavior { | |||
public static aspect A { | |||
declare @method: * Target4.hello(..): @Tagged; | |||
} | |||
public static void main(String []argv) throws Exception { | |||
System.out.println(Target4.class.getDeclaredMethod("hello").getDeclaredAnnotations().length); | |||
System.out.println(Target4.class.getDeclaredMethod("hello").getDeclaredAnnotations()[0]); | |||
} | |||
} | |||
@Retention(RetentionPolicy.RUNTIME) @interface Tagged { int value() default 42;} |
@@ -21,6 +21,22 @@ import org.aspectj.testing.XMLBasedAjcTestCase; | |||
*/ | |||
public class Ajc174Tests extends org.aspectj.testing.XMLBasedAjcTestCase { | |||
public void testAnnotatedItd_418129() throws Exception { | |||
runTest("annotated itd"); | |||
} | |||
public void testAnnotatedItd_418129_2() throws Exception { | |||
runTest("annotated itd 2"); | |||
} | |||
public void testAnnotatedItd_418129_3() throws Exception { | |||
runTest("annotated itd 3"); | |||
} | |||
public void testAnnotatedItd_418129_4() throws Exception { | |||
runTest("annotated itd 4"); | |||
} | |||
public void testSuperItdCtor_413378() throws Exception { | |||
runTest("super itd ctor"); | |||
} |
@@ -2,6 +2,67 @@ | |||
<suite> | |||
<ajc-test dir="bugs174/pr418129" title="annotated itd"> | |||
<compile files="Target.java" options="-1.5 -showWeaveInfo"> | |||
<message kind="weave" text="Type 'Behavior' (Target.java) has intertyped method from 'Trait' (Target.java:'java.lang.String Behavior.hello()')"/> | |||
<message kind="weave" text="Type 'Target' (Target.java) has intertyped method from 'Trait' (Target.java:'java.lang.String Behavior.hello()')"/> | |||
<message kind="weave" text="'public java.lang.String Target.hello()' (Target.java) is annotated with @Tagged method annotation from 'Target$A' (Target.java:18)"/> | |||
</compile> | |||
<run class="Target"> | |||
<stdout> | |||
<line text="@Tagged()"/> | |||
</stdout> | |||
</run> | |||
</ajc-test> | |||
<!-- declared with throws exception --> | |||
<ajc-test dir="bugs174/pr418129" title="annotated itd 2"> | |||
<compile files="Target2.java" options="-1.5 -showWeaveInfo"> | |||
<message kind="weave" text="Type 'Behavior' (Target2.java) has intertyped method from 'Trait' (Target2.java:'java.lang.String Behavior.hello()')"/> | |||
<message kind="weave" text="Type 'Target2' (Target2.java) has intertyped method from 'Trait' (Target2.java:'java.lang.String Behavior.hello()')"/> | |||
<message kind="weave" text="'public java.lang.String Target2.hello()' (Target2.java) is annotated with @Tagged method annotation from 'Target2$A' (Target2.java:18)"/> | |||
</compile> | |||
<run class="Target2"> | |||
<stdout> | |||
<line text="@Tagged()"/> | |||
</stdout> | |||
</run> | |||
</ajc-test> | |||
<!-- already annotated with another annotation --> | |||
<ajc-test dir="bugs174/pr418129" title="annotated itd 3"> | |||
<compile files="Target3.java" options="-1.5 -showWeaveInfo"> | |||
<message kind="weave" text="Type 'Behavior' (Target3.java) has intertyped method from 'Trait' (Target3.java:'java.lang.String Behavior.hello()')"/> | |||
<message kind="weave" text="Type 'Target3' (Target3.java) has intertyped method from 'Trait' (Target3.java:'java.lang.String Behavior.hello()')"/> | |||
<message kind="weave" text="'public java.lang.String Target3.hello()' (Target3.java) is annotated with @Tagged method annotation from 'Target3$A' (Target3.java:16)"/> | |||
</compile> | |||
<run class="Target3"> | |||
<stdout> | |||
<line text="2"/> | |||
<line text="@Wibble()"/> | |||
<line text="@Tagged()"/> | |||
</stdout> | |||
</run> | |||
</ajc-test> | |||
<!-- already annotated with the same annotation --> | |||
<ajc-test dir="bugs174/pr418129" title="annotated itd 4"> | |||
<compile files="Target4.java" options="-1.5 -showWeaveInfo"> | |||
<message kind="weave" text="Type 'Behavior' (Target4.java) has intertyped method from 'Trait' (Target4.java:'java.lang.String Behavior.hello()')"/> | |||
<message kind="weave" text="Type 'Target4' (Target4.java) has intertyped method from 'Trait' (Target4.java:'java.lang.String Behavior.hello()')"/> | |||
<!-- warning turned off as it gets confusing - when the itd on the interface is hit by a deca --> | |||
<!-- | |||
<message kind="warning" text="java.lang.String Target4.hello() - already has an annotation of type Tagged, cannot add a second instance [Xlint:elementAlreadyAnnotated]"/> | |||
--> | |||
</compile> | |||
<run class="Target4"> | |||
<stdout> | |||
<line text="1"/> | |||
<line text="@Tagged(value=31)"/> | |||
</stdout> | |||
</run> | |||
</ajc-test> | |||
<ajc-test dir="bugs174/pr413378" title="super itd ctor"> | |||
<compile files="Code.java" options="-1.5 -showWeaveInfo"> | |||
<message kind="weave" text="Type 'Child' (Code.java) has intertyped constructor from 'MyTest' (Code.java:'void Child.<init>(java.lang.String, int)')"/> |
@@ -68,6 +68,7 @@ import org.aspectj.weaver.ConcreteTypeMunger; | |||
import org.aspectj.weaver.IClassWeaver; | |||
import org.aspectj.weaver.IntMap; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.MemberKind; | |||
import org.aspectj.weaver.MissingResolvedTypeWithKnownSignature; | |||
import org.aspectj.weaver.NameMangler; | |||
import org.aspectj.weaver.NewConstructorTypeMunger; | |||
@@ -532,8 +533,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
// finally, if we changed, we add in the introduced methods. | |||
if (isChanged) { | |||
clazz.getOrCreateWeaverStateInfo(inReweavableMode); | |||
weaveInAddedMethods(); // FIXME asc are these potentially affected | |||
// by declare annotation? | |||
weaveInAddedMethods(); | |||
} | |||
if (inReweavableMode) { | |||
@@ -893,15 +893,91 @@ class BcelClassWeaver implements IClassWeaver { | |||
isChanged = weaveAtMethodOnITDSRepeatedly(allDecams, itdMethodsCtors, reportedProblems); | |||
} | |||
// deal with all the other methods... | |||
List<LazyMethodGen> members = clazz.getMethodGens(); | |||
List<DeclareAnnotation> decaMs = getMatchingSubset(allDecams, clazz.getType()); | |||
if (decaMs.isEmpty()) { | |||
return false; // nothing to do | |||
} | |||
Set<DeclareAnnotation> unusedDecams = new HashSet<DeclareAnnotation>(); | |||
unusedDecams.addAll(decaMs); | |||
// These methods may have been targeted with declare annotation. Example: ITD on an interface | |||
// where the top most implementor gets a real method. The top most implementor method | |||
// is an 'addedLazyMethodGen' | |||
if (addedLazyMethodGens!=null) { | |||
for (LazyMethodGen method: addedLazyMethodGens) { | |||
// They have no resolvedmember of their own, conjure one up for matching purposes | |||
ResolvedMember resolvedmember = | |||
new ResolvedMemberImpl(ResolvedMember.METHOD,method.getEnclosingClass().getType(),method.getAccessFlags(), | |||
BcelWorld.fromBcel(method.getReturnType()),method.getName(), | |||
BcelWorld.fromBcel(method.getArgumentTypes()),UnresolvedType.forNames(method.getDeclaredExceptions())); | |||
resolvedmember.setAnnotationTypes(method.getAnnotationTypes()); | |||
resolvedmember.setAnnotations(method.getAnnotations()); | |||
List<DeclareAnnotation> worthRetrying = new ArrayList<DeclareAnnotation>(); | |||
boolean modificationOccured = false; | |||
for (DeclareAnnotation decam: decaMs) { | |||
if (decam.matches(resolvedmember, world)) { | |||
if (doesAlreadyHaveAnnotation(resolvedmember, decam, reportedProblems,false)) { | |||
// remove the declare @method since don't want an error when the annotation is already there | |||
unusedDecams.remove(decam); | |||
continue; | |||
} | |||
AnnotationGen a = ((BcelAnnotation) decam.getAnnotation()).getBcelAnnotation(); | |||
// create copy to get the annotation type into the right constant pool | |||
AnnotationAJ aj = new BcelAnnotation(new AnnotationGen(a, clazz.getConstantPool(), true),world); | |||
method.addAnnotation(aj); | |||
resolvedmember.addAnnotation(decam.getAnnotation()); | |||
AsmRelationshipProvider.addDeclareAnnotationMethodRelationship(decam.getSourceLocation(), | |||
clazz.getName(), resolvedmember, world.getModelAsAsmManager()); | |||
reportMethodCtorWeavingMessage(clazz, resolvedmember, decam, method.getDeclarationLineNumber()); | |||
isChanged = true; | |||
modificationOccured = true; | |||
unusedDecams.remove(decam); | |||
} else if (!decam.isStarredAnnotationPattern()) { | |||
// an annotation is specified that might be put on by a subsequent decaf | |||
worthRetrying.add(decam); | |||
} | |||
} | |||
// Multiple secondary passes | |||
while (!worthRetrying.isEmpty() && modificationOccured) { | |||
modificationOccured = false; | |||
// lets have another go | |||
List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>(); | |||
for (DeclareAnnotation decam : worthRetrying) { | |||
if (decam.matches(resolvedmember, world)) { | |||
if (doesAlreadyHaveAnnotation(resolvedmember, decam, reportedProblems,false)) { | |||
// remove the declare @method since don't | |||
// want an error when | |||
// the annotation is already there | |||
unusedDecams.remove(decam); | |||
continue; // skip this one... | |||
} | |||
AnnotationGen a = ((BcelAnnotation) decam.getAnnotation()).getBcelAnnotation(); | |||
// create copy to get the annotation type into the right constant pool | |||
AnnotationAJ aj = new BcelAnnotation(new AnnotationGen(a, clazz.getConstantPool(), true),world); | |||
method.addAnnotation(aj); | |||
resolvedmember.addAnnotation(decam.getAnnotation()); | |||
AsmRelationshipProvider.addDeclareAnnotationMethodRelationship(decam.getSourceLocation(), | |||
clazz.getName(), resolvedmember, world.getModelAsAsmManager());// getMethod()); | |||
isChanged = true; | |||
modificationOccured = true; | |||
forRemoval.add(decam); | |||
unusedDecams.remove(decam); | |||
} | |||
} | |||
worthRetrying.removeAll(forRemoval); | |||
} | |||
} | |||
} | |||
// deal with all the other methods... | |||
List<LazyMethodGen> members = clazz.getMethodGens(); | |||
if (!members.isEmpty()) { | |||
Set<DeclareAnnotation> unusedDecams = new HashSet<DeclareAnnotation>(); | |||
unusedDecams.addAll(decaMs); | |||
for (int memberCounter = 0; memberCounter < members.size(); memberCounter++) { | |||
LazyMethodGen mg = members.get(memberCounter); | |||
if (!mg.getName().startsWith(NameMangler.PREFIX)) { | |||
@@ -913,7 +989,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
for (DeclareAnnotation decaM : decaMs) { | |||
if (decaM.matches(mg.getMemberView(), world)) { | |||
if (doesAlreadyHaveAnnotation(mg.getMemberView(), decaM, reportedProblems)) { | |||
if (doesAlreadyHaveAnnotation(mg.getMemberView(), decaM, reportedProblems,true)) { | |||
// remove the declare @method since don't want | |||
// an error when the annotation is already there | |||
unusedDecams.remove(decaM); | |||
@@ -954,7 +1030,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>(); | |||
for (DeclareAnnotation decaM : worthRetrying) { | |||
if (decaM.matches(mg.getMemberView(), world)) { | |||
if (doesAlreadyHaveAnnotation(mg.getMemberView(), decaM, reportedProblems)) { | |||
if (doesAlreadyHaveAnnotation(mg.getMemberView(), decaM, reportedProblems,true)) { | |||
// remove the declare @method since don't | |||
// want an error when | |||
// the annotation is already there | |||
@@ -1347,7 +1423,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
unusedDecafs.remove(decaf); | |||
} else { | |||
if (!dontAddTwice(decaf, dontAddMeTwice)) { | |||
if (doesAlreadyHaveAnnotation(field, decaf, reportedProblems)) { | |||
if (doesAlreadyHaveAnnotation(field, decaf, reportedProblems,true )) { | |||
// remove the declare @field since don't want an error when the annotation is already there | |||
unusedDecafs.remove(decaf); | |||
continue; | |||
@@ -1389,7 +1465,7 @@ class BcelClassWeaver implements IClassWeaver { | |||
} else { | |||
// below code is for recursive things | |||
unusedDecafs.remove(decaF); | |||
if (doesAlreadyHaveAnnotation(field, decaF, reportedProblems)) { | |||
if (doesAlreadyHaveAnnotation(field, decaF, reportedProblems,true)) { | |||
continue; | |||
} | |||
field.addAnnotation(decaF.getAnnotation()); | |||
@@ -1486,9 +1562,9 @@ class BcelClassWeaver implements IClassWeaver { | |||
/** | |||
* Check if a resolved member (field/method/ctor) already has an annotation, if it does then put out a warning and return true | |||
*/ | |||
private boolean doesAlreadyHaveAnnotation(ResolvedMember rm, DeclareAnnotation deca, List<Integer> reportedProblems) { | |||
private boolean doesAlreadyHaveAnnotation(ResolvedMember rm, DeclareAnnotation deca, List<Integer> reportedProblems, boolean reportError) { | |||
if (rm.hasAnnotation(deca.getAnnotationType())) { | |||
if (world.getLint().elementAlreadyAnnotated.isEnabled()) { | |||
if (reportError && world.getLint().elementAlreadyAnnotated.isEnabled()) { | |||
Integer uniqueID = new Integer(rm.hashCode() * deca.hashCode()); | |||
if (!reportedProblems.contains(uniqueID)) { | |||
reportedProblems.add(uniqueID); |
@@ -345,6 +345,22 @@ public class BcelWorld extends World implements Repository { | |||
return ret; | |||
} | |||
public static Type[] makeBcelTypes(String[] types) { | |||
if (types == null || types.length==0 ) { | |||
return null; | |||
} | |||
Type[] ret = new Type[types.length]; | |||
for (int i=0, len=types.length; i<len; i++) { | |||
ret[i] = makeBcelType(types[i]); | |||
} | |||
return ret; | |||
} | |||
public static Type makeBcelType(String type) { | |||
return Type.getType(type); | |||
} | |||
static String[] makeBcelTypesAsClassNames(UnresolvedType[] types) { | |||
String[] ret = new String[types.length]; | |||
for (int i = 0, len = types.length; i < len; i++) { | |||
@@ -1239,4 +1255,5 @@ public class BcelWorld extends World implements Repository { | |||
public void demote(ResolvedType type) { | |||
typeMap.demote(type); | |||
} | |||
} |
@@ -124,6 +124,15 @@ public final class LazyMethodGen implements Traceable { | |||
List<BcelShadow> matchedShadows; | |||
// Used for interface introduction - this is the type of the interface the method is technically on | |||
public ResolvedType definingType = null; | |||
static class LightweightBcelMethod extends BcelMethod { | |||
LightweightBcelMethod(BcelObjectType declaringType, Method method) { | |||
super(declaringType, method); | |||
// TODO Auto-generated constructor stub | |||
} | |||
} | |||
public LazyMethodGen(int modifiers, Type returnType, String name, Type[] paramTypes, String[] declaredExceptions, | |||
LazyClassGen enclosingClass) { | |||
@@ -304,6 +313,27 @@ public final class LazyMethodGen implements Traceable { | |||
memberView.addParameterAnnotation(parameterNumber, anno); | |||
} | |||
} | |||
public ResolvedType[] getAnnotationTypes() { | |||
initialize(); | |||
if (memberView == null && newAnnotations!=null && newAnnotations.size()!=0) { | |||
// TODO Ignoring removed annotations for now | |||
ResolvedType[] annotationTypes = new ResolvedType[newAnnotations.size()]; | |||
for (int a=0,len=newAnnotations.size();a<len;a++) { | |||
annotationTypes[a] = newAnnotations.get(a).getType(); | |||
} | |||
return annotationTypes; | |||
} | |||
return null; | |||
} | |||
public AnnotationAJ[] getAnnotations() { | |||
initialize(); | |||
if (memberView == null && newAnnotations!=null && newAnnotations.size()!=0) { | |||
return newAnnotations.toArray(new AnnotationAJ[newAnnotations.size()]); | |||
} | |||
return null; | |||
} | |||
public boolean hasAnnotation(UnresolvedType annotationType) { | |||
initialize(); |