@@ -17,7 +17,6 @@ import java.lang.reflect.Modifier; | |||
import junit.framework.TestCase; | |||
import org.aspectj.internal.lang.annotation.ajcDeclareEoW; | |||
import org.aspectj.internal.lang.annotation.ajcITD; | |||
import org.aspectj.internal.lang.annotation.ajcPrivileged; | |||
import org.aspectj.lang.annotation.AdviceName; | |||
import org.aspectj.lang.annotation.After; |
@@ -47,7 +47,6 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.PackageBinding; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; | |||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TagBits; | |||
@@ -57,7 +56,6 @@ import org.aspectj.weaver.AsmRelationshipProvider; | |||
import org.aspectj.weaver.ConcreteTypeMunger; | |||
import org.aspectj.weaver.ReferenceType; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.ResolvedTypeMunger; | |||
import org.aspectj.weaver.UnresolvedType; | |||
import org.aspectj.weaver.WeaverMessages; | |||
import org.aspectj.weaver.WeaverStateInfo; | |||
@@ -543,6 +541,7 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC | |||
needOldStyleWarning = false; | |||
} | |||
onType.addInterTypeMunger(munger); | |||
/* | |||
//TODO: Andy Should be done at weave time. | |||
// Unfortunately we can't do it at weave time unless the type mungers remember where | |||
// they came from. Thats why we do it here during complation because at this time | |||
@@ -554,6 +553,7 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC | |||
// AsmRelationshipProvider (see BCELTypeMunger) | |||
if (!ResolvedTypeMunger.persistSourceLocation) // Do it up front if we bloody have to | |||
AsmInterTypeRelationshipProvider.getDefault().addRelationship(onType, munger); | |||
*/ | |||
} | |||
} | |||
@@ -863,7 +863,7 @@ public class AjLookupEnvironment extends LookupEnvironment implements AnonymousC | |||
needFieldsAndMethods, | |||
accessRestriction); | |||
factory.getWorld().validateType(factory.fromBinding(ret)); | |||
// if you need the bytes to pass to validate, here they are:ClassFileReader)binaryType).getReferenceBytes() | |||
// if you need the bytes to pass to validate, here they are:((ClassFileReader)binaryType).getReferenceBytes() | |||
weaveInterTypeDeclarations(ret); | |||
return ret; | |||
} finally { |
@@ -464,10 +464,11 @@ public class EclipseFactory { | |||
ret.setVarargsMethod(); | |||
} | |||
if (typeVariablesForThisMember.size()!=0) { | |||
UnresolvedType[] tvars = new UnresolvedType[typeVariablesForThisMember.size()]; | |||
// SAUSAGES this might be broken with the change for resolved members to own type variables | |||
TypeVariable[] tvars = new TypeVariable[typeVariablesForThisMember.size()]; | |||
int i =0; | |||
for (Iterator iter = typeVariablesForThisMember.values().iterator(); iter.hasNext();) { | |||
tvars[i++] = (UnresolvedType)iter.next(); | |||
tvars[i++] = ((TypeVariableReference)((UnresolvedType)iter.next())).getTypeVariable(); | |||
} | |||
ret.setTypeVariables(tvars); | |||
} | |||
@@ -621,7 +622,7 @@ public class EclipseFactory { | |||
if (member.getTypeVariables().length==0) { | |||
tvbs = MethodBinding.NoTypeVariables; | |||
} else { | |||
tvbs = makeTypeVariableBindings(member.getTypeVariables()); | |||
tvbs = makeTypeVariableBindingsFromAJTypeVariables(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]; | |||
@@ -661,6 +662,15 @@ public class EclipseFactory { | |||
} | |||
return ret; | |||
} | |||
private TypeVariableBinding[] makeTypeVariableBindingsFromAJTypeVariables(TypeVariable[] typeVariables) { | |||
int len = typeVariables.length; | |||
TypeVariableBinding[] ret = new TypeVariableBinding[len]; | |||
for (int i = 0; i < len; i++) { | |||
ret[i] = makeTypeVariableBindingFromAJTypeVariable(typeVariables[i]); | |||
} | |||
return ret; | |||
} | |||
// only accessed through private methods in this class. Ensures all type variables we encounter | |||
// map back to the same type binding - this is important later when Eclipse code is processing | |||
@@ -705,6 +715,38 @@ public class EclipseFactory { | |||
} | |||
return tvBinding; | |||
} | |||
private TypeVariableBinding makeTypeVariableBindingFromAJTypeVariable(TypeVariable tv) { | |||
TypeVariableBinding tvBinding = (TypeVariableBinding)typeVariableToTypeBinding.get(tv.getName()); | |||
if (currentType!=null) { | |||
TypeVariableBinding tvb = currentType.getTypeVariable(tv.getName().toCharArray()); | |||
if (tvb!=null) return tvb; | |||
} | |||
if (tvBinding==null) { | |||
Binding declaringElement = null; | |||
// this will cause an infinite loop or NPE... not required yet luckily. | |||
// if (tVar.getDeclaringElement() instanceof Member) { | |||
// declaringElement = makeMethodBinding((ResolvedMember)tVar.getDeclaringElement()); | |||
// } else { | |||
// declaringElement = makeTypeBinding((UnresolvedType)tVar.getDeclaringElement()); | |||
// } | |||
tvBinding = new TypeVariableBinding(tv.getName().toCharArray(),declaringElement,tv.getRank()); | |||
typeVariableToTypeBinding.put(tv.getName(),tvBinding); | |||
tvBinding.superclass=(ReferenceBinding)makeTypeBinding(tv.getUpperBound()); | |||
tvBinding.firstBound=tvBinding.superclass; // FIXME asc is this correct? possibly it could be first superinterface | |||
if (tv.getAdditionalInterfaceBounds()==null) { | |||
tvBinding.superInterfaces=TypeVariableBinding.NoSuperInterfaces; | |||
} else { | |||
TypeBinding tbs[] = makeTypeBindings(tv.getAdditionalInterfaceBounds()); | |||
ReferenceBinding[] rbs= new ReferenceBinding[tbs.length]; | |||
for (int i = 0; i < tbs.length; i++) { | |||
rbs[i] = (ReferenceBinding)tbs[i]; | |||
} | |||
tvBinding.superInterfaces=rbs; | |||
} | |||
} | |||
return tvBinding; | |||
} | |||
public MethodBinding makeMethodBindingForCall(Member member) { | |||
return new MethodBinding(member.getCallsiteModifiers(), |
@@ -14,5 +14,6 @@ | |||
<classpathentry kind="lib" path="/lib/ant/lib/ant-launcher.jar"/> | |||
<classpathentry kind="src" path="testsrc"/> | |||
<classpathentry kind="var" path="JAVA_HOME/lib/tools.jar"/> | |||
<classpathentry combineaccessrules="false" kind="src" path="/weaver"/> | |||
<classpathentry kind="output" path="bin"/> | |||
</classpath> |
@@ -0,0 +1,6 @@ | |||
class C { | |||
} | |||
aspect X { | |||
<T> void C.m(T t) {} | |||
} |
@@ -0,0 +1,12 @@ | |||
class C {} | |||
interface I {} | |||
aspect X { | |||
<T extends Number> void C.m0(T t) {} // L7 | |||
<Q extends I> void C.m1(Q q) {} // L9 | |||
<R extends Number,I> void C.m2(R r) {} // L11 | |||
} |
@@ -0,0 +1,10 @@ | |||
class C {} | |||
interface I {} | |||
aspect X { | |||
<T extends Number,Q extends I> void C.m0(T t,Q q) {} // L7 | |||
<A,B,C> List<A> C.m1(B b,Collection<C> cs) {} // L9 | |||
} |
@@ -1,6 +1,7 @@ | |||
import java.util.*; | |||
public aspect Bar { | |||
private List<String> Foo.l; | |||
@@ -47,6 +47,7 @@ public class AllTestsAspectJ150 { | |||
suite.addTest(SuppressedWarnings.suite()); | |||
suite.addTest(DeclareAnnotationTests.suite()); | |||
suite.addTest(GenericsTests.suite()); | |||
suite.addTest(GenericITDsDesign.suite()); | |||
suite.addTest(AtAjSyntaxTests.suite()); | |||
suite.addTest(AtAjMisuseTests.suite()); | |||
suite.addTest(AtAjLTWTests.suite()); |
@@ -0,0 +1,167 @@ | |||
package org.aspectj.systemtest.ajc150; | |||
import java.io.File; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import junit.framework.Test; | |||
import org.aspectj.apache.bcel.classfile.Attribute; | |||
import org.aspectj.apache.bcel.classfile.JavaClass; | |||
import org.aspectj.apache.bcel.classfile.Signature; | |||
import org.aspectj.apache.bcel.util.ClassPath; | |||
import org.aspectj.apache.bcel.util.SyntheticRepository; | |||
import org.aspectj.testing.XMLBasedAjcTestCase; | |||
import org.aspectj.tools.ajc.Ajc; | |||
import org.aspectj.weaver.CrosscuttingMembers; | |||
import org.aspectj.weaver.ReferenceType; | |||
import org.aspectj.weaver.ResolvedMember; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.ResolvedTypeMunger; | |||
import org.aspectj.weaver.TypeVariable; | |||
import org.aspectj.weaver.TypeVariableReference; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.bcel.BcelTypeMunger; | |||
import org.aspectj.weaver.bcel.BcelWorld; | |||
public class GenericITDsDesign extends XMLBasedAjcTestCase { | |||
private World recentWorld; | |||
public static Test suite() { | |||
return XMLBasedAjcTestCase.loadSuite(GenericITDsDesign.class); | |||
} | |||
protected File getSpecFile() { | |||
return new File("../tests/src/org/aspectj/systemtest/ajc150/ajc150.xml"); | |||
} | |||
public static Signature getClassSignature(Ajc ajc,String classname) { | |||
try { | |||
ClassPath cp = | |||
new ClassPath(ajc.getSandboxDirectory() + File.pathSeparator + System.getProperty("java.class.path")); | |||
SyntheticRepository sRepos = SyntheticRepository.getInstance(cp); | |||
JavaClass clazz = sRepos.loadClass(classname); | |||
Signature sigAttr = null; | |||
Attribute[] attrs = clazz.getAttributes(); | |||
for (int i = 0; i < attrs.length; i++) { | |||
Attribute attribute = attrs[i]; | |||
if (attribute.getName().equals("Signature")) sigAttr = (Signature)attribute; | |||
} | |||
return sigAttr; | |||
} catch (ClassNotFoundException e) { | |||
fail("Couldn't find class "+classname+" in the sandbox directory."); | |||
} | |||
return null; | |||
} | |||
// Check the signature attribute on a class is correct | |||
public static void verifyClassSignature(Ajc ajc,String classname,String sig) { | |||
Signature sigAttr = getClassSignature(ajc,classname); | |||
assertTrue("Failed to find signature attribute for class "+classname,sigAttr!=null); | |||
assertTrue("Expected signature to be '"+sig+"' but was '"+sigAttr.getSignature()+"'", | |||
sigAttr.getSignature().equals(sig)); | |||
} | |||
public List /*BcelTypeMunger*/ getTypeMunger(String classname) { | |||
ClassPath cp = | |||
new ClassPath(ajc.getSandboxDirectory() + File.pathSeparator + | |||
System.getProperty("java.class.path")); | |||
recentWorld = new BcelWorld(cp.toString()); | |||
ReferenceType resolvedType = (ReferenceType)recentWorld.resolve(classname); | |||
CrosscuttingMembers cmembers = resolvedType.collectCrosscuttingMembers(); | |||
List tmungers = cmembers.getTypeMungers(); | |||
return tmungers; | |||
} | |||
private BcelTypeMunger getMungerFromLine(String classname,int linenumber) { | |||
List allMungers = getTypeMunger(classname); | |||
for (Iterator iter = allMungers.iterator(); iter.hasNext();) { | |||
BcelTypeMunger element = (BcelTypeMunger) iter.next(); | |||
if (element.getMunger().getSourceLocation().getLine()==linenumber) return element; | |||
} | |||
for (Iterator iter = allMungers.iterator(); iter.hasNext();) { | |||
BcelTypeMunger element = (BcelTypeMunger) iter.next(); | |||
System.err.println("Line: "+element.getMunger().getSourceLocation().getLine()+" > "+element); | |||
} | |||
fail("Couldn't find a type munger from line "+linenumber+" in class "+classname); | |||
return null; | |||
} | |||
/* | |||
test plan: | |||
1. Serializing and recovering 'default bounds' type variable info: | |||
a. methods | |||
b. fields | |||
c. ctors | |||
2. Serializing and recovering 'extends' with a class bounded type variable info: | |||
a. methods | |||
b. fields | |||
c. ctors | |||
3. Serializing and recovering 'extends' with an interface bounded type variable info: | |||
a. methods | |||
b. fields | |||
c. ctors | |||
4. Multiple interface bounds | |||
a. methods | |||
b. fields | |||
c. ctors | |||
5. wildcard bounds '? extends/? super' | |||
a. methods | |||
b. fields | |||
c. ctors | |||
6. using type variables in an ITD from the containing aspect, no bounds | |||
a. methods | |||
b. fields | |||
c. ctors | |||
*/ | |||
// Verify: a) After storing it in a class file and recovering it (through deserialization), we can see the type | |||
// variable and that the parameter refers to the type variable. | |||
public void testDesignA() { | |||
runTest("generic itds - design A"); | |||
BcelTypeMunger theBcelMunger = getMungerFromLine("X",5); | |||
ResolvedType typeC = recentWorld.resolve("C"); | |||
ResolvedTypeMunger rtMunger = theBcelMunger.getMunger(); | |||
ResolvedMember theMember = rtMunger.getSignature(); | |||
// Let's check all parts of the member | |||
assertTrue("Declaring type should be C: "+theMember, | |||
theMember.getDeclaringType().equals(typeC)); | |||
TypeVariable tVar = theMember.getTypeVariables()[0]; | |||
TypeVariableReference tvrt = (TypeVariableReference)theMember.getParameterTypes()[0]; | |||
theMember.resolve(recentWorld); // resolution will join the type variables together (i.e. make them refer to the same instance) | |||
tVar = theMember.getTypeVariables()[0]; | |||
tvrt = (TypeVariableReference)theMember.getParameterTypes()[0]; | |||
assertTrue("Post resolution, the type variable in the parameter should be identical to the type variable declared on the member", | |||
tVar==tvrt.getTypeVariable()); | |||
} | |||
// Verify: bounds are preserved and accessible after serialization | |||
public void xtestDesignB() { | |||
runTest("generic itds - design B"); | |||
BcelTypeMunger theBcelMunger = getMungerFromLine("X",7); | |||
} | |||
// Verify: a) multiple type variables work. | |||
// b) type variables below the 'top level' (e.g. List<A>) are preserved. | |||
public void xtestDesignC() { | |||
runTest("generic itds - design B"); | |||
BcelTypeMunger theBcelMunger = getMungerFromLine("X",7); | |||
} | |||
/* | |||
* broken stuff: | |||
* | |||
* When generic signatures are unpacked from members, the typevariables attached to the bcelmethod/field won't | |||
* be the same instances as those held in the TypeVariableReferenceTypes for anything that occurs in the | |||
* return type or parameterset - we should perhaps fix that up. | |||
*/ | |||
} |
@@ -5024,4 +5024,19 @@ | |||
</stdout> | |||
</run> | |||
</ajc-test> | |||
<!-- generic ITDs --> | |||
<ajc-test dir="java5/generics/itds/design" title="generic itds - design A"> | |||
<compile files="DesignA.java" options="-1.5"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds/design" title="generic itds - design B"> | |||
<compile files="DesignB.java" options="-1.5"/> | |||
</ajc-test> | |||
<ajc-test dir="java5/generics/itds/design" title="generic itds - design C"> | |||
<compile files="DesignC.java" options="-1.5"/> | |||
</ajc-test> | |||
</suite> |
@@ -663,7 +663,7 @@ public class AjdeInteractionTestbed extends TestCase { | |||
} | |||
public String getSourceCompatibilityLevel() { | |||
return null; | |||
return "1.5"; | |||
} | |||
public Set getWarnings() { |
@@ -289,12 +289,14 @@ public class MultiProjectIncrementalTests extends AjdeInteractionTestbed { | |||
} | |||
/* public void testPr111779() { | |||
super.VERBOSE=true; | |||
initialiseProject("PR111779"); | |||
build("PR111779"); | |||
alter("PR111779","inc1"); | |||
build("PR111779"); | |||
} | |||
*/ | |||
// other possible tests: | |||
// - memory usage (freemem calls?) |
@@ -202,13 +202,17 @@ public class JoinPointSignature implements ResolvedMember { | |||
return realMember.parameterizedWith(typeParameters, newDeclaringType, isParameterized); | |||
} | |||
public void setTypeVariables(UnresolvedType[] types) { | |||
public void setTypeVariables(TypeVariable[] types) { | |||
realMember.setTypeVariables(types); | |||
} | |||
public UnresolvedType[] getTypeVariables() { | |||
public TypeVariable[] getTypeVariables() { | |||
return realMember.getTypeVariables(); | |||
} | |||
public TypeVariable getTypeVariableNamed(String name) { | |||
return realMember.getTypeVariableNamed(name); | |||
} | |||
public ResolvedMember getErasure() { | |||
throw new UnsupportedOperationException("Adrian doesn't think you should be asking for the erasure of one of these..."); |
@@ -113,9 +113,9 @@ public interface ResolvedMember extends Member, AnnotatedElement, TypeVariableDe | |||
UnresolvedType[] typeParameters, ResolvedType newDeclaringType, | |||
boolean isParameterized); | |||
public void setTypeVariables(UnresolvedType[] types); | |||
public void setTypeVariables(TypeVariable[] types); | |||
public UnresolvedType[] getTypeVariables(); | |||
public TypeVariable[] getTypeVariables(); | |||
/** | |||
* If this member is defined by a parameterized super-type, return the erasure |
@@ -50,7 +50,7 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
private boolean isAjSynthetic = true; | |||
// generic methods have type variables | |||
private UnresolvedType[] typeVariables; | |||
private TypeVariable[] typeVariables; | |||
// these three fields hold the source location of this member | |||
protected int start, end; | |||
@@ -385,9 +385,10 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
int tvcount = s.readInt(); | |||
if (tvcount!=0) { | |||
m.typeVariables = new UnresolvedType[tvcount]; | |||
m.typeVariables = new TypeVariable[tvcount]; | |||
for (int i=0;i<tvcount;i++) { | |||
m.typeVariables[i]=UnresolvedType.read(s); | |||
m.typeVariables[i]=TypeVariable.read(s); | |||
m.typeVariables[i].setDeclaringElement(m); | |||
} | |||
} | |||
} | |||
@@ -407,30 +408,37 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
public ResolvedMember resolve(World world) { | |||
// 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();) { | |||
UnresolvedType element = (UnresolvedType) iter.next(); | |||
r.add(world.resolve(element)); | |||
} | |||
annotationTypes = r; | |||
} | |||
declaringType = declaringType.resolve(world); | |||
if (declaringType.isRawType()) declaringType = ((ReferenceType)declaringType).getGenericType(); | |||
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); | |||
try { | |||
if (typeVariables!=null && typeVariables.length>0) { | |||
for (int i = 0; i < typeVariables.length; i++) { | |||
typeVariables[i] = typeVariables[i].resolve(world); | |||
} | |||
} | |||
world.setTypeVariableLookupScope(this); | |||
if (annotationTypes!=null) { | |||
Set r = new HashSet(); | |||
for (Iterator iter = annotationTypes.iterator(); iter.hasNext();) { | |||
UnresolvedType element = (UnresolvedType) iter.next(); | |||
r.add(world.resolve(element)); | |||
} | |||
annotationTypes = r; | |||
} | |||
declaringType = declaringType.resolve(world); | |||
if (declaringType.isRawType()) declaringType = ((ReferenceType)declaringType).getGenericType(); | |||
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); | |||
parameterTypes[i] = parameterTypes[i].resolve(world); | |||
} | |||
} | |||
returnType = returnType.resolve(world); | |||
} finally { | |||
world.setTypeVariableLookupScope(null); | |||
} | |||
returnType = returnType.resolve(world);return this; | |||
return this; | |||
} | |||
public ISourceContext getSourceContext(World world) { | |||
@@ -567,11 +575,11 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
} | |||
public void setTypeVariables(UnresolvedType[] types) { | |||
typeVariables = types; | |||
public void setTypeVariables(TypeVariable[] tvars) { | |||
typeVariables = tvars; | |||
} | |||
public UnresolvedType[] getTypeVariables() { | |||
public TypeVariable[] getTypeVariables() { | |||
return typeVariables; | |||
} | |||
@@ -758,5 +766,20 @@ public class ResolvedMemberImpl extends MemberImpl implements IHasPosition, Anno | |||
} | |||
return buf.toString(); | |||
} | |||
public TypeVariable getTypeVariableNamed(String name) { | |||
// Check locally... | |||
if (typeVariables!=null) { | |||
for (int i = 0; i < typeVariables.length; i++) { | |||
if (typeVariables[i].getName().equals(name)) return typeVariables[i]; | |||
} | |||
} | |||
// Bugger, check the declaring type! | |||
return declaringType.getTypeVariableNamed(name); | |||
// Do generic aspects with ITDs that share type variables with the aspect and the target type and have their own tvars cause this to be messier? | |||
} | |||
} | |||
@@ -47,8 +47,6 @@ public abstract class ResolvedTypeMunger { | |||
// might need serializing the class file for binary weaving. | |||
protected List /*String*/ typeVariableToGenericTypeVariableIndex; | |||
public static transient boolean persistSourceLocation = true; | |||
private Set /* resolvedMembers */ superMethodsCalled = Collections.EMPTY_SET; | |||
private ISourceLocation location; // Lost during serialize/deserialize ! | |||
@@ -138,6 +136,7 @@ public abstract class ResolvedTypeMunger { | |||
Set ret = new HashSet(); | |||
int n = s.readInt(); | |||
if (n<0) throw new BCException("Problem deserializing type munger"); | |||
for (int i=0; i < n; i++) { | |||
ret.add(ResolvedMemberImpl.readResolvedMember(s, null)); | |||
} | |||
@@ -146,7 +145,7 @@ public abstract class ResolvedTypeMunger { | |||
protected void writeSuperMethodsCalled(DataOutputStream s) throws IOException { | |||
if (superMethodsCalled == null) { | |||
if (superMethodsCalled == null || superMethodsCalled.size()==0) { | |||
s.writeInt(0); | |||
return; | |||
} | |||
@@ -163,7 +162,6 @@ public abstract class ResolvedTypeMunger { | |||
} | |||
protected static ISourceLocation readSourceLocation(VersionedDataInputStream s) throws IOException { | |||
if (!persistSourceLocation) return null; | |||
// Location persistence for type mungers was added after 1.2.1 was shipped... | |||
if (s.getMajorVersion()<AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) return null; | |||
SourceLocation ret = null; | |||
@@ -196,7 +194,6 @@ public abstract class ResolvedTypeMunger { | |||
} | |||
protected void writeSourceLocation(DataOutputStream s) throws IOException { | |||
if (!persistSourceLocation) return; | |||
ObjectOutputStream oos = new ObjectOutputStream(s); | |||
// oos.writeObject(location); | |||
oos.writeObject(new Boolean(location!=null)); |
@@ -11,6 +11,8 @@ | |||
* ******************************************************************/ | |||
package org.aspectj.weaver; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.util.HashSet; | |||
import java.util.Set; | |||
@@ -106,10 +108,10 @@ public class TypeVariable { | |||
/** | |||
* resolve all the bounds of this type variable | |||
*/ | |||
public void resolve(World inSomeWorld) { | |||
if (beingResolved) { return; } // avoid spiral of death | |||
public TypeVariable resolve(World inSomeWorld) { | |||
if (beingResolved) { return this; } // avoid spiral of death | |||
beingResolved = true; | |||
if (isResolved) return; | |||
if (isResolved) return this; | |||
TypeVariable resolvedTVar = null; | |||
@@ -128,13 +130,14 @@ public class TypeVariable { | |||
} else { | |||
// look for type variable on method... | |||
ResolvedMember declaring = (ResolvedMember) declaringElement; | |||
UnresolvedType[] tvrts = declaring.getTypeVariables(); | |||
TypeVariable[] tvrts = declaring.getTypeVariables(); | |||
for (int i = 0; i < tvrts.length; i++) { | |||
if (tvrts[i].isTypeVariableReference()) { | |||
TypeVariableReferenceType tvrt = (TypeVariableReferenceType) tvrts[i].resolve(inSomeWorld); | |||
TypeVariable tv = tvrt.getTypeVariable(); | |||
if (tv.getName().equals(getName())) resolvedTVar = tv; | |||
} | |||
if (tvrts[i].getName().equals(getName())) resolvedTVar = tvrts[i]; | |||
// if (tvrts[i].isTypeVariableReference()) { | |||
// TypeVariableReferenceType tvrt = (TypeVariableReferenceType) tvrts[i].resolve(inSomeWorld); | |||
// TypeVariable tv = tvrt.getTypeVariable(); | |||
// if (tv.getName().equals(getName())) resolvedTVar = tv; | |||
// } | |||
} | |||
} | |||
@@ -155,12 +158,14 @@ public class TypeVariable { | |||
upperBound = upperBound.resolve(inSomeWorld); | |||
if (lowerBound != null) lowerBound = lowerBound.resolve(inSomeWorld); | |||
for (int i = 0; i < additionalInterfaceBounds.length; i++) { | |||
additionalInterfaceBounds[i] = additionalInterfaceBounds[i].resolve(inSomeWorld); | |||
if (additionalInterfaceBounds!=null) { | |||
for (int i = 0; i < additionalInterfaceBounds.length; i++) { | |||
additionalInterfaceBounds[i] = additionalInterfaceBounds[i].resolve(inSomeWorld); | |||
} | |||
} | |||
isResolved = true; | |||
beingResolved = false; | |||
return this; | |||
} | |||
/** | |||
@@ -320,4 +325,37 @@ public class TypeVariable { | |||
return declaringElementKind; | |||
} | |||
public void write(DataOutputStream s) throws IOException { | |||
// name, upperbound, additionalInterfaceBounds, lowerbound | |||
s.writeUTF(name); | |||
upperBound.write(s); | |||
if (additionalInterfaceBounds==null || additionalInterfaceBounds.length==0) { | |||
s.writeInt(0); | |||
} else { | |||
s.writeInt(additionalInterfaceBounds.length); | |||
for (int i = 0; i < additionalInterfaceBounds.length; i++) { | |||
UnresolvedType ibound = additionalInterfaceBounds[i]; | |||
ibound.write(s); | |||
} | |||
} | |||
} | |||
public static TypeVariable read(VersionedDataInputStream s) throws IOException { | |||
//if (s.getMajorVersion()>=AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) { | |||
String name = s.readUTF(); | |||
UnresolvedType ubound = UnresolvedType.read(s); | |||
int iboundcount = s.readInt(); | |||
UnresolvedType[] ibounds = null; | |||
if (iboundcount>0) { | |||
ibounds = new UnresolvedType[iboundcount]; | |||
for (int i=0; i<iboundcount; i++) { | |||
ibounds[i] = UnresolvedType.read(s); | |||
} | |||
} | |||
TypeVariable newVariable = new TypeVariable(name,ubound,ibounds); | |||
return newVariable; | |||
} | |||
} |
@@ -19,5 +19,5 @@ package org.aspectj.weaver; | |||
* the declaring element | |||
*/ | |||
public interface TypeVariableDeclaringElement { | |||
public TypeVariable getTypeVariableNamed(String name); | |||
} |
@@ -22,6 +22,12 @@ public class TypeVariableReferenceType extends BoundedReferenceType implements T | |||
private TypeVariable typeVariable; | |||
private boolean resolvedIfBounds = false; | |||
// If 'fixedUp' then the type variable in here is a reference to the real one that may | |||
// exist either on a member or a type. Not fixedUp means that we unpacked a generic | |||
// signature and weren't able to fix it up during resolution (didn't quite know enough | |||
// at the right time). Wonder if we can fix it up late? | |||
boolean fixedUp = false; | |||
public TypeVariableReferenceType( | |||
TypeVariable aTypeVariable, | |||
World aWorld) { | |||
@@ -62,6 +68,7 @@ public class TypeVariableReferenceType extends BoundedReferenceType implements T | |||
} | |||
public TypeVariable getTypeVariable() { | |||
// if (!fixedUp) throw new BCException("ARGH"); // SAUSAGES - fix it up now? | |||
return typeVariable; | |||
} | |||
@@ -104,17 +111,17 @@ public class TypeVariableReferenceType extends BoundedReferenceType implements T | |||
public void write(DataOutputStream s) throws IOException { | |||
super.write(s); | |||
TypeVariableDeclaringElement tvde = typeVariable.getDeclaringElement(); | |||
if (tvde == null) { | |||
s.writeInt(TypeVariable.UNKNOWN); | |||
} else { | |||
s.writeInt(typeVariable.getDeclaringElementKind()); | |||
if (typeVariable.getDeclaringElementKind() == TypeVariable.TYPE) { | |||
((UnresolvedType)tvde).write(s); | |||
} else if (typeVariable.getDeclaringElementKind() == TypeVariable.METHOD){ | |||
// it's a method | |||
((ResolvedMember)tvde).write(s); | |||
} | |||
} | |||
// TypeVariableDeclaringElement tvde = typeVariable.getDeclaringElement(); | |||
// if (tvde == null) { | |||
// s.writeInt(TypeVariable.UNKNOWN); | |||
// } else { | |||
// s.writeInt(typeVariable.getDeclaringElementKind()); | |||
// if (typeVariable.getDeclaringElementKind() == TypeVariable.TYPE) { | |||
// ((UnresolvedType)tvde).write(s); | |||
// } else if (typeVariable.getDeclaringElementKind() == TypeVariable.METHOD){ | |||
// // it's a method | |||
// ((ResolvedMember)tvde).write(s); | |||
// } | |||
// } | |||
} | |||
} |
@@ -779,10 +779,6 @@ public class UnresolvedType implements TypeVariableDeclaringElement { | |||
return ResolvedType.MISSING; | |||
} else { | |||
UnresolvedType ret = UnresolvedType.forSignature(sig); | |||
// ugh, this is horrid, we shouldn't know about this subclass. | |||
if (ret instanceof UnresolvedTypeVariableReferenceType) { | |||
UnresolvedTypeVariableReferenceType.readDeclaringElement(s, (UnresolvedTypeVariableReferenceType)ret); | |||
} | |||
return ret; | |||
} | |||
} | |||
@@ -883,5 +879,14 @@ public class UnresolvedType implements TypeVariableDeclaringElement { | |||
throw new RuntimeException("I dont know - you should ask a resolved version of me: "+this); | |||
} | |||
public TypeVariable getTypeVariableNamed(String name) { | |||
if (typeVariables==null || typeVariables.length==0) return null; | |||
for (int i = 0; i < typeVariables.length; i++) { | |||
TypeVariable aVar = typeVariables[i]; | |||
if (aVar.getName().equals(name)) return aVar; | |||
} | |||
return null; | |||
} | |||
} | |||
@@ -11,7 +11,6 @@ | |||
* ******************************************************************/ | |||
package org.aspectj.weaver; | |||
import java.io.DataInputStream; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
@@ -41,13 +40,56 @@ public class UnresolvedTypeVariableReferenceType extends UnresolvedType implemen | |||
} | |||
public ResolvedType resolve(World world) { | |||
if (typeVariable == null) { | |||
throw new BCException("Cannot resolve this type variable reference, the type variable has not been set!"); | |||
TypeVariableDeclaringElement typeVariableScope = world.getTypeVariableLookupScope(); | |||
TypeVariable resolvedTypeVariable = null; | |||
TypeVariableReferenceType tvrt = null; | |||
if (typeVariableScope == null) { | |||
// throw new BCException("There is no scope in which to lookup type variables!"); | |||
// SAUSAGES correct thing to do is go bang, but to limp along, lets cope with the scope missing | |||
resolvedTypeVariable = typeVariable.resolve(world); | |||
tvrt = new TypeVariableReferenceType(resolvedTypeVariable,world); | |||
} else { | |||
boolean foundOK = false; | |||
resolvedTypeVariable = typeVariableScope.getTypeVariableNamed(typeVariable.getName()); | |||
// SAUSAGES remove this when the shared type var stuff is sorted | |||
if (resolvedTypeVariable == null) { | |||
resolvedTypeVariable = typeVariable.resolve(world); | |||
} else { | |||
foundOK = true; | |||
} | |||
tvrt = new TypeVariableReferenceType(resolvedTypeVariable,world); | |||
tvrt.fixedUp = foundOK; | |||
} | |||
typeVariable.resolve(world); | |||
return new TypeVariableReferenceType(typeVariable,world); | |||
return tvrt; | |||
// // SAUSAGES should really be resolved in a scope, or you won't get the type variable you really want! | |||
// //throw new BCException("NO - UnresolvedTypeVariableReferenceTypes must be resolved in a type variable scope"); | |||
// 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); | |||
} | |||
// public ResolvedType resolve(World world,TypeVariableDeclaringElement tvde) { | |||
// if (typeVariable == null) { | |||
// throw new BCException("Cannot resolve this type variable reference, the type variable has not been set!"); | |||
// } | |||
// | |||
// // SAUSAGES temporary whilst the ITD logic gets sorted out | |||
// if (tvde == null) return new TypeVariableReferenceType(typeVariable.resolve(world),world); | |||
// | |||
// TypeVariable resolvedTypeVariable = tvde.getTypeVariableNamed(typeVariable.getName()); | |||
// if (resolvedTypeVariable == null) { | |||
// resolvedTypeVariable = typeVariable.resolve(world); | |||
// // SAUSAGES put this in once ITDs remember the complex shared type var stuff | |||
// // throw new BCException("Could not locate type variable '"+typeVariable.getName()+"' during resolution, scope was: "+tvde); | |||
// } | |||
// TypeVariableReferenceType tvrt = new TypeVariableReferenceType(resolvedTypeVariable,world); | |||
// tvrt.fixedUp = true; | |||
// return tvrt; | |||
// } | |||
public boolean isTypeVariableReference() { | |||
return true; | |||
} | |||
@@ -71,20 +113,8 @@ public class UnresolvedTypeVariableReferenceType extends UnresolvedType implemen | |||
public void write(DataOutputStream s) throws IOException { | |||
super.write(s); | |||
TypeVariableDeclaringElement tvde = typeVariable.getDeclaringElement(); | |||
if (tvde == null) { | |||
s.writeInt(TypeVariable.UNKNOWN); | |||
} else { | |||
s.writeInt(typeVariable.getDeclaringElementKind()); | |||
if (typeVariable.getDeclaringElementKind() == TypeVariable.TYPE) { | |||
((UnresolvedType)tvde).write(s); | |||
} else if (typeVariable.getDeclaringElementKind() == TypeVariable.METHOD){ | |||
// it's a method | |||
((ResolvedMember)tvde).write(s); | |||
} | |||
} | |||
} | |||
/* | |||
public static void readDeclaringElement(DataInputStream s, UnresolvedTypeVariableReferenceType utv) | |||
throws IOException { | |||
int kind = s.readInt(); | |||
@@ -97,5 +127,5 @@ public class UnresolvedTypeVariableReferenceType extends UnresolvedType implemen | |||
utv.typeVariable.setDeclaringElement(rm); | |||
} | |||
} | |||
*/ | |||
} |
@@ -45,6 +45,9 @@ public abstract class World implements Dump.INode { | |||
/** handler for cross-reference information produced during the weaving process */ | |||
private ICrossReferenceHandler xrefHandler = null; | |||
/** Currently 'active' scope in which to lookup (resolve) typevariable references */ | |||
private TypeVariableDeclaringElement typeVariableLookupScope; | |||
/** The heart of the world, a map from type signatures to resolved types */ | |||
protected TypeMap typeMap = new TypeMap(); // Signature to ResolvedType | |||
@@ -329,7 +332,7 @@ public abstract class World implements Dump.INode { | |||
// 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) { | |||
if (rawType.isSimpleType() && (anUnresolvedType.typeParameters==null || anUnresolvedType.typeParameters.length==0)) { | |||
rawType.world = this; | |||
return rawType; | |||
} | |||
@@ -546,6 +549,15 @@ public abstract class World implements Dump.INode { | |||
public ICrossReferenceHandler getCrossReferenceHandler() { | |||
return this.xrefHandler; | |||
} | |||
public void setTypeVariableLookupScope(TypeVariableDeclaringElement scope) { | |||
this.typeVariableLookupScope = scope; | |||
} | |||
public TypeVariableDeclaringElement getTypeVariableLookupScope() { | |||
return typeVariableLookupScope; | |||
} | |||
public List getDeclareParents() { | |||
return crosscuttingMembersSet.getDeclareParents(); |
@@ -106,15 +106,12 @@ public class BcelTypeMunger extends ConcreteTypeMunger { | |||
weaver.getLazyClassGen().getOrCreateWeaverStateInfo(weaver.getReweavableMode()); | |||
info.addConcreteMunger(this); | |||
} | |||
// Whilst type mungers aren't persisting their source locations, we add this relationship during | |||
// compilation time (see other reference to ResolvedTypeMunger.persist) | |||
if (ResolvedTypeMunger.persistSourceLocation) { | |||
if (changed && worthReporting) { | |||
if (munger.getKind().equals(ResolvedTypeMunger.Parent)) { | |||
AsmRelationshipProvider.getDefault().addRelationship(weaver.getLazyClassGen().getType(), munger,getAspectType()); | |||
} else { | |||
AsmRelationshipProvider.getDefault().addRelationship(weaver.getLazyClassGen().getType(), munger,getAspectType()); | |||
} | |||
if (changed && worthReporting) { | |||
if (munger.getKind().equals(ResolvedTypeMunger.Parent)) { | |||
AsmRelationshipProvider.getDefault().addRelationship(weaver.getLazyClassGen().getType(), munger,getAspectType()); | |||
} else { | |||
AsmRelationshipProvider.getDefault().addRelationship(weaver.getLazyClassGen().getType(), munger,getAspectType()); | |||
} | |||
} | |||
@@ -894,7 +891,7 @@ public class BcelTypeMunger extends ConcreteTypeMunger { | |||
boolean matchOK = true; | |||
for (int j = 0; j < memberParams.length && matchOK; j++){ | |||
UnresolvedType memberParam = memberParams[j]; | |||
UnresolvedType lookingForParam = lookingForParams[j].resolve(aspectType.getWorld()); | |||
UnresolvedType lookingForParam = lookingForParams[j].resolve(aspectType.getWorld()); | |||
if (lookingForParam.isTypeVariableReference()) lookingForParam = lookingForParam.getUpperBound(); | |||
if (!memberParam.equals(lookingForParam)){ | |||
matchOK=false; |