@@ -13,6 +13,7 @@ | |||
package org.aspectj.ajdt.internal.compiler.ast; | |||
import java.lang.reflect.Modifier; | |||
import org.aspectj.ajdt.internal.compiler.lookup.*; | |||
import org.aspectj.weaver.*; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile; | |||
@@ -94,9 +95,16 @@ public class InterTypeConstructorDeclaration extends InterTypeDeclaration { | |||
pre.scope = new MethodScope(scope, pre, true); | |||
//??? do we need to do anything with scope??? | |||
pre.binding = world.makeMethodBinding( | |||
AjcMemberMaker.preIntroducedConstructor(aspectTypeX, targetTypeX, | |||
world.fromBindings(binding.parameters))); | |||
// Use the factory to build a semi-correct resolvedmember - then patch it up with | |||
// reset calls. This is SAFE | |||
ResolvedMember preIntroducedConstructorRM = world.makeResolvedMember(binding); | |||
preIntroducedConstructorRM.resetName(NameMangler.preIntroducedConstructor(aspectTypeX, targetTypeX)); | |||
preIntroducedConstructorRM.resetModifiers(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL); | |||
preIntroducedConstructorRM.resetReturnTypeToObjectArray(); | |||
pre.binding = world.makeMethodBinding(preIntroducedConstructorRM); | |||
pre.bindArguments(); | |||
pre.bindThrownExceptions(); | |||
@@ -218,12 +226,14 @@ public class InterTypeConstructorDeclaration extends InterTypeDeclaration { | |||
ResolvedType declaringTypeX = world.fromEclipse(onTypeBinding); | |||
ResolvedType aspectType = world.fromEclipse(classScope.referenceContext.binding); | |||
ResolvedMember bindingAsMember = world.makeResolvedMember(binding); | |||
ResolvedMember signature = | |||
new ResolvedMemberImpl(Member.CONSTRUCTOR, declaringTypeX, declaredModifiers, | |||
ResolvedType.VOID, "<init>", bindingAsMember.getParameterTypes(), | |||
world.fromEclipse(binding.thrownExceptions)); | |||
// This signature represents what we want consumers of the targetted type to 'see' | |||
ResolvedMember signature = world.makeResolvedMember(binding,onTypeBinding); | |||
signature.resetKind(Member.CONSTRUCTOR); | |||
signature.resetName("<init>"); | |||
signature.resetModifiers(declaredModifiers); | |||
ResolvedMember syntheticInterMember = | |||
AjcMemberMaker.interConstructor(declaringTypeX, signature, aspectType); | |||
@@ -17,16 +17,6 @@ import java.lang.reflect.Modifier; | |||
import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory; | |||
import org.aspectj.ajdt.internal.compiler.lookup.EclipseTypeMunger; | |||
import org.aspectj.weaver.AjAttribute; | |||
import org.aspectj.weaver.AjcMemberMaker; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.NameMangler; | |||
import org.aspectj.weaver.NewMethodTypeMunger; | |||
import org.aspectj.weaver.ResolvedMember; | |||
import org.aspectj.weaver.ResolvedMemberImpl; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.Shadow; | |||
import org.aspectj.weaver.UnresolvedType; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; | |||
@@ -39,6 +29,14 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit; | |||
import org.aspectj.weaver.AjAttribute; | |||
import org.aspectj.weaver.AjcMemberMaker; | |||
import org.aspectj.weaver.NameMangler; | |||
import org.aspectj.weaver.NewMethodTypeMunger; | |||
import org.aspectj.weaver.ResolvedMember; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.Shadow; | |||
import org.aspectj.weaver.UnresolvedType; | |||
/** | |||
* An inter-type method declaration. | |||
@@ -125,12 +123,13 @@ public class InterTypeMethodDeclaration extends InterTypeDeclaration { | |||
if (isTargetAnnotation(classScope,"method")) return null; // Error message output in isTargetAnnotation | |||
if (isTargetEnum(classScope,"method")) return null; // Error message output in isTargetEnum | |||
ResolvedMemberImpl sig = new ResolvedMemberImpl(Member.METHOD, world.fromBinding(onTypeBinding), | |||
declaredModifiers, world.fromBinding(binding.returnType), new String(declaredSelector), | |||
world.fromBindings(binding.parameters), | |||
world.fromEclipse(binding.thrownExceptions)); | |||
sig.setTypeVariables(world.fromBindings(binding.typeVariables)); | |||
// This signature represents what we want consumers of the targetted type to 'see' | |||
// must use the factory method to build it since there may be typevariables from the binding | |||
// referred to in the parameters/returntype | |||
ResolvedMember sig = world.makeResolvedMember(binding,onTypeBinding); | |||
sig.resetName(new String(declaredSelector)); | |||
sig.resetModifiers(declaredModifiers); | |||
NewMethodTypeMunger myMunger = new NewMethodTypeMunger(sig, null); | |||
setMunger(myMunger); |
@@ -24,26 +24,8 @@ import java.util.Map; | |||
import org.aspectj.ajdt.internal.compiler.ast.AspectDeclaration; | |||
import org.aspectj.ajdt.internal.compiler.ast.AstUtil; | |||
import org.aspectj.ajdt.internal.core.builder.AjBuildManager; | |||
import org.aspectj.ajdt.internal.core.builder.AsmHierarchyBuilder; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.bridge.IMessage.Kind; | |||
import org.aspectj.weaver.BoundedReferenceType; | |||
import org.aspectj.weaver.ConcreteTypeMunger; | |||
import org.aspectj.weaver.IHasPosition; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.ReferenceType; | |||
import org.aspectj.weaver.ResolvedMember; | |||
import org.aspectj.weaver.ResolvedMemberImpl; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.Shadow; | |||
import org.aspectj.weaver.TypeFactory; | |||
import org.aspectj.weaver.TypeVariable; | |||
import org.aspectj.weaver.TypeVariableDeclaringElement; | |||
import org.aspectj.weaver.TypeVariableReference; | |||
import org.aspectj.weaver.TypeVariableReferenceType; | |||
import org.aspectj.weaver.UnresolvedType; | |||
import org.aspectj.weaver.UnresolvedTypeVariableReferenceType; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; | |||
@@ -64,9 +46,24 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Scope; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeConstants; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; | |||
import org.aspectj.weaver.BoundedReferenceType; | |||
import org.aspectj.weaver.ConcreteTypeMunger; | |||
import org.aspectj.weaver.IHasPosition; | |||
import org.aspectj.weaver.Member; | |||
import org.aspectj.weaver.ReferenceType; | |||
import org.aspectj.weaver.ResolvedMember; | |||
import org.aspectj.weaver.ResolvedMemberImpl; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.Shadow; | |||
import org.aspectj.weaver.TypeFactory; | |||
import org.aspectj.weaver.TypeVariable; | |||
import org.aspectj.weaver.TypeVariableDeclaringElement; | |||
import org.aspectj.weaver.TypeVariableReference; | |||
import org.aspectj.weaver.UnresolvedType; | |||
import org.aspectj.weaver.UnresolvedTypeVariableReferenceType; | |||
import org.aspectj.weaver.World; | |||
/** | |||
* @author Jim Hugunin | |||
@@ -231,10 +228,14 @@ public class EclipseFactory { | |||
} | |||
} | |||
ResolvedType baseType = UnresolvedType.forName(getName(binding)).resolve(getWorld()); | |||
return TypeFactory.createParameterizedType( | |||
baseType, | |||
arguments, | |||
getWorld()); | |||
// Create an unresolved parameterized type. We can't create a resolved one as the | |||
// act of resolution here may cause recursion problems since the parameters may | |||
// be type variables that we haven't fixed up yet. | |||
if (!baseType.isGenericType() && arguments!=null) baseType = baseType.getGenericType(); | |||
if (arguments==null) arguments=new UnresolvedType[0]; | |||
String parameterizedSig = ResolvedType.PARAMETERIZED_TYPE_IDENTIFIER+CharOperation.charToString(binding.genericTypeSignature()).substring(1); | |||
return TypeFactory.createUnresolvedParameterizedType(parameterizedSig,baseType.getErasureSignature(),arguments); | |||
} | |||
// Convert the source type binding for a generic type into a generic UnresolvedType | |||
@@ -261,27 +262,47 @@ public class EclipseFactory { | |||
return UnresolvedType.forName(getName(binding)); | |||
} | |||
/** | |||
* Some type variables refer to themselves recursively, this enables us to avoid | |||
* recursion problems. | |||
*/ | |||
private static Map typeVariableBindingsInProgress = new HashMap(); | |||
/** | |||
* Convert from the eclipse form of type variable (TypeVariableBinding) to the AspectJ | |||
* form (TypeVariable). | |||
*/ | |||
private UnresolvedType fromTypeVariableBinding(TypeVariableBinding aTypeVariableBinding) { | |||
// first, check for recursive call to this method for the same tvBinding | |||
if (typeVariableBindingsInProgress.containsKey(aTypeVariableBinding)) { | |||
return (UnresolvedType) typeVariableBindingsInProgress.get(aTypeVariableBinding); | |||
} | |||
if (typeVariablesForThisMember.containsKey(new Integer(aTypeVariableBinding.rank))) { | |||
return (UnresolvedType)typeVariablesForThisMember.get(new Integer(aTypeVariableBinding.rank)); | |||
} | |||
// Create the UnresolvedTypeVariableReferenceType for the type variable | |||
String name = CharOperation.charToString(aTypeVariableBinding.sourceName()); | |||
UnresolvedTypeVariableReferenceType ret = new UnresolvedTypeVariableReferenceType(); | |||
typeVariableBindingsInProgress.put(aTypeVariableBinding,ret); | |||
// Dont set any bounds here, you'll get in a recursive mess | |||
// TODO -- what about lower bounds?? | |||
String name = new String(aTypeVariableBinding.sourceName()); | |||
UnresolvedType superclassType = fromBinding(aTypeVariableBinding.superclass()); | |||
UnresolvedType superclassType = fromBinding(aTypeVariableBinding.superclass()); | |||
UnresolvedType[] superinterfaces = new UnresolvedType[aTypeVariableBinding.superInterfaces.length]; | |||
for (int i = 0; i < superinterfaces.length; i++) { | |||
superinterfaces[i] = fromBinding(aTypeVariableBinding.superInterfaces[i]); | |||
} | |||
TypeVariable tv = new TypeVariable(name,superclassType,superinterfaces); | |||
tv.setUpperBound(superclassType); | |||
tv.setAdditionalInterfaceBounds(superinterfaces); | |||
tv.setRank(aTypeVariableBinding.rank); | |||
// getting things right for method declaring elements is tricky... | |||
if (!(aTypeVariableBinding.declaringElement instanceof MethodBinding)) { | |||
tv.setDeclaringElement(fromBinding(aTypeVariableBinding.declaringElement)); | |||
} | |||
tv.resolve(world); | |||
// dont need the declaring element yet... | |||
// if (aTypeVariableBinding.declaringElement instanceof MethodBinding) { | |||
// tv.setDeclaringElement(fromBinding((MethodBinding)aTypeVariableBinding.declaringElement); | |||
// } else { | |||
// // tv.setDeclaringElement(fromBinding(aTypeVariableBinding.declaringElement)); | |||
// } | |||
ret.setTypeVariable(tv); | |||
typeVariableBindingsInProgress.remove(aTypeVariableBinding); | |||
return ret; | |||
@@ -369,8 +390,30 @@ public class EclipseFactory { | |||
return makeResolvedMember(binding, binding.declaringClass); | |||
} | |||
/** | |||
* Conversion from a methodbinding (eclipse) to a resolvedmember (aspectj) is now done | |||
* in the scope of some type variables. Before converting the parts of a methodbinding | |||
* (params, return type) we store the type variables in this structure, then should any | |||
* component of the method binding refer to them, we grab them from the map. | |||
*/ | |||
// FIXME asc convert to array, indexed by rank | |||
private Map typeVariablesForThisMember = new HashMap(); | |||
public ResolvedMember makeResolvedMember(MethodBinding binding, TypeBinding declaringType) { | |||
//System.err.println("member for: " + binding + ", " + new String(binding.declaringClass.sourceName)); | |||
// Convert the type variables and store them | |||
UnresolvedType[] ajTypeRefs = null; | |||
// This is the set of type variables available whilst building the resolved member... | |||
if (binding.typeVariables!=null) { | |||
ajTypeRefs = new UnresolvedType[binding.typeVariables.length]; | |||
for (int i = 0; i < binding.typeVariables.length; i++) { | |||
ajTypeRefs[i] = fromBinding(binding.typeVariables[i]); | |||
typeVariablesForThisMember.put(new Integer(binding.typeVariables[i].rank),ajTypeRefs[i]); | |||
} | |||
} | |||
// AMC these next two lines shouldn't be needed once we sort out generic types properly in the world map | |||
ResolvedType realDeclaringType = world.resolve(fromBinding(declaringType)); | |||
if (realDeclaringType.isRawType()) realDeclaringType = realDeclaringType.getGenericType(); | |||
@@ -378,10 +421,14 @@ public class EclipseFactory { | |||
binding.isConstructor() ? Member.CONSTRUCTOR : Member.METHOD, | |||
realDeclaringType, | |||
binding.modifiers, | |||
world.resolve(fromBinding(binding.returnType)), | |||
fromBinding(binding.returnType), | |||
new String(binding.selector), | |||
world.resolve(fromBindings(binding.parameters)), | |||
world.resolve(fromBindings(binding.thrownExceptions))); | |||
fromBindings(binding.parameters), | |||
fromBindings(binding.thrownExceptions) | |||
); | |||
if (ajTypeRefs!=null) ret.setTypeVariables(ajTypeRefs); | |||
typeVariablesForThisMember.clear(); | |||
ret.resolve(world); | |||
return ret; | |||
} | |||
@@ -407,7 +454,7 @@ public class EclipseFactory { | |||
if (ret == null) { | |||
ret = makeTypeBinding1(typeX); | |||
// FIXME asc keep type variables *out* of the map for now, they go in typeVariableToTypeBinding | |||
if (!(typeX instanceof TypeVariableReference)) | |||
if (!(typeX instanceof BoundedReferenceType)) | |||
typexToBinding.put(typeX, ret); | |||
} | |||
if (ret == null) { | |||
@@ -457,8 +504,8 @@ public class EclipseFactory { | |||
BoundedReferenceType brt = (BoundedReferenceType)typeX; | |||
// Work out 'kind' for the WildcardBinding | |||
int boundkind = Wildcard.UNBOUND; | |||
if (brt.isGenericWildcardExtends()) boundkind = Wildcard.EXTENDS; | |||
if (brt.isGenericWildcardSuper()) boundkind = Wildcard.SUPER; | |||
if (brt.isExtends()) boundkind = Wildcard.EXTENDS; | |||
if (brt.isSuper()) boundkind = Wildcard.SUPER; | |||
// get the bound right | |||
TypeBinding bound = null; | |||
if (brt.isGenericWildcardExtends()) bound = makeTypeBinding(brt.getUpperBound()); | |||
@@ -518,46 +565,48 @@ public class EclipseFactory { | |||
public MethodBinding makeMethodBinding(ResolvedMember member) { | |||
typeVariableToTypeBinding.clear(); | |||
ReferenceBinding declaringType = (ReferenceBinding)makeTypeBinding(member.getDeclaringType()); | |||
MethodBinding mb = new MethodBinding(member.getModifiers(), | |||
member.getName().toCharArray(), | |||
makeTypeBinding(member.getReturnType()), | |||
makeTypeBindings(member.getParameterTypes()), | |||
makeReferenceBindings(member.getExceptions()), | |||
declaringType); | |||
TypeVariableBinding[] tvbs = null; | |||
if (member.getTypeVariables()!=null) { | |||
if (member.getTypeVariables().length==0) { | |||
mb.typeVariables = MethodBinding.NoTypeVariables; | |||
tvbs = MethodBinding.NoTypeVariables; | |||
} else { | |||
TypeVariableBinding[] tvbs = makeTypeVariableBindings(member.getTypeVariables()); | |||
tvbs = makeTypeVariableBindings(member.getTypeVariables()); | |||
// fixup the declaring element, we couldn't do it whilst processing the typevariables as we'll end up in recursion. | |||
for (int i = 0; i < tvbs.length; i++) { | |||
TypeVariableBinding binding = tvbs[i]; | |||
if (binding.declaringElement==null && ((TypeVariableReference)member.getTypeVariables()[i]).getTypeVariable().getDeclaringElement() instanceof Member) { | |||
tvbs[i].declaringElement = mb; | |||
} else { | |||
tvbs[i].declaringElement = declaringType; | |||
} | |||
// if (binding.declaringElement==null && ((TypeVariableReference)member.getTypeVariables()[i]).getTypeVariable().getDeclaringElement() instanceof Member) { | |||
// tvbs[i].declaringElement = mb; | |||
// } else { | |||
// tvbs[i].declaringElement = declaringType; | |||
// } | |||
} | |||
mb.typeVariables = tvbs; | |||
} | |||
} | |||
} | |||
ReferenceBinding declaringType = (ReferenceBinding)makeTypeBinding(member.getDeclaringType()); | |||
MethodBinding mb = new MethodBinding(member.getModifiers(), | |||
member.getName().toCharArray(), | |||
makeTypeBinding(member.getReturnType()), | |||
makeTypeBindings(member.getParameterTypes()), | |||
makeReferenceBindings(member.getExceptions()), | |||
declaringType); | |||
if (tvbs!=null) mb.typeVariables = tvbs; | |||
typeVariableToTypeBinding.clear(); | |||
return mb; | |||
} | |||
/** | |||
* Convert a bunch of type variables in one go, from AspectJ form to Eclipse form. | |||
*/ | |||
private TypeVariableBinding[] makeTypeVariableBindings(UnresolvedType[] typeVariables) { | |||
int len = typeVariables.length; | |||
TypeVariableBinding[] ret = new TypeVariableBinding[len]; | |||
for (int i = 0; i < len; i++) { | |||
TypeVariableReference tvReference = (TypeVariableReference)typeVariables[i]; | |||
TypeVariableBinding tvb = (TypeVariableBinding)typeVariableToTypeBinding.get(tvReference.getTypeVariable().getName()); | |||
if (tvb==null) { | |||
tvb = makeTypeVariableBinding(tvReference); | |||
} | |||
ret[i] = tvb; | |||
ret[i] = makeTypeVariableBinding((TypeVariableReference)typeVariables[i]); | |||
} | |||
return ret; | |||
} | |||
@@ -575,7 +624,7 @@ public class EclipseFactory { | |||
*/ | |||
private TypeVariableBinding makeTypeVariableBinding(TypeVariableReference tvReference) { | |||
TypeVariable tVar = tvReference.getTypeVariable(); | |||
TypeVariableBinding tvBinding = (TypeVariableBinding)typeVariableToTypeBinding.get(tVar); | |||
TypeVariableBinding tvBinding = (TypeVariableBinding)typeVariableToTypeBinding.get(tVar.getName()); | |||
if (tvBinding==null) { | |||
Binding declaringElement = null; | |||
// this will cause an infinite loop or NPE... not required yet luckily. | |||
@@ -585,6 +634,7 @@ public class EclipseFactory { | |||
// declaringElement = makeTypeBinding((UnresolvedType)tVar.getDeclaringElement()); | |||
// } | |||
tvBinding = new TypeVariableBinding(tVar.getName().toCharArray(),declaringElement,tVar.getRank()); | |||
typeVariableToTypeBinding.put(tVar.getName(),tvBinding); | |||
tvBinding.superclass=(ReferenceBinding)makeTypeBinding(tVar.getUpperBound()); | |||
tvBinding.firstBound=tvBinding.superclass; // FIXME asc is this correct? possibly it could be first superinterface | |||
if (tVar.getAdditionalInterfaceBounds()==null) { | |||
@@ -596,7 +646,6 @@ public class EclipseFactory { | |||
rbs[i] = (ReferenceBinding)tbs[i]; | |||
} | |||
tvBinding.superInterfaces=rbs; | |||
typeVariableToTypeBinding.put(tVar.getName(),tvBinding); | |||
} | |||
} | |||
return tvBinding; |
@@ -99,6 +99,29 @@ public class GenericsTests extends XMLBasedAjcTestCase { | |||
* - wait till we get there! | |||
*/ | |||
/* ========================================== | |||
* Generics test plan for ITDs. | |||
* | |||
* think about: | |||
* - source/binary weaving | |||
* - visibility default/private/public | |||
* - static/nonstatic | |||
* - parameterized ITDs (methods/ctors/fields) | |||
* - ITD target: interface/class/aspect | |||
* - multiple type variables | |||
* - generic ITDs (like generic methods) | |||
* - constructor ITDs, method ITDs | |||
* - ITDs sharing type variables with generic types | |||
* - relating to above point, this makes generic ITD fields possible | |||
* - signature attributes for generic ITDs (required? required only for public ITDs?) | |||
* - binary weaving when target type changes over time (might start out 'simple' then sometime later be 'generic') | |||
* - bridge methods - when to create them | |||
* - multiple 'separate' ITDs in a file that share a type variable by 'name' | |||
* - wildcards '?' 'extends' 'super' '&' | |||
* - do type variables assigned to members need to persist across serialization | |||
* - recursive type variable definitions eg. <R extends Comparable<? super R>> | |||
*/ | |||
public static Test suite() { | |||
return XMLBasedAjcTestCase.loadSuite(GenericsTests.class); | |||
} | |||
@@ -182,12 +205,21 @@ 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>) | |||
public void testGenericMethodITD10() {runTest("generic method itd - 10");} // <R extends Comparable<? super R>> ... (List<R>) called incorrectly | |||
public void testGenericMethodITD11() {runTest("generic method itd - 11");} // <R extends Comparable<? extends R>> ... (List<R>) | |||
public void testGenericMethodITD12() {runTest("generic method itd - 12");} // <R extends Comparable<? extends R>> ... (List<R>) called incorrectly | |||
public void testGenericMethodITD13() {runTest("generic method itd - 13");} // <R extends Comparable<? extends R>> ... (List<R>) called correctly in a clever way ;) | |||
public void testGenericMethodITD14() {runTest("generic method itd - 14");} // <R extends Comparable<? super R>> ... (List<R>) called incorrectly in a clever way | |||
public void testGenericMethodITD15() {runTest("generic method itd - 15");} // <R extends Comparable<? super R>> ... (List<R>) called correctly in a clever way | |||
public void testParameterizedMethodITD1() {runTest("parameterized method itd - 1");} // (List<? extends Super>) | |||
@@ -196,8 +228,11 @@ public class GenericsTests extends XMLBasedAjcTestCase { | |||
public void testParameterizedMethodITD4() {runTest("parameterized method itd - 4");} // (List<? super B>) | |||
// public void testNonStaticGenericCtorITD1() {runTest("generic ctor itd - 1");} | |||
// public void testGenericITFSharingTypeVariable() { | |||
public void testGenericCtorITD1() {runTest("generic ctor itd - 1");} // <T> new(List<T>) | |||
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() { | |||
// runTest("generic intertype field declaration, sharing type variable"); | |||
// } | |||
@@ -2386,9 +2386,19 @@ | |||
</run> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="non static generic ctor itd - 1"> | |||
<compile files="NonstaticGenericCtorITD1.aj" options="-1.5"/> | |||
<run class="NonstaticGenericCtorITD1"/> | |||
<ajc-test dir="java5/generics/itds" title="generic ctor itd - 1"> | |||
<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"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="generic ctor itd - 3"> | |||
<compile files="GenericCtorITD3.aj" options="-1.5"/> | |||
<run class="GenericCtorITD3"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="parameterized method itd - 1"> | |||
@@ -2447,6 +2457,55 @@ | |||
<run class="GenericMethodITD6"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="generic method itd - 7"> | |||
<compile files="GenericMethodITD7.aj" options="-1.5"/> | |||
<run class="GenericMethodITD7"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="generic method itd - 8"> | |||
<compile files="GenericMethodITD8.aj" options="-1.5"> | |||
<message kind="error" line="10" text="The method simple(List<E>, List<? extends E>) in the type X is not applicable for the arguments (List<Number>, List<String>)"/> | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="generic method itd - 9"> | |||
<compile files="GenericMethodITD9.aj" options="-1.5"/> | |||
<run class="GenericMethodITD9"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="generic method itd - 10"> | |||
<compile files="GenericMethodITD10.aj" options="-1.5"> | |||
<message kind="error" line="10" text="Bound mismatch: The generic method crazy(List<R>) of type X is not applicable for the arguments (List<A>) since the type A is not a valid substitute for the bounded parameter <R extends Object & Comparable<? super R>>"/> | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="generic method itd - 11"> | |||
<compile files="GenericMethodITD11.aj" options="-1.5"/> | |||
<run class="GenericMethodITD11"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="generic method itd - 12"> | |||
<compile files="GenericMethodITD12.aj" options="-1.5"> | |||
<message kind="error" line="10" text="Bound mismatch: The generic method crazy(List<R>) of type X is not applicable for the arguments (List<A>) since the type A is not a valid substitute for the bounded parameter <R extends Object & Foo<? extends R>>"/> | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="generic method itd - 13"> | |||
<compile files="GenericMethodITD13.aj" options="-1.5"/> | |||
<run class="GenericMethodITD13"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="generic method itd - 14"> | |||
<compile files="GenericMethodITD14.aj" options="-1.5"> | |||
<message kind="error" line="10" text="Bound mismatch: The generic method crazy(List<R>) of type X is not applicable for the arguments (List<A>) since the type A is not a valid substitute for the bounded parameter <R extends Object & Foo<? super R>>"/> | |||
</compile> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="generic method itd - 15"> | |||
<compile files="GenericMethodITD15.aj" options="-1.5"/> | |||
<run class="GenericMethodITD15"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds" title="non static generic method itd - 2"> | |||
<compile files="NonstaticGenericCtorITD2.aj" options="-1.5"/> | |||
<run class="NonstaticGenericCtorITD2"/> |
@@ -19,17 +19,23 @@ import org.aspectj.weaver.patterns.PerClause; | |||
/** | |||
* A BoundedReferenceType is the result of a generics wildcard expression | |||
* ? extends String, ? super Foo etc.. | |||
* | |||
* The "signature" for a bounded reference type follows the generic signature | |||
* specification in section 4.4 of JVM spec: *,+,- plus signature strings | |||
* specification in section 4.4 of JVM spec: *,+,- plus signature strings. | |||
* | |||
* The bound may be a type variable (e.g. ? super T) | |||
*/ | |||
public class BoundedReferenceType extends ReferenceType { | |||
protected ReferenceType[] additionalInterfaceBounds = new ReferenceType[0]; | |||
protected boolean isExtends = true; | |||
protected boolean isSuper = false; | |||
protected boolean isSuper = false; | |||
public BoundedReferenceType(ReferenceType aBound, boolean isExtends, World world) { | |||
super((isExtends ? "+" : "-") + aBound.signature,world); | |||
this.isExtends = isExtends; this.isSuper=!isExtends; | |||
this.isExtends = isExtends; | |||
this.isSuper = !isExtends; | |||
if (isExtends) { | |||
setUpperBound(aBound); | |||
} else { | |||
@@ -38,7 +44,7 @@ public class BoundedReferenceType extends ReferenceType { | |||
} | |||
setDelegate(new ReferenceTypeReferenceTypeDelegate((ReferenceType)getUpperBound())); | |||
} | |||
public BoundedReferenceType(ReferenceType aBound, boolean isExtends, World world, ReferenceType[] additionalInterfaces) { | |||
this(aBound,isExtends,world); | |||
this.additionalInterfaceBounds = additionalInterfaces; | |||
@@ -51,20 +57,22 @@ public class BoundedReferenceType extends ReferenceType { | |||
/** | |||
* only for use when resolving GenericsWildcardTypeX or a TypeVariableReferenceType | |||
*/ | |||
BoundedReferenceType(String sig, World world) { | |||
protected BoundedReferenceType(String sig, World world) { | |||
super(sig,world); | |||
setUpperBound(world.resolve(UnresolvedType.OBJECT)); | |||
setDelegate(new ReferenceTypeReferenceTypeDelegate((ReferenceType)getUpperBound())); | |||
} | |||
public ReferenceType[] getInterfaceBounds() { return additionalInterfaceBounds; } | |||
public ReferenceType[] getInterfaceBounds() { | |||
return additionalInterfaceBounds; | |||
} | |||
public boolean hasLowerBound() { | |||
return getLowerBound() != null; | |||
} | |||
public boolean isExtends() { return isExtends; } | |||
public boolean isSuper() { return isSuper; } | |||
public boolean isSuper() { return isSuper; } | |||
// override to include additional interface bounds... | |||
public ResolvedType[] getDeclaredInterfaces() { |
@@ -17,6 +17,7 @@ import java.util.Collection; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.weaver.AjAttribute.EffectiveSignatureAttribute; | |||
import org.aspectj.weaver.Member.Kind; | |||
/** | |||
* @author colyer | |||
@@ -351,4 +352,20 @@ public class JoinPointSignature implements ResolvedMember { | |||
return buf.toString(); | |||
} | |||
public void resetName(String newName) { | |||
realMember.resetName(newName); | |||
} | |||
public void resetKind(Kind newKind) { | |||
realMember.resetKind(newKind); | |||
} | |||
public void resetModifiers(int newModifiers) { | |||
realMember.resetModifiers(newModifiers); | |||
} | |||
public void resetReturnTypeToObjectArray() { | |||
realMember.resetReturnTypeToObjectArray(); | |||
} | |||
} |
@@ -21,14 +21,14 @@ import java.util.Iterator; | |||
import java.util.List; | |||
public class MemberImpl implements Comparable, AnnotatedElement, Member { | |||
public class MemberImpl implements Comparable, AnnotatedElement,Member { | |||
private final Kind kind; | |||
protected Kind kind; | |||
protected UnresolvedType declaringType; | |||
protected final int modifiers; // protected because ResolvedMember uses it | |||
private final UnresolvedType returnType; | |||
private final String name; | |||
private final UnresolvedType[] parameterTypes; | |||
protected int modifiers; | |||
protected UnresolvedType returnType; | |||
protected String name; | |||
protected UnresolvedType[] parameterTypes; | |||
private final String signature; | |||
private final String declaredSignature; // TODO asc Is this redundant? Is it needed for generics? | |||
private String paramSignature; |
@@ -17,6 +17,7 @@ import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.weaver.Member.Kind; | |||
public interface ResolvedMember extends Member, AnnotatedElement, TypeVariableDeclaringElement { | |||
@@ -135,5 +136,9 @@ public interface ResolvedMember extends Member, AnnotatedElement, TypeVariableDe | |||
* variable to match any other type variable regardless of bounds. | |||
*/ | |||
public boolean matches(ResolvedMember aCandidateMatch); | |||
public void resetName(String newName); | |||
public void resetKind(Kind newKind); | |||
public void resetModifiers(int newModifiers); | |||
public void resetReturnTypeToObjectArray(); | |||
} |
@@ -26,6 +26,7 @@ import java.util.Map; | |||
import java.util.Set; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.weaver.Member.Kind; | |||
/** | |||
* This is the declared member, i.e. it will always correspond to an | |||
@@ -266,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 | |||
@@ -372,7 +373,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
public ResolvedMember resolve(World world) { | |||
// FIXME asc guard with a check on resolution having happened ! | |||
// make sure all the pieces of a resolvedmember really are resolved | |||
if (annotationTypes!=null) { | |||
Set r = new HashSet(); | |||
for (Iterator iter = annotationTypes.iterator(); iter.hasNext();) { | |||
@@ -383,7 +384,20 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
} | |||
declaringType = declaringType.resolve(world); | |||
if (declaringType.isRawType()) declaringType = ((ReferenceType)declaringType).getGenericType(); | |||
return this; | |||
if (typeVariables!=null && typeVariables.length>0) { | |||
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++) { | |||
UnresolvedType array_element = parameterTypes[i]; | |||
parameterTypes[i] = parameterTypes[i].resolve(world); | |||
} | |||
} | |||
returnType = returnType.resolve(world);return this; | |||
} | |||
public ISourceContext getSourceContext(World world) { | |||
@@ -587,7 +601,20 @@ 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. | |||
*/ | |||
public void resetName(String newName) {this.name = newName;} | |||
public void resetKind(Kind newKind) {this.kind=newKind; } | |||
public void resetModifiers(int newModifiers) {this.modifiers=newModifiers;} | |||
public void resetReturnTypeToObjectArray() { | |||
returnType = UnresolvedType.OBJECTARRAY; | |||
} | |||
/** | |||
* Returns a copy of this member but with the declaring type swapped. | |||
* Copy only needs to be shallow. |
@@ -38,7 +38,7 @@ public class TypeFactory { | |||
ResolvedType baseType = aBaseType; | |||
if (!aBaseType.isGenericType()) { | |||
// try and find the generic type... | |||
if (someTypeParameters != null) { | |||
if (someTypeParameters != null && someTypeParameters.length>0) { | |||
if (!aBaseType.isRawType()) throw new IllegalStateException("Expecting raw type"); | |||
baseType = baseType.getGenericType(); | |||
if (baseType == null) throw new IllegalStateException("Raw type does not have generic type set"); | |||
@@ -50,6 +50,13 @@ public class TypeFactory { | |||
return (ReferenceType) pType.resolve(inAWorld); | |||
} | |||
/** | |||
* Create an *unresolved* parameterized version of a generic type. | |||
*/ | |||
public static UnresolvedType createUnresolvedParameterizedType(String sig,String erasuresig,UnresolvedType[] arguments) { | |||
return new UnresolvedType(sig,erasuresig,arguments); | |||
} | |||
public static ReferenceType createRawType( | |||
ResolvedType aBaseType, | |||
World inAWorld |
@@ -25,6 +25,9 @@ public class TypeVariable { | |||
*/ | |||
private boolean isResolved = false; | |||
private boolean beingResolved = false; | |||
/** | |||
* the name of the type variable as recorded in the generic signature | |||
*/ | |||
@@ -93,6 +96,8 @@ public class TypeVariable { | |||
* resolve all the bounds of this type variable | |||
*/ | |||
public void resolve(World inSomeWorld) { | |||
if (beingResolved) { return; } // avoid spiral of death | |||
beingResolved = true; | |||
if (isResolved) return; | |||
upperBound = upperBound.resolve(inSomeWorld); | |||
@@ -103,6 +108,7 @@ public class TypeVariable { | |||
} | |||
isResolved = true; | |||
beingResolved = false; | |||
} | |||
/** |
@@ -23,18 +23,29 @@ public class TypeVariableReferenceType extends BoundedReferenceType implements T | |||
World aWorld) { | |||
super(aTypeVariable.getUpperBound().getSignature(),aWorld); | |||
this.typeVariable = aTypeVariable; | |||
this.isExtends = false; | |||
this.isSuper = false; | |||
setUpperBound(aTypeVariable.getUpperBound()); | |||
setLowerBound(aTypeVariable.getLowerBound()); | |||
UnresolvedType[] ifBounds = aTypeVariable.getAdditionalInterfaceBounds(); | |||
if (ifBounds.length > 0) { | |||
this.additionalInterfaceBounds = new ReferenceType[ifBounds.length]; | |||
this.isExtends = false; | |||
this.isSuper = false; | |||
setDelegate(new ReferenceTypeReferenceTypeDelegate((ReferenceType)aTypeVariable.getUpperBound())); | |||
} | |||
public UnresolvedType getUpperBound() { | |||
if (typeVariable==null) return super.getUpperBound(); | |||
return typeVariable.getUpperBound(); | |||
} | |||
public UnresolvedType getLowerBound() { | |||
return typeVariable.getLowerBound(); | |||
} | |||
public ReferenceType[] getAdditionalBounds() { | |||
if (additionalInterfaceBounds ==null && typeVariable.getAdditionalInterfaceBounds()!=null) { | |||
UnresolvedType [] ifBounds = typeVariable.getAdditionalInterfaceBounds(); | |||
additionalInterfaceBounds = new ReferenceType[ifBounds.length]; | |||
for (int i = 0; i < ifBounds.length; i++) { | |||
this.additionalInterfaceBounds[i] = (ReferenceType) ifBounds[i]; | |||
additionalInterfaceBounds[i] = (ReferenceType) ifBounds[i]; | |||
} | |||
} | |||
setDelegate(new ReferenceTypeReferenceTypeDelegate((ReferenceType)aTypeVariable.getUpperBound())); | |||
return additionalInterfaceBounds; | |||
} | |||
public TypeVariable getTypeVariable() { | |||
@@ -45,6 +56,10 @@ public class TypeVariableReferenceType extends BoundedReferenceType implements T | |||
return true; | |||
} | |||
// public ResolvedType resolve(World world) { | |||
// return super.resolve(world); | |||
//} | |||
/** | |||
* return the signature for a *REFERENCE* to a type variable, which is simply: | |||
* Tname; |
@@ -37,7 +37,9 @@ public class UnresolvedTypeVariableReferenceType extends UnresolvedType implemen | |||
} | |||
public ResolvedType resolve(World world) { | |||
if (typeVariable == null) return ResolvedType.MISSING; | |||
if (typeVariable == null) { | |||
throw new BCException("Cannot resolve this type variable reference, the type variable has not been set!"); | |||
} | |||
typeVariable.resolve(world); | |||
return new TypeVariableReferenceType(typeVariable,world); | |||
} |
@@ -249,7 +249,7 @@ public abstract class World implements Dump.INode { | |||
/** | |||
* Resolve to a ReferenceType - simple, raw, parameterized, or generic. | |||
* Raw, parmeterized, and generic versions of a type share a delegate. | |||
* Raw, parameterized, and generic versions of a type share a delegate. | |||
*/ | |||
private final ResolvedType resolveToReferenceType(UnresolvedType ty) { | |||
if (ty.isParameterizedType()) { | |||
@@ -309,6 +309,17 @@ public abstract class World implements Dump.INode { | |||
// raw type from a source type, it won't if its been created just through | |||
// being referenced, e.g. java.util.List | |||
ResolvedType genericType = rawType.getGenericType(); | |||
// There is a special case to consider here (testGenericsBang_pr95993 highlights it) | |||
// You may have an unresolvedType for a parameterized type but it | |||
// is backed by a simple type rather than a generic type. This occurs for | |||
// inner types of generic types that inherit their enclosing types | |||
// type variables. | |||
if (rawType.isSimpleType() && anUnresolvedType.typeParameters.length==0) { | |||
rawType.world = this; | |||
return rawType; | |||
} | |||
if (genericType != null) { | |||
genericType.world = this; | |||
return genericType; | |||
@@ -324,18 +335,23 @@ public abstract class World implements Dump.INode { | |||
} | |||
} | |||
// we have a generic wildcard with either extends or super, resolves to a | |||
// BoundedReferenceType | |||
/** | |||
* Go from an unresolved generic wildcard (represented by UnresolvedType) to a resolved version (BoundedReferenceType). | |||
*/ | |||
private ReferenceType resolveGenericWildcardFor(UnresolvedType aType) { | |||
BoundedReferenceType ret = null; | |||
// FIXME asc isExtends? isGenericWildcardExtends? I dont like having two | |||
// FIXME asc doesnt take account of additional interface bounds (e.g. ? super R & Serializable - can you do that?) | |||
if (aType.isGenericWildcardExtends()) { | |||
ReferenceType upperBound = (ReferenceType) resolve(aType.getUpperBound()); | |||
ReferenceType upperBound = (ReferenceType)resolve(aType.getUpperBound()); | |||
ret = new BoundedReferenceType(upperBound,true,this); | |||
} else { | |||
} else { | |||
ReferenceType lowerBound = (ReferenceType) resolve(aType.getLowerBound()); | |||
ret = new BoundedReferenceType(lowerBound,false,this); | |||
} | |||
typeMap.put(aType.getSignature(),ret); | |||
// FIXME asc verify: I don't think these go in the typemap, it makes it potentially impossible to differentiate different uses of 'T', | |||
// for example '? super T' where T is representing different things in two places would have the same sig (-TT;) | |||
// typeMap.put(aType.getSignature(),ret); | |||
return ret; | |||
} | |||