From 900a3e81d5b09c55e4044451f311f0566c025ec6 Mon Sep 17 00:00:00 2001 From: aclement Date: Thu, 4 Aug 2005 16:11:03 +0000 Subject: [PATCH] genericitds: lots of new support for recursive type variables and ITD ctors. --- .../ast/InterTypeConstructorDeclaration.java | 26 ++- .../ast/InterTypeMethodDeclaration.java | 31 ++-- .../compiler/lookup/EclipseFactory.java | 171 +++++++++++------- .../systemtest/ajc150/GenericsTests.java | 51 +++++- .../org/aspectj/systemtest/ajc150/ajc150.xml | 65 ++++++- .../aspectj/weaver/BoundedReferenceType.java | 22 ++- .../aspectj/weaver/JoinPointSignature.java | 17 ++ weaver/src/org/aspectj/weaver/MemberImpl.java | 12 +- .../org/aspectj/weaver/ResolvedMember.java | 7 +- .../aspectj/weaver/ResolvedMemberImpl.java | 35 +++- .../src/org/aspectj/weaver/TypeFactory.java | 9 +- .../src/org/aspectj/weaver/TypeVariable.java | 6 + .../weaver/TypeVariableReferenceType.java | 33 +++- .../UnresolvedTypeVariableReferenceType.java | 4 +- weaver/src/org/aspectj/weaver/World.java | 28 ++- 15 files changed, 386 insertions(+), 131 deletions(-) diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeConstructorDeclaration.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeConstructorDeclaration.java index d524dcfbd..0f0cf78b2 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeConstructorDeclaration.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeConstructorDeclaration.java @@ -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, "", 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(""); + signature.resetModifiers(declaredModifiers); + ResolvedMember syntheticInterMember = AjcMemberMaker.interConstructor(declaringTypeX, signature, aspectType); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeMethodDeclaration.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeMethodDeclaration.java index f20476fdd..21c5f2106 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeMethodDeclaration.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/InterTypeMethodDeclaration.java @@ -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); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseFactory.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseFactory.java index b853c14a0..85810decc 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseFactory.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseFactory.java @@ -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; diff --git a/tests/src/org/aspectj/systemtest/ajc150/GenericsTests.java b/tests/src/org/aspectj/systemtest/ajc150/GenericsTests.java index ab4e34add..f38a45198 100644 --- a/tests/src/org/aspectj/systemtest/ajc150/GenericsTests.java +++ b/tests/src/org/aspectj/systemtest/ajc150/GenericsTests.java @@ -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. > + */ + 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");} // ... (List) - public void testGenericMethodITD2() {runTest("generic method itd - 2");} // ... (List) called incorrectly - public void testGenericMethodITD3() {runTest("generic method itd - 3");} // ... (List,List) - public void testGenericMethodITD4() {runTest("generic method itd - 4");} // ... (List,List) - public void testGenericMethodITD5() {runTest("generic method itd - 5");} // ... (List,List) called incorrectly - public void testGenericMethodITD6() {runTest("generic method itd - 6");} // ... (List) + public void testGenericMethodITD1() {runTest("generic method itd - 1"); } // ... (List) + public void testGenericMethodITD2() {runTest("generic method itd - 2"); } // ... (List) called incorrectly + public void testGenericMethodITD3() {runTest("generic method itd - 3"); } // ... (List,List) + public void testGenericMethodITD4() {runTest("generic method itd - 4"); } // ... (List,List) + public void testGenericMethodITD5() {runTest("generic method itd - 5"); } // ... (List,List) called incorrectly + public void testGenericMethodITD6() {runTest("generic method itd - 6"); } // ... (List) + public void testGenericMethodITD7() {runTest("generic method itd - 7"); } // ... (List,List) + public void testGenericMethodITD8() {runTest("generic method itd - 8"); } // ... (List,List) called incorrectly + public void testGenericMethodITD9() {runTest("generic method itd - 9"); } // > ... (List) + public void testGenericMethodITD10() {runTest("generic method itd - 10");} // > ... (List) called incorrectly + public void testGenericMethodITD11() {runTest("generic method itd - 11");} // > ... (List) + public void testGenericMethodITD12() {runTest("generic method itd - 12");} // > ... (List) called incorrectly + public void testGenericMethodITD13() {runTest("generic method itd - 13");} // > ... (List) called correctly in a clever way ;) + public void testGenericMethodITD14() {runTest("generic method itd - 14");} // > ... (List) called incorrectly in a clever way + public void testGenericMethodITD15() {runTest("generic method itd - 15");} // > ... (List) called correctly in a clever way public void testParameterizedMethodITD1() {runTest("parameterized method itd - 1");} // (List) @@ -196,8 +228,11 @@ public class GenericsTests extends XMLBasedAjcTestCase { public void testParameterizedMethodITD4() {runTest("parameterized method itd - 4");} // (List) -// public void testNonStaticGenericCtorITD1() {runTest("generic ctor itd - 1");} -// public void testGenericITFSharingTypeVariable() { + public void testGenericCtorITD1() {runTest("generic ctor itd - 1");} // new(List) + public void testGenericCtorITD2() {runTest("generic ctor itd - 2");} // new(List,List) + public void testGenericCtorITD3() {runTest("generic ctor itd - 3");} // new(List,Comparator) + + // public void testGenericITFSharingTypeVariable() { // runTest("generic intertype field declaration, sharing type variable"); // } diff --git a/tests/src/org/aspectj/systemtest/ajc150/ajc150.xml b/tests/src/org/aspectj/systemtest/ajc150/ajc150.xml index 0d7143caa..d3e7cfd85 100644 --- a/tests/src/org/aspectj/systemtest/ajc150/ajc150.xml +++ b/tests/src/org/aspectj/systemtest/ajc150/ajc150.xml @@ -2386,9 +2386,19 @@ - - - + + + + + + + + + + + + + @@ -2447,6 +2457,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/weaver/src/org/aspectj/weaver/BoundedReferenceType.java b/weaver/src/org/aspectj/weaver/BoundedReferenceType.java index dfb8efc30..48ec7f927 100644 --- a/weaver/src/org/aspectj/weaver/BoundedReferenceType.java +++ b/weaver/src/org/aspectj/weaver/BoundedReferenceType.java @@ -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() { diff --git a/weaver/src/org/aspectj/weaver/JoinPointSignature.java b/weaver/src/org/aspectj/weaver/JoinPointSignature.java index 12f66fca1..9fefcdf23 100644 --- a/weaver/src/org/aspectj/weaver/JoinPointSignature.java +++ b/weaver/src/org/aspectj/weaver/JoinPointSignature.java @@ -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(); + } + } diff --git a/weaver/src/org/aspectj/weaver/MemberImpl.java b/weaver/src/org/aspectj/weaver/MemberImpl.java index cf2a16548..96a4478b2 100644 --- a/weaver/src/org/aspectj/weaver/MemberImpl.java +++ b/weaver/src/org/aspectj/weaver/MemberImpl.java @@ -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; diff --git a/weaver/src/org/aspectj/weaver/ResolvedMember.java b/weaver/src/org/aspectj/weaver/ResolvedMember.java index 6fd6c0a7c..17b1e2930 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedMember.java +++ b/weaver/src/org/aspectj/weaver/ResolvedMember.java @@ -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(); } \ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/ResolvedMemberImpl.java b/weaver/src/org/aspectj/weaver/ResolvedMemberImpl.java index de94d3c55..1acebd584 100644 --- a/weaver/src/org/aspectj/weaver/ResolvedMemberImpl.java +++ b/weaver/src/org/aspectj/weaver/ResolvedMemberImpl.java @@ -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. diff --git a/weaver/src/org/aspectj/weaver/TypeFactory.java b/weaver/src/org/aspectj/weaver/TypeFactory.java index e81d63238..465747b4d 100644 --- a/weaver/src/org/aspectj/weaver/TypeFactory.java +++ b/weaver/src/org/aspectj/weaver/TypeFactory.java @@ -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 diff --git a/weaver/src/org/aspectj/weaver/TypeVariable.java b/weaver/src/org/aspectj/weaver/TypeVariable.java index 66f9a2a0f..35623d7bd 100644 --- a/weaver/src/org/aspectj/weaver/TypeVariable.java +++ b/weaver/src/org/aspectj/weaver/TypeVariable.java @@ -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; } /** diff --git a/weaver/src/org/aspectj/weaver/TypeVariableReferenceType.java b/weaver/src/org/aspectj/weaver/TypeVariableReferenceType.java index c77e36cd7..9c47db1aa 100644 --- a/weaver/src/org/aspectj/weaver/TypeVariableReferenceType.java +++ b/weaver/src/org/aspectj/weaver/TypeVariableReferenceType.java @@ -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; diff --git a/weaver/src/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java b/weaver/src/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java index 667c10c43..cf8494ea4 100644 --- a/weaver/src/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java +++ b/weaver/src/org/aspectj/weaver/UnresolvedTypeVariableReferenceType.java @@ -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); } diff --git a/weaver/src/org/aspectj/weaver/World.java b/weaver/src/org/aspectj/weaver/World.java index 13c0e4889..053a3c10d 100644 --- a/weaver/src/org/aspectj/weaver/World.java +++ b/weaver/src/org/aspectj/weaver/World.java @@ -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; } -- 2.39.5