diff options
author | acolyer <acolyer> | 2005-04-20 19:24:30 +0000 |
---|---|---|
committer | acolyer <acolyer> | 2005-04-20 19:24:30 +0000 |
commit | 7a639d019a9b04b3eb7af97a7a2975cbbf72e0cf (patch) | |
tree | 8bd9464cb6c1df486ab5e84d301cf82bc11fbdcb | |
parent | 1e6fae862407f7c0b49321a6c452774f91f3cd04 (diff) | |
download | aspectj-7a639d019a9b04b3eb7af97a7a2975cbbf72e0cf.tar.gz aspectj-7a639d019a9b04b3eb7af97a7a2975cbbf72e0cf.zip |
this set of commits teaches the TypeX world about parameterized types. it handles passing of parameterized types into the weaver from Eclipse, and back out again. Fixes the ITD and parameterized types issue that shows up in the examples. Much more work to be done in this area of course before M3.
6 files changed, 180 insertions, 16 deletions
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 5aeedd62e..931c7db15 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 @@ -47,11 +47,13 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BaseTypes; import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding; 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.ParameterizedTypeBinding; 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.TypeVariableBinding; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; /** * @author Jim Hugunin @@ -165,6 +167,19 @@ public class EclipseFactory { TypeVariableBinding tvb = (TypeVariableBinding) binding; return TypeX.forName(getName(tvb.firstBound)); // XXX needs more investigation as to whether this is correct in all cases } + if (binding instanceof ParameterizedTypeBinding) { + ParameterizedTypeBinding ptb = (ParameterizedTypeBinding) binding; + String[] arguments = new String[ptb.arguments.length]; + for (int i = 0; i < arguments.length; i++) { + if (ptb.arguments[i] instanceof WildcardBinding) { + WildcardBinding wcb = (WildcardBinding) ptb.arguments[i]; + arguments[i] = getName(((TypeVariableBinding)wcb.typeVariable()).firstBound); + } else { + arguments[i] = getName(ptb.arguments[i]); + } + } + return TypeX.forParameterizedTypeNames(getName(binding), arguments); + } return TypeX.forName(getName(binding)); } @@ -307,21 +322,32 @@ public class EclipseFactory { typeX = typeX.getComponentType(); } return lookupEnvironment.createArrayType(makeTypeBinding(typeX), dim); + } else if (typeX.isParameterized()){ + TypeX[] typeParameters = typeX.getTypeParameters(); + ReferenceBinding baseTypeBinding = lookupBinding(typeX.getBaseName()); + ReferenceBinding[] argumentBindings = new ReferenceBinding[typeParameters.length]; + for (int i = 0; i < argumentBindings.length; i++) { + argumentBindings[i] = lookupBinding(typeParameters[i].getName()); + } + ParameterizedTypeBinding ptb = + lookupEnvironment.createParameterizedType(baseTypeBinding,argumentBindings,baseTypeBinding.enclosingType()); + return ptb; } else { - String n = typeX.getName(); - char[][] name = CharOperation.splitOn('.', n.toCharArray()); - ReferenceBinding rb = lookupEnvironment.getType(name); - // XXX We do this because the pertypewithin aspectOf(Class) generated method needs it. Without this - // we don't get a 'rawtype' as the argument type for a messagesend to aspectOf() and this leads to - // a compile error if some client class calls aspectOf(A.class) or similar as it says Class<A> isn't - // compatible with Class<T> - if (n.equals("java.lang.Class")) - rb = lookupEnvironment.createRawType(rb,rb.enclosingType()); - return rb; + return lookupBinding(typeX.getName()); } } - + private ReferenceBinding lookupBinding(String sname) { + char[][] name = CharOperation.splitOn('.', sname.toCharArray()); + ReferenceBinding rb = lookupEnvironment.getType(name); + // XXX We do this because the pertypewithin aspectOf(Class) generated method needs it. Without this + // we don't get a 'rawtype' as the argument type for a messagesend to aspectOf() and this leads to + // a compile error if some client class calls aspectOf(A.class) or similar as it says Class<A> isn't + // compatible with Class<T> + if (sname.equals("java.lang.Class")) + rb = lookupEnvironment.createRawType(rb,rb.enclosingType()); + return rb; + } public TypeBinding[] makeTypeBindings(TypeX[] types) { int len = types.length; diff --git a/tests/java5/generics/ITDReturningParameterizedType.aj b/tests/java5/generics/ITDReturningParameterizedType.aj index aa5f3e978..4495e8042 100644 --- a/tests/java5/generics/ITDReturningParameterizedType.aj +++ b/tests/java5/generics/ITDReturningParameterizedType.aj @@ -2,6 +2,8 @@ import java.util.*; public aspect ITDReturningParameterizedType { + private List<String> myStrings = new ArrayList<String>(); + private List<String> C.strings = new ArrayList<String>(); public List<String> C.getStrings() { diff --git a/tests/src/org/aspectj/systemtest/ajc150/AllTestsAspectJ150.java b/tests/src/org/aspectj/systemtest/ajc150/AllTestsAspectJ150.java index 52e285c83..1f0ad25f9 100644 --- a/tests/src/org/aspectj/systemtest/ajc150/AllTestsAspectJ150.java +++ b/tests/src/org/aspectj/systemtest/ajc150/AllTestsAspectJ150.java @@ -42,7 +42,7 @@ public class AllTestsAspectJ150 { suite.addTest(SuppressedWarnings.suite()); suite.addTest(DeclareAnnotationTests.suite()); - + suite.addTest(GenericsTests.suite()); suite.addTest(AtAjSyntaxTests.suite()); //$JUnit-END$ return suite; diff --git a/weaver/src/org/aspectj/weaver/TypeX.java b/weaver/src/org/aspectj/weaver/TypeX.java index 2b046a370..cd9e352f3 100644 --- a/weaver/src/org/aspectj/weaver/TypeX.java +++ b/weaver/src/org/aspectj/weaver/TypeX.java @@ -23,6 +23,11 @@ public class TypeX implements AnnotatedElement { * This is the bytecode string representation of this Type */ protected String signature; + + /** + * If this is a parameterized type, these are its parameters + */ + protected TypeX[] typeParameters; /** * @param signature the bytecode string representation of this Type @@ -101,7 +106,29 @@ public class TypeX implements AnnotatedElement { } return ret; } - + + /** + * Makes a parameterized type with the given name + * and parameterized type names. + */ + public static TypeX forParameterizedTypeNames(String name, String[] paramTypeNames) { + TypeX ret = TypeX.forName(name); + ret.typeParameters = new TypeX[paramTypeNames.length]; + for (int i = 0; i < paramTypeNames.length; i++) { + ret.typeParameters[i] = TypeX.forName(paramTypeNames[i]); + } + // sig for e.g. List<String> is Ljava/util/List<Ljava/lang/String;>; + StringBuffer sigAddition = new StringBuffer(); + sigAddition.append("<"); + for (int i = 0; i < ret.typeParameters.length; i++) { + sigAddition.append(ret.typeParameters[i].signature); + sigAddition.append(">"); + sigAddition.append(";"); + } + ret.signature = ret.signature + sigAddition.toString(); + return ret; + } + /** * Creates a new type array with a fresh type appended to the end. * @@ -205,6 +232,15 @@ public class TypeX implements AnnotatedElement { public String getName() { return signatureToName(signature); } + + public String getBaseName() { + String name = getName(); + if (isParameterized()) { + return name.substring(0,name.indexOf("<")); + } else { + return name; + } + } /** * Returns an array of strings representing the java langauge names of @@ -250,6 +286,14 @@ public class TypeX implements AnnotatedElement { public final boolean isArray() { return signature.startsWith("["); } + + /** + * Determines if this represents a parameterized type. + */ + public final boolean isParameterized() { + return signature.indexOf("<") != -1; + //(typeParameters != null) && (typeParameters.length > 0); + } /** * Returns a TypeX object representing the effective outermost enclosing type @@ -603,7 +647,48 @@ public class TypeX implements AnnotatedElement { case 'I': return "int"; case 'J': return "long"; case 'L': - return signature.substring(1, signature.length() - 1).replace('/', '.'); + String name = signature.substring(1, signature.length() - 1).replace('/', '.'); + if (name.indexOf("<") == -1) return name; + // signature for parameterized types is e.g. + // List<String> -> Ljava/util/List<Ljava/lang/String;>; + // Map<String,List<Integer>> -> Ljava/util/Map<java/lang/String;Ljava/util/List<Ljava/lang/Integer;>;>; + StringBuffer nameBuff = new StringBuffer(); + boolean justSeenLeftArrowChar = false; + boolean justSeenSemiColon= false; + int paramNestLevel = 0; + for (int i = 0 ; i < name.length(); i++) { + char c = name.charAt(i); + switch (c) { + case '<' : + justSeenLeftArrowChar = true; + paramNestLevel++; + nameBuff.append(c); + break; + case ';' : + justSeenSemiColon = true; + break; + case '>' : + paramNestLevel--; + nameBuff.append(c); + break; + case 'L' : + if (justSeenLeftArrowChar) { + justSeenLeftArrowChar = false; + break; + } + if (justSeenSemiColon) { + nameBuff.append(","); + } else { + nameBuff.append("L"); + } + break; + default: + justSeenSemiColon = false; + justSeenLeftArrowChar = false; + nameBuff.append(c); + } + } + return nameBuff.toString(); case 'S': return "short"; case 'V': return "void"; case 'Z': return "boolean"; @@ -631,7 +716,27 @@ public class TypeX implements AnnotatedElement { // 1) If it is already an array type, do not mess with it. if (name.charAt(0)=='[' && name.charAt(name.length()-1)==';') return name; - else return "L" + name.replace('.', '/') + ";"; + else { + if (name.indexOf("<") == -1) { + // not parameterised + return "L" + name.replace('.', '/') + ";"; + } else { + StringBuffer nameBuff = new StringBuffer(); + nameBuff.append("L"); + for (int i = 0; i < name.length(); i++) { + char c = name.charAt(i); + switch (c) { + case '.' : nameBuff.append('/'); break; + case '<' : nameBuff.append("<L"); break; + case '>' : nameBuff.append(";>"); break; + case ',' : nameBuff.append(";L"); break; + default: nameBuff.append(c); + } + } + nameBuff.append(";"); + return nameBuff.toString(); + } + } } else throw new BCException("Bad type name: " + name); @@ -721,6 +826,10 @@ public class TypeX implements AnnotatedElement { } } + public TypeX[] getTypeParameters() { + return typeParameters == null ? new TypeX[0] : typeParameters; + } + /** * Doesn't include the package */ diff --git a/weaver/src/org/aspectj/weaver/World.java b/weaver/src/org/aspectj/weaver/World.java index ca7e0a211..04ec34815 100644 --- a/weaver/src/org/aspectj/weaver/World.java +++ b/weaver/src/org/aspectj/weaver/World.java @@ -137,6 +137,11 @@ public abstract class World implements Dump.INode { dumpState_cantFindTypeExceptions.add(new RuntimeException("Can't find type "+ty.getName())); } } + if (ty.isParameterized()) { + for (int i = 0; i < ty.typeParameters.length; i++) { + ty.typeParameters[i] = resolve(ty.typeParameters[i],allowMissing); + } + } //System.out.println("ret: " + ret); typeMap.put(signature, ret); return ret; @@ -147,7 +152,14 @@ public abstract class World implements Dump.INode { return resolve(TypeX.forName(name)); } protected final ResolvedTypeX resolveObjectType(TypeX ty) { - ResolvedTypeX.Name name = new ResolvedTypeX.Name(ty.getSignature(), this); + String signature = ty.getSignature(); + if (signature.indexOf("<") != -1) { + // extract the raw type... + // XXX - might need to do more in the future to propagate full parameterized info... + signature = signature.substring(0,signature.indexOf("<")); + } + + ResolvedTypeX.Name name = new ResolvedTypeX.Name(signature, this); ResolvedTypeX.ConcreteName concreteName = resolveObjectType(name); if (concreteName == null) return ResolvedTypeX.MISSING; name.setDelegate(concreteName); diff --git a/weaver/testsrc/org/aspectj/weaver/TypeXTestCase.java b/weaver/testsrc/org/aspectj/weaver/TypeXTestCase.java index 3219b2f15..1ba812845 100644 --- a/weaver/testsrc/org/aspectj/weaver/TypeXTestCase.java +++ b/weaver/testsrc/org/aspectj/weaver/TypeXTestCase.java @@ -61,6 +61,21 @@ public class TypeXTestCase extends TestCase { assertEquals(t.getOutermostType(), TypeX.forName("java.util.Map")); assertEquals(TypeX.forName("java.util.Map").getOutermostType(), TypeX.forName("java.util.Map")); } + + public void testNameAndSigWithParameters() { + TypeX t = TypeX.forName("java.util.List<java.lang.String>"); + assertEquals(t.getName(),"java.util.List<java.lang.String>"); + assertEquals(t.getSignature(),"Ljava/util/List<Ljava/lang/String;>;"); + t = new TypeX("Ljava/util/List<Ljava/lang/String;>;"); + assertEquals(t.getName(),"java.util.List<java.lang.String>"); + assertEquals(t.getSignature(),"Ljava/util/List<Ljava/lang/String;>;"); + t = TypeX.forName("java.util.Map<java.util.String,java.util.List<java.lang.Integer>>"); + assertEquals(t.getName(),"java.util.Map<java.util.String,java.util.List<java.lang.Integer>>"); + assertEquals(t.getSignature(),"Ljava/util/Map<Ljava/util/String;Ljava/util/List<Ljava/lang/Integer;>;>;"); + t = new TypeX("Ljava/util/Map<Ljava/util/String;Ljava/util/List<Ljava/lang/Integer;>;>;"); + assertEquals(t.getName(),"java.util.Map<java.util.String,java.util.List<java.lang.Integer>>"); + assertEquals(t.getSignature(),"Ljava/util/Map<Ljava/util/String;Ljava/util/List<Ljava/lang/Integer;>;>;"); + } private void isPrimitiveTest(TypeX[] types, boolean[] isPrimitives) { for (int i = 0, len = types.length; i < len; i++) { |