@@ -0,0 +1,106 @@ | |||
public aspect CallOverriding { | |||
void foo() { | |||
// make some calls! | |||
Generic<Number> gn = new Generic<Number>(); | |||
SubGeneric<Double> sgd = new SubGeneric<Double>(); | |||
SubParameterized sp = new SubParameterized(); | |||
gn.foo(new Integer(5)); | |||
sgd.foo(new Double(5)); | |||
sp.foo("hi"); | |||
} | |||
// if a type overrides a generic method from a supertype, changing the | |||
// signature in the process (for example, is a generic subtype with a | |||
// narrowed type variable, or extends a parameterized super class, or | |||
// implements a parameterized interface), then a type pattern of | |||
// OriginalDeclaringType.erasureOfOriginalSignature matches, and a | |||
// type pattern of *.erasureOfOriginalSignature matches, but | |||
// a type pattern OverridingType.erasureOfOriginalSignature DOES NOT | |||
// MATCH. | |||
declare warning : call(void *.foo(Object)) | |||
: "wildcard declaring type match on erasure"; | |||
declare warning : call(void Generic.foo(Object)) | |||
: "base declaring type match on erasure"; | |||
declare warning : call(void SubGeneric.foo(Object)) | |||
: "not expecting any matches"; | |||
declare warning : call(void SubGeneric.foo(Number)) | |||
: "sub type match on erasure"; | |||
declare warning : call(void SubParameterized.foo(Object)) | |||
: "not expecting any matches"; | |||
declare warning : call(void SubParameterized.foo(String)) | |||
: "parameterized match on erasure"; | |||
} | |||
class Generic<T> { | |||
int x = 0; | |||
// call (void Generic.foo(Object)) | |||
// call (void *.foo(Object)) | |||
public void foo(T someObject) { | |||
x = 1; | |||
} | |||
} | |||
class SubGeneric<N extends Number> extends Generic<N> { | |||
int y = 0; | |||
// call(void Generic.foo(Object)) | |||
// call( void *.foo(Object)) | |||
// call(void SubGeneric.foo(Number)) | |||
// !call(void SubGeneric.foo(Object)) | |||
public void foo(N someObject) { | |||
y = 1; | |||
} | |||
} | |||
class SubParameterized extends Generic<String> { | |||
int y = 0; | |||
// call(void Generic.foo(Object)) | |||
// call( void *.foo(Object)) | |||
// call(void SubParameterized.foo(String)) | |||
// !call(void SubGeneric.foo(Object)) | |||
public void foo(String someObject) { | |||
y = 1; | |||
} | |||
} | |||
interface I<E> { | |||
void bar(E anElement); | |||
} | |||
class ParameterizedI implements I<Double> { | |||
int x; | |||
void foo() { | |||
ParameterizedI pi = new ParameterizedI(); | |||
pi.bar(5.0d); | |||
} | |||
// call(void I.bar(Object)) | |||
// call(void *.bar(Object)) | |||
// call(void ParameterizedI.bar(Double)) | |||
// !call(void ParameterizedI.bar(Object)) | |||
public void bar(Double d) { | |||
x = 1; | |||
} | |||
static aspect ParameterizedChecker { | |||
declare warning : call(void I.bar(Object)) : "erasure match on base interface"; | |||
declare warning : call(void *.bar(Object)) : "wildcard match on erasure"; | |||
declare warning : call(void ParameterizedI.bar(Double)) : "parameterized match"; | |||
declare warning : call(void ParameterizedI.bar(Object)) : "no match expected"; | |||
} | |||
} | |||
@@ -0,0 +1,18 @@ | |||
public aspect CallPointcutMatchingErrorCases { | |||
// rule 1) you can't use generic or parameterized type patterns in the declaring type position | |||
pointcut tryExecutionGeneric() : call(* Generic<T>.*(..)); // CE L 4 | |||
pointcut tryExecutionParameterized() : call(* Generic<String>.*(..)); // CE L5 | |||
pointcut badThrows() : call(* Generic.*(..) throws Ex*<String>); // CE L6 | |||
} | |||
class Generic<T> { | |||
T foo = null; | |||
T getFoo() { | |||
return foo; | |||
} | |||
} |
@@ -0,0 +1,80 @@ | |||
import java.util.*; | |||
public aspect CallPointcutMatchingParamAndReturnTypes { | |||
void foo() { | |||
// make some calls! | |||
Generic<Number> gn = new Generic(new ArrayList<String>()); | |||
new UglyBuilding().foo(); | |||
gn = new Generic<Number>(5.0d); | |||
gn.foo(); | |||
new UglyBuilding().iSee("you"); | |||
new UglyBuilding().ic2it(); | |||
// new UglyBuilding().iSee(new Object()); | |||
} | |||
// rule 3) a raw parameter pattern matches any parameterized type | |||
declare warning : call(Generic.new(List)) | |||
: "raw param type matching in call ok"; | |||
declare warning : call(List UglyBuilding.foo()) | |||
: "raw return type matching in call ok"; | |||
// rule 4) A param type declared using a type variable is matched by its erasure | |||
declare warning : call(Generic.new(Object)) | |||
: "erasure type matching in call ok"; | |||
declare warning : call(Object Generic.foo()) | |||
: "erasure type matching in call ok"; | |||
// rule 5) no join points in bridge methods - test this separately for call... | |||
declare warning : call(void UglyBuilding.iSee(String)) | |||
: "call and parameterized method ok"; | |||
declare warning : call(* ISore.*(..)) | |||
: "call and generic interface ok"; | |||
declare warning : call(* I2.*(..)) | |||
: "call and interface control test"; | |||
// declare warning : call(void UglyBuilding.iSee(Object)) | |||
// : "should be no join points for bridge methods"; | |||
// rule 6) parameterized types in return and args can be matched exactly | |||
declare warning : call(Generic.new(List<String>)) : "match on parameterized args"; | |||
declare warning : call(List<Number> *(..)) : "match on parameterized return type"; | |||
} | |||
class Generic<T> { | |||
int x; | |||
public Generic(List<String> ls) { | |||
x = 5; | |||
} | |||
public Generic(T t) { | |||
x = 6; | |||
} | |||
T foo() { x = 7; return null; } | |||
} | |||
interface ISore<E> { | |||
void iSee(E anE); | |||
} | |||
interface I2 { | |||
void ic2it(); | |||
} | |||
class UglyBuilding implements ISore<String>, I2 { | |||
int y; | |||
// this class will have a bridge method with signature void iSee(Object), with a cast and call | |||
// to the method below | |||
public void iSee(String s) { | |||
y = 2; | |||
} | |||
public void ic2it() { y = 4; } | |||
List<Number> foo() { y = 1; return null; } | |||
} |
@@ -31,8 +31,8 @@ public aspect ExecutionOverriding { | |||
class Generic<T> { | |||
int x = 0; | |||
// withincode (void Generic.foo(Object)) | |||
// withincode (void *.foo(Object)) | |||
// execution (void Generic.foo(Object)) | |||
// execution (void *.foo(Object)) | |||
public void foo(T someObject) { | |||
x = 1; | |||
} | |||
@@ -42,10 +42,10 @@ class Generic<T> { | |||
class SubGeneric<N extends Number> extends Generic<N> { | |||
int y = 0; | |||
// withincode(void Generic.foo(Object)) | |||
// withincode( void *.foo(Object)) | |||
// withincode(void SubGeneric.foo(Number)) | |||
// !withincode(void SubGeneric.foo(Object)) | |||
// execution(void Generic.foo(Object)) | |||
// execution( void *.foo(Object)) | |||
// execution(void SubGeneric.foo(Number)) | |||
// !execution(void SubGeneric.foo(Object)) | |||
public void foo(N someObject) { | |||
y = 1; | |||
} | |||
@@ -55,10 +55,10 @@ class SubGeneric<N extends Number> extends Generic<N> { | |||
class SubParameterized extends Generic<String> { | |||
int y = 0; | |||
// withincode(void Generic.foo(Object)) | |||
// withincode( void *.foo(Object)) | |||
// withincode(void SubParameterized.foo(String)) | |||
// !withincode(void SubGeneric.foo(Object)) | |||
// execution(void Generic.foo(Object)) | |||
// execution( void *.foo(Object)) | |||
// execution(void SubParameterized.foo(String)) | |||
// !execution(void SubGeneric.foo(Object)) | |||
public void foo(String someObject) { | |||
y = 1; | |||
} | |||
@@ -72,10 +72,10 @@ interface I<E> { | |||
class ParameterizedI implements I<Double> { | |||
int x; | |||
// withincode(void I.bar(Object)) | |||
// withincode(void *.bar(Object)) | |||
// withincode(void ParameterizedI.bar(Double)) | |||
// !withincode(void ParameterizedI.bar(Object)) | |||
// execution(void I.bar(Object)) | |||
// execution(void *.bar(Object)) | |||
// execution(void ParameterizedI.bar(Double)) | |||
// !execution(void ParameterizedI.bar(Object)) | |||
public void bar(Double d) { | |||
x = 1; | |||
} |
@@ -96,7 +96,13 @@ public class GenericsTests extends XMLBasedAjcTestCase { | |||
* - parameter as parameterized type PASS | |||
* - no join points for bridge methods PASS | |||
* call | |||
* - wait till we get there! | |||
* - no generic or parameterized declaring type patterns | |||
* - no parameterized throws patterns | |||
* - return type as type variable | |||
* - return type as parameterized type | |||
* - parameter as type variable | |||
* - parameter as parameterized type | |||
* - a call to a bridge method is really a call to the method being bridged... (1.4/1.5 differences here?) | |||
*/ | |||
/* ========================================== | |||
@@ -205,12 +211,12 @@ public class GenericsTests extends XMLBasedAjcTestCase { | |||
// non static | |||
public void testGenericMethodITD1() {runTest("generic method itd - 1"); } // <E> ... (List<? extends E>) | |||
public void testGenericMethodITD2() {runTest("generic method itd - 2"); } // <E extends Number> ... (List<? extends E>) called incorrectly | |||
public void testGenericMethodITD3() {runTest("generic method itd - 3"); } // <E> ... (List<E>,List<E>) | |||
public void testGenericMethodITD4() {runTest("generic method itd - 4"); } // <A,B> ... (List<A>,List<B>) | |||
public void testGenericMethodITD5() {runTest("generic method itd - 5"); } // <E> ... (List<E>,List<E>) called incorrectly | |||
public void testGenericMethodITD6() {runTest("generic method itd - 6"); } // <E extends Number> ... (List<? extends E>) | |||
public void testGenericMethodITD1() {runTest("generic method itd - 1");} // <E> ... (List<? extends E>) | |||
public void testGenericMethodITD2() {runTest("generic method itd - 2");} // <E extends Number> ... (List<? extends E>) called incorrectly | |||
public void testGenericMethodITD3() {runTest("generic method itd - 3");} // <E> ... (List<E>,List<E>) | |||
public void testGenericMethodITD4() {runTest("generic method itd - 4");} // <A,B> ... (List<A>,List<B>) | |||
public void testGenericMethodITD5() {runTest("generic method itd - 5");} // <E> ... (List<E>,List<E>) called incorrectly | |||
public void testGenericMethodITD6() {runTest("generic method itd - 6");} // <E extends Number> ... (List<? extends E>) | |||
public void testGenericMethodITD7() {runTest("generic method itd - 7"); } // <E> ... (List<E>,List<? extends E>) | |||
public void testGenericMethodITD8() {runTest("generic method itd - 8"); } // <E> ... (List<E>,List<? extends E>) called incorrectly | |||
public void testGenericMethodITD9() {runTest("generic method itd - 9"); } // <R extends Comparable<? super R>> ... (List<R>) | |||
@@ -232,7 +238,7 @@ public class GenericsTests extends XMLBasedAjcTestCase { | |||
public void testGenericCtorITD2() {runTest("generic ctor itd - 2");} // <T> new(List<T>,List<? extends T>) | |||
public void testGenericCtorITD3() {runTest("generic ctor itd - 3");} // <T> new(List<T>,Comparator<? super T>) | |||
// public void testGenericITFSharingTypeVariable() { | |||
// public void testGenericITFSharingTypeVariable() { | |||
// runTest("generic intertype field declaration, sharing type variable"); | |||
// } | |||
@@ -424,6 +430,19 @@ public class GenericsTests extends XMLBasedAjcTestCase { | |||
public void testExecutionOverrideMatchingWithGenericMembers() { | |||
runTest("execution with overriding of inherited generic members"); | |||
} | |||
public void testCallPointcutErrors() { | |||
runTest("call with various parameterizations and generic types - errors"); | |||
} | |||
public void testCallMatching() { | |||
runTest("call with various parameterizations and generic types - matching"); | |||
} | |||
public void testCallOverrideMatchingWithGenericMembers() { | |||
runTest("call with overriding of inherited generic members"); | |||
} | |||
public void testGetAndSetPointcutErrors() { | |||
runTest("get and set with various parameterizations and generic types - errors"); | |||
} |
@@ -2390,7 +2390,7 @@ | |||
<compile files="GenericCtorITD1.aj" options="-1.5"/> | |||
<run class="GenericCtorITD1"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="generic ctor itd - 2"> | |||
<compile files="GenericCtorITD2.aj" options="-1.5"/> | |||
<run class="GenericCtorITD2"/> | |||
@@ -2905,7 +2905,7 @@ | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/pointcuts" title="execution with various parameterizations and generic types - errors"> | |||
<ajc-test dir="java5/generics/pointcuts" title="execution with various parameterizations and generic types - errors"> | |||
<compile files="ExecutionPointcutMatchingErrorCases.aj" options="-1.5"> | |||
<message kind="warning" line="4" text="no match for this type name: T"/> | |||
<message kind="error" line="4" text="can't use parameterized type patterns for the declaring type of an execution pointcut expression (use the raw type instead)"/> | |||
@@ -2955,6 +2955,46 @@ | |||
<message kind="warning" line="5" text="execution<T>(* GenericInterface<T extends Number>.asInt(T))"/> | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/pointcuts" title="call with various parameterizations and generic types - errors"> | |||
<compile files="CallPointcutMatchingErrorCases.aj" options="-1.5"> | |||
<message kind="warning" line="4" text="no match for this type name: T"/> | |||
<message kind="error" line="4" text="can't use parameterized type patterns for the declaring type of a call pointcut expression (use the raw type instead)"/> | |||
<message kind="error" line="5" text="can't use parameterized type patterns for the declaring type of a call pointcut expression (use the raw type instead)"/> | |||
<message kind="error" line="6" text="invalid throws pattern: a generic class may not be a direct or indirect subclass of Throwable"/> | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/pointcuts" title="call with various parameterizations and generic types - matching"> | |||
<compile files="CallPointcutMatchingParamAndReturnTypes.aj" options="-1.5"> | |||
<message kind="warning" line="7" text="raw param type matching in call ok"/> | |||
<message kind="warning" line="8" text="raw return type matching in call ok"/> | |||
<message kind="warning" line="9" text="erasure type matching in call ok"/> | |||
<message kind="warning" line="10" text="erasure type matching in call ok"/> | |||
<message kind="warning" line="11" text="call and parameterized method ok"/> | |||
<message kind="warning" line="11" text="call and generic interface ok"/> | |||
<message kind="warning" line="12" text="call and interface control test"/> | |||
<message kind="warning" line="7" text="match on parameterized args"/> | |||
<message kind="warning" line="8" text="match on parameterized return type"/> | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/pointcuts" title="call with overriding of inherited generic members"> | |||
<compile files="CallOverriding.aj" options="-1.5"> | |||
<message kind="warning" line="8" text="wildcard declaring type match on erasure"/> | |||
<message kind="warning" line="9" text="wildcard declaring type match on erasure"/> | |||
<message kind="warning" line="10" text="wildcard declaring type match on erasure"/> | |||
<message kind="warning" line="8" text="base declaring type match on erasure"/> | |||
<message kind="warning" line="9" text="base declaring type match on erasure"/> | |||
<message kind="warning" line="10" text="base declaring type match on erasure"/> | |||
<message kind="warning" line="9" text="sub type match on erasure"/> | |||
<message kind="warning" line="10" text="parameterized match on erasure"/> | |||
<message kind="warning" line="87" text="erasure match on base interface"/> | |||
<message kind="warning" line="87" text="wildcard match on erasure"/> | |||
<message kind="warning" line="87" text="parameterized match"/> | |||
</compile> | |||
</ajc-test> | |||
<!-- end of generics and pointcuts tests --> | |||
<!-- ============================================================== --> |
@@ -267,7 +267,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
} | |||
public boolean hasAnnotation(UnresolvedType ofType) { | |||
// The ctors don't allow annotations to be specified ... yet - but | |||
// 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 | |||
@@ -388,7 +388,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
for (int i = 0; i < typeVariables.length; i++) { | |||
UnresolvedType array_element = typeVariables[i]; | |||
typeVariables[i] = typeVariables[i].resolve(world); | |||
} | |||
} | |||
} | |||
if (parameterTypes!=null && parameterTypes.length>0) { | |||
for (int i = 0; i < parameterTypes.length; i++) { | |||
@@ -396,7 +396,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
parameterTypes[i] = parameterTypes[i].resolve(world); | |||
} | |||
} | |||
returnType = returnType.resolve(world);return this; | |||
} | |||
@@ -601,9 +601,8 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
private ResolvedMember myErasure = null; | |||
private boolean calculatedMyErasure = false; | |||
/** | |||
/** | |||
* For ITDs, we use the default factory methods to build a resolved member, then alter a couple of characteristics | |||
* using this method - this is safe. | |||
*/ | |||
@@ -675,7 +674,12 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
StringBuffer sig = new StringBuffer(); | |||
UnresolvedType[] myParameterTypes = getParameterTypes(); | |||
for (int i = 0; i < myParameterTypes.length; i++) { | |||
sig.append(myParameterTypes[i].getSignature()); | |||
UnresolvedType thisParameter = myParameterTypes[i]; | |||
if (thisParameter.isTypeVariableReference()) { | |||
sig.append(thisParameter.getUpperBound().getSignature()); | |||
} else { | |||
sig.append(thisParameter.getSignature()); | |||
} | |||
} | |||
myParameterSignatureErasure = sig.toString(); | |||
return myParameterSignatureErasure; |