@@ -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; |
@@ -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() { |
@@ -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; |
@@ -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 | |||
*/ |
@@ -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); |
@@ -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++) { |