import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding; | 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.LookupEnvironment; | ||||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding; | 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.ReferenceBinding; | ||||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Scope; | 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.SourceTypeBinding; | ||||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding; | 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.TypeVariableBinding; | ||||
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; | |||||
/** | /** | ||||
* @author Jim Hugunin | * @author Jim Hugunin | ||||
TypeVariableBinding tvb = (TypeVariableBinding) binding; | TypeVariableBinding tvb = (TypeVariableBinding) binding; | ||||
return TypeX.forName(getName(tvb.firstBound)); // XXX needs more investigation as to whether this is correct in all cases | 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)); | return TypeX.forName(getName(binding)); | ||||
} | } | ||||
typeX = typeX.getComponentType(); | typeX = typeX.getComponentType(); | ||||
} | } | ||||
return lookupEnvironment.createArrayType(makeTypeBinding(typeX), dim); | 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 { | } 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) { | public TypeBinding[] makeTypeBindings(TypeX[] types) { | ||||
int len = types.length; | int len = types.length; |
public aspect ITDReturningParameterizedType { | public aspect ITDReturningParameterizedType { | ||||
private List<String> myStrings = new ArrayList<String>(); | |||||
private List<String> C.strings = new ArrayList<String>(); | private List<String> C.strings = new ArrayList<String>(); | ||||
public List<String> C.getStrings() { | public List<String> C.getStrings() { |
suite.addTest(SuppressedWarnings.suite()); | suite.addTest(SuppressedWarnings.suite()); | ||||
suite.addTest(DeclareAnnotationTests.suite()); | suite.addTest(DeclareAnnotationTests.suite()); | ||||
suite.addTest(GenericsTests.suite()); | |||||
suite.addTest(AtAjSyntaxTests.suite()); | suite.addTest(AtAjSyntaxTests.suite()); | ||||
//$JUnit-END$ | //$JUnit-END$ | ||||
return suite; | return suite; |
* This is the bytecode string representation of this Type | * This is the bytecode string representation of this Type | ||||
*/ | */ | ||||
protected String signature; | 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 | * @param signature the bytecode string representation of this Type | ||||
} | } | ||||
return ret; | 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. | * Creates a new type array with a fresh type appended to the end. | ||||
* | * | ||||
public String getName() { | public String getName() { | ||||
return signatureToName(signature); | 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 | * Returns an array of strings representing the java langauge names of | ||||
public final boolean isArray() { | public final boolean isArray() { | ||||
return signature.startsWith("["); | 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 | * Returns a TypeX object representing the effective outermost enclosing type | ||||
case 'I': return "int"; | case 'I': return "int"; | ||||
case 'J': return "long"; | case 'J': return "long"; | ||||
case 'L': | 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 'S': return "short"; | ||||
case 'V': return "void"; | case 'V': return "void"; | ||||
case 'Z': return "boolean"; | case 'Z': return "boolean"; | ||||
// 1) If it is already an array type, do not mess with it. | // 1) If it is already an array type, do not mess with it. | ||||
if (name.charAt(0)=='[' && name.charAt(name.length()-1)==';') return name; | 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 | else | ||||
throw new BCException("Bad type name: " + name); | throw new BCException("Bad type name: " + name); | ||||
} | } | ||||
} | } | ||||
public TypeX[] getTypeParameters() { | |||||
return typeParameters == null ? new TypeX[0] : typeParameters; | |||||
} | |||||
/** | /** | ||||
* Doesn't include the package | * Doesn't include the package | ||||
*/ | */ |
dumpState_cantFindTypeExceptions.add(new RuntimeException("Can't find type "+ty.getName())); | 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); | //System.out.println("ret: " + ret); | ||||
typeMap.put(signature, ret); | typeMap.put(signature, ret); | ||||
return ret; | return ret; | ||||
return resolve(TypeX.forName(name)); | return resolve(TypeX.forName(name)); | ||||
} | } | ||||
protected final ResolvedTypeX resolveObjectType(TypeX ty) { | 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); | ResolvedTypeX.ConcreteName concreteName = resolveObjectType(name); | ||||
if (concreteName == null) return ResolvedTypeX.MISSING; | if (concreteName == null) return ResolvedTypeX.MISSING; | ||||
name.setDelegate(concreteName); | name.setDelegate(concreteName); |
assertEquals(t.getOutermostType(), TypeX.forName("java.util.Map")); | assertEquals(t.getOutermostType(), TypeX.forName("java.util.Map")); | ||||
assertEquals(TypeX.forName("java.util.Map").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) { | private void isPrimitiveTest(TypeX[] types, boolean[] isPrimitives) { | ||||
for (int i = 0, len = types.length; i < len; i++) { | for (int i = 0, len = types.length; i < len; i++) { |