Browse Source

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.

tags/PRE_ANDY
acolyer 19 years ago
parent
commit
7a639d019a

+ 37
- 11
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseFactory.java View File

@@ -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
- 0
tests/java5/generics/ITDReturningParameterizedType.aj View File

@@ -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() {

+ 1
- 1
tests/src/org/aspectj/systemtest/ajc150/AllTestsAspectJ150.java View File

@@ -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;

+ 112
- 3
weaver/src/org/aspectj/weaver/TypeX.java View File

@@ -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
*/

+ 13
- 1
weaver/src/org/aspectj/weaver/World.java View File

@@ -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);

+ 15
- 0
weaver/testsrc/org/aspectj/weaver/TypeXTestCase.java View File

@@ -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++) {

Loading…
Cancel
Save