aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@tipit.to>2009-06-12 09:54:24 +0200
committerReinier Zwitserloot <reinier@tipit.to>2009-06-12 09:54:24 +0200
commit637298300039a4b943e49c654cb4d2b26161ba60 (patch)
treedfe03dd68e2b961f67260b72e6fb130e8e05bb94 /src
parent40e35d6f79f456fb868c95d764f5d0c9869ea6e4 (diff)
downloadlombok-637298300039a4b943e49c654cb4d2b26161ba60.tar.gz
lombok-637298300039a4b943e49c654cb4d2b26161ba60.tar.bz2
lombok-637298300039a4b943e49c654cb4d2b26161ba60.zip
Now everything works; handlers are called via SPI, and annotations are being parsed. w00t!
Diffstat (limited to 'src')
-rw-r--r--src/lombok/eclipse/EclipseASTAdapter.java8
-rw-r--r--src/lombok/eclipse/EclipseAnnotationHandler.java5
-rw-r--r--src/lombok/eclipse/HandlerLibrary.java282
-rw-r--r--src/lombok/eclipse/TransformEclipseAST.java89
-rw-r--r--src/lombok/eclipse/handlers/HandleGetter_ecj.java32
-rw-r--r--src/lombok/transformations/TypeLibrary.java3
-rw-r--r--src/lombok/transformations/TypeResolver.java23
7 files changed, 409 insertions, 33 deletions
diff --git a/src/lombok/eclipse/EclipseASTAdapter.java b/src/lombok/eclipse/EclipseASTAdapter.java
index fa87872f..a76380cf 100644
--- a/src/lombok/eclipse/EclipseASTAdapter.java
+++ b/src/lombok/eclipse/EclipseASTAdapter.java
@@ -18,8 +18,8 @@ public abstract class EclipseASTAdapter implements EclipseASTVisitor {
@Override public void endVisitInitializer(Node node, Initializer initializer) {}
@Override public void visitField(Node node, FieldDeclaration field) {}
@Override public void endVisitField(Node node, FieldDeclaration field) {}
- @Override public void visitMethod(Node node, AbstractMethodDeclaration declaration) {}
- @Override public void endVisitMethod(Node node, AbstractMethodDeclaration declaration) {}
- @Override public void visitLocal(Node node, LocalDeclaration declaration) {}
- @Override public void endVisitLocal(Node node, LocalDeclaration declaration) {}
+ @Override public void visitMethod(Node node, AbstractMethodDeclaration method) {}
+ @Override public void endVisitMethod(Node node, AbstractMethodDeclaration method) {}
+ @Override public void visitLocal(Node node, LocalDeclaration local) {}
+ @Override public void endVisitLocal(Node node, LocalDeclaration local) {}
}
diff --git a/src/lombok/eclipse/EclipseAnnotationHandler.java b/src/lombok/eclipse/EclipseAnnotationHandler.java
new file mode 100644
index 00000000..e760917b
--- /dev/null
+++ b/src/lombok/eclipse/EclipseAnnotationHandler.java
@@ -0,0 +1,5 @@
+package lombok.eclipse;
+
+public interface EclipseAnnotationHandler<T extends java.lang.annotation.Annotation> {
+ void handle(T annotation, org.eclipse.jdt.internal.compiler.ast.Annotation ast, EclipseAST.Node node);
+}
diff --git a/src/lombok/eclipse/HandlerLibrary.java b/src/lombok/eclipse/HandlerLibrary.java
new file mode 100644
index 00000000..01b2d021
--- /dev/null
+++ b/src/lombok/eclipse/HandlerLibrary.java
@@ -0,0 +1,282 @@
+package lombok.eclipse;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+import lombok.eclipse.EclipseAST.Node;
+import lombok.transformations.TypeLibrary;
+import lombok.transformations.TypeResolver;
+
+import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
+import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.ImportReference;
+import org.eclipse.jdt.internal.compiler.ast.Literal;
+import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
+import org.eclipse.jdt.internal.compiler.ast.NameReference;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+
+public class HandlerLibrary {
+ private TypeLibrary typeLibrary = new TypeLibrary();
+
+ private static class HandlerContainer<T extends Annotation> {
+ private EclipseAnnotationHandler<T> handler;
+ private Class<T> annotationClass;
+
+ HandlerContainer(EclipseAnnotationHandler<T> handler, Class<T> annotationClass) {
+ this.handler = handler;
+ this.annotationClass = annotationClass;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void handle(Object annInstance,
+ org.eclipse.jdt.internal.compiler.ast.Annotation annotation,
+ Node node) {
+ handler.handle((T) annInstance, annotation, node);
+ }
+ }
+
+ private Map<String, HandlerContainer<?>> handlers = new HashMap<String, HandlerContainer<?>>();
+
+ @SuppressWarnings("unchecked")
+ public <A extends Annotation> A createAnnotation(Class<A> target,
+ CompilationUnitDeclaration ast,
+ org.eclipse.jdt.internal.compiler.ast.Annotation node) throws EnumDecodeFail {
+ final Map<String, Object> values = new HashMap<String, Object>();
+
+ final MemberValuePair[] pairs = node.memberValuePairs();
+
+ for ( Method m : target.getMethods() ) {
+ String name = m.getName();
+ Object value = m.getDefaultValue();
+ for ( MemberValuePair pair : pairs ) {
+ if ( name.equals(new String(pair.name)) ) {
+ value = calculateValue(ast, m.getReturnType(), pair.value);
+ break;
+ }
+ }
+ values.put(name, value);
+ }
+
+ InvocationHandler invocations = new InvocationHandler() {
+ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ return values.get(method.getName());
+ }
+ };
+
+ return (A) Proxy.newProxyInstance(target.getClassLoader(), new Class[] { target }, invocations);
+ }
+
+ private Object calculateValue(CompilationUnitDeclaration ast, Class<?> type, Expression e) throws EnumDecodeFail {
+ if ( e instanceof Literal ) {
+ ((Literal)e).computeConstant();
+ return convertConstant(type, e.constant);
+ } else if ( e instanceof ArrayInitializer ) {
+ if ( !type.isArray() ) throw new EnumDecodeFail("Did not expect an array here.");
+
+ Class<?> component = type.getComponentType();
+ Expression[] expressions = ((ArrayInitializer)e).expressions;
+ int length = expressions == null ? 0 : expressions.length;
+ Object[] values = new Object[length];
+ for (int i = 0; i < length; i++) {
+ values[i] = calculateValue(ast, component, expressions[i]);
+ }
+ return values;
+ } else if ( e instanceof ClassLiteralAccess ) {
+ if ( type == Class.class ) return toClass(ast, str(((ClassLiteralAccess)e).type.getTypeName()));
+ else throw new EnumDecodeFail("Expected a " + type + " literal.");
+ } else if ( e instanceof NameReference ) {
+ String s = null;
+ if ( e instanceof SingleNameReference ) s = new String(((SingleNameReference)e).token);
+ else if ( e instanceof QualifiedNameReference ) s = str(((QualifiedNameReference)e).tokens);
+ if ( Enum.class.isAssignableFrom(type) ) toEnum(type, s);
+ throw new EnumDecodeFail("Lombok annotations must contain literals only.");
+ } else {
+ throw new EnumDecodeFail("Lombok could not decode this annotation parameter.");
+ }
+ }
+
+ private Enum<?> toEnum(Class<?> enumType, String ref) throws EnumDecodeFail {
+ int idx = ref.indexOf('.');
+ if ( idx > -1 ) ref = ref.substring(idx +1);
+ Object[] enumConstants = enumType.getEnumConstants();
+ for ( Object constant : enumConstants ) {
+ String target = ((Enum<?>)constant).name();
+ if ( target.equals(ref) ) return (Enum<?>) constant;
+ }
+ throw new EnumDecodeFail("I can't figure out which enum constant you mean.");
+ }
+
+ private Class<?> toClass(CompilationUnitDeclaration ast, String typeName) throws EnumDecodeFail {
+ Class<?> c;
+ boolean fqn = typeName.indexOf('.') > -1;
+
+ if ( fqn ) {
+ c = tryClass(typeName);
+ if ( c != null ) return c;
+ }
+
+ for ( ImportReference ref : ast.imports ) {
+ String im = str(ref.tokens);
+ int idx = im.lastIndexOf('.');
+ String simple = im;
+ if ( idx > -1 ) simple = im.substring(idx+1);
+ if ( simple.equals(typeName) ) {
+ c = tryClass(im);
+ if ( c != null ) return c;
+ }
+ }
+
+ if ( ast.currentPackage != null && ast.currentPackage.tokens != null ) {
+ String pkg = str(ast.currentPackage.tokens);
+ c = tryClass(pkg + "." + typeName);
+ if ( c != null ) return c;
+ }
+
+ c = tryClass("java.lang." + typeName);
+ if ( c != null ) return c;
+
+ throw new EnumDecodeFail("I can't find this class. Try using the fully qualified name.");
+ }
+
+ private Class<?> tryClass(String name) {
+ try {
+ return Class.forName(name);
+ } catch ( ClassNotFoundException e ) {
+ return null;
+ }
+ }
+
+ private Object convertConstant(Class<?> type, Constant constant) throws EnumDecodeFail {
+ int targetTypeID;
+ boolean array = type.isArray();
+ if ( array ) type = type.getComponentType();
+
+ if ( type == int.class ) targetTypeID = TypeIds.T_int;
+ else if ( type == long.class ) targetTypeID = TypeIds.T_long;
+ else if ( type == short.class ) targetTypeID = TypeIds.T_short;
+ else if ( type == byte.class ) targetTypeID = TypeIds.T_byte;
+ else if ( type == double.class ) targetTypeID = TypeIds.T_double;
+ else if ( type == float.class ) targetTypeID = TypeIds.T_float;
+ else if ( type == String.class ) targetTypeID = TypeIds.T_JavaLangString;
+ else if ( type == char.class ) targetTypeID = TypeIds.T_char;
+ else if ( type == boolean.class ) targetTypeID = TypeIds.T_boolean;
+ else {
+ //Enum or Class, so a constant isn't going to be very useful.
+ throw new EnumDecodeFail("Expected a constant of some sort here (a number or a string)");
+ }
+ if ( !Expression.isConstantValueRepresentable(constant, constant.typeID(), targetTypeID) ) {
+ throw new EnumDecodeFail("I can't turn this literal into a " + type);
+ }
+
+ Object o = null;
+
+ if ( type == int.class ) o = constant.intValue();
+ else if ( type == long.class ) o = constant.longValue();
+ else if ( type == short.class ) o = constant.shortValue();
+ else if ( type == byte.class ) o = constant.byteValue();
+ else if ( type == double.class ) o = constant.doubleValue();
+ else if ( type == float.class ) o = constant.floatValue();
+ else if ( type == String.class ) o = constant.stringValue();
+ else if ( type == char.class ) o = constant.charValue();
+ else if ( type == boolean.class ) o = constant.booleanValue();
+
+ if ( array ) {
+ Object a = Array.newInstance(type, 1);
+ Array.set(a, 0, o);
+ return a;
+ }
+
+ return o;
+ }
+
+ private static class EnumDecodeFail extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ EnumDecodeFail(String msg) {
+ super(msg);
+ }
+ }
+
+ private static String str(char[][] c) {
+ boolean first = true;
+ StringBuilder sb = new StringBuilder();
+ for ( char[] part : c ) {
+ sb.append(first ? "" : ".").append(part);
+ first = false;
+ }
+ return sb.toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ public static HandlerLibrary load() {
+ HandlerLibrary lib = new HandlerLibrary();
+ for ( EclipseAnnotationHandler<?> handler : ServiceLoader.load(EclipseAnnotationHandler.class) ) {
+ Class<? extends Annotation> annotationClass = lib.findAnnotationClass(handler.getClass());
+ HandlerContainer<?> container = new HandlerContainer(handler, annotationClass);
+ lib.handlers.put(container.annotationClass.getName(), container);
+ lib.typeLibrary.addType(container.annotationClass.getName());
+ }
+
+ return lib;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Class<? extends Annotation> findAnnotationClass(Class<?> c) {
+ if ( c == Object.class || c == null ) return null;
+ for ( Type iface : c.getGenericInterfaces() ) {
+ if ( iface instanceof ParameterizedType ) {
+ ParameterizedType p = (ParameterizedType)iface;
+ if ( !EclipseAnnotationHandler.class.equals(p.getRawType()) ) continue;
+ Type target = p.getActualTypeArguments()[0];
+ if ( target instanceof Class<?> ) {
+ if ( Annotation.class.isAssignableFrom((Class<?>) target) ) {
+ return (Class<? extends Annotation>) target;
+ }
+ }
+
+ throw new ClassCastException("Not an annotation type: " + target);
+ }
+ }
+
+ Class<? extends Annotation> potential = findAnnotationClass(c.getSuperclass());
+ if ( potential != null ) return potential;
+ for ( Class<?> iface : c.getInterfaces() ) {
+ potential = findAnnotationClass(iface);
+ if ( potential != null ) return potential;
+ }
+
+ return null;
+ }
+
+ public void handle(CompilationUnitDeclaration ast, EclipseAST.Node node,
+ org.eclipse.jdt.internal.compiler.ast.Annotation annotation) {
+ TypeResolver resolver = new TypeResolver(typeLibrary, node.top());
+ TypeReference rawType = annotation.type;
+ if ( rawType == null ) return;
+ for ( String fqn : resolver.findTypeMatches(node, annotation.type) ) {
+ HandlerContainer<?> container = handlers.get(fqn);
+ if ( container == null ) continue;
+ try {
+ Object annInstance = createAnnotation(container.annotationClass, ast, annotation);
+ container.handle(annInstance, annotation, node);
+ } catch (EnumDecodeFail e) {
+ e.printStackTrace();
+ //TODO: Add to problems array in ast.
+ }
+ }
+ }
+}
diff --git a/src/lombok/eclipse/TransformEclipseAST.java b/src/lombok/eclipse/TransformEclipseAST.java
index d0685d1d..34350597 100644
--- a/src/lombok/eclipse/TransformEclipseAST.java
+++ b/src/lombok/eclipse/TransformEclipseAST.java
@@ -1,15 +1,15 @@
package lombok.eclipse;
-import java.util.Map;
-import java.util.WeakHashMap;
+import java.lang.reflect.Field;
import lombok.eclipse.EclipseAST.Node;
-import lombok.eclipse.handlers.HandleGetter_ecj;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.parser.Parser;
/**
@@ -26,8 +26,27 @@ import org.eclipse.jdt.internal.compiler.parser.Parser;
* @author rspilker
*/
public class TransformEclipseAST {
- private static final Map<CompilationUnitDeclaration, EclipseAST> astCache =
- new WeakHashMap<CompilationUnitDeclaration, EclipseAST>();
+ private final EclipseAST ast;
+ //The patcher hacks this field onto CUD. It's public.
+ private static final Field astCacheField;
+ private static final HandlerLibrary handlers;
+
+ static {
+ Field f = null;
+ HandlerLibrary l = null;
+ try {
+ l = HandlerLibrary.load();
+ } catch ( Exception e ) {
+ e.printStackTrace();
+ }
+ try {
+ f = CompilationUnitDeclaration.class.getDeclaredField("$lombokAST");
+ } catch ( NoSuchFieldException ignore ) {
+ ignore.printStackTrace();
+ }
+ astCacheField = f;
+ handlers = l;
+ }
/**
* This method is called immediately after eclipse finishes building a CompilationUnitDeclaration, which is
@@ -41,25 +60,67 @@ public class TransformEclipseAST {
* @param ast The AST node belonging to the compilation unit (java speak for a single source file).
*/
public static void transform(Parser parser, CompilationUnitDeclaration ast) {
- EclipseAST existing = astCache.get(ast);
+ EclipseAST existing = getCache(ast);
if ( existing == null ) {
existing = new EclipseAST(ast);
- astCache.put(ast, existing);
+ setCache(ast, existing);
} else existing.reparse();
-
- existing.traverse(new AnnotationVisitor());
+ new TransformEclipseAST(existing).go();
+ }
+
+ private static EclipseAST getCache(CompilationUnitDeclaration ast) {
+ if ( astCacheField == null ) return null;
+ try {
+ return (EclipseAST)astCacheField.get(ast);
+ } catch ( Exception e ) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private static void setCache(CompilationUnitDeclaration ast, EclipseAST cache) {
+ if ( astCacheField != null ) try {
+ astCacheField.set(ast, cache);
+ } catch ( Exception ignore ) {
+ ignore.printStackTrace();
+ }
+ }
+
+ public TransformEclipseAST(EclipseAST ast) {
+ this.ast = ast;
+ }
+
+ public void go() {
+ ast.traverse(new AnnotationVisitor());
}
private static class AnnotationVisitor extends EclipseASTAdapter {
@Override public void visitField(Node node, FieldDeclaration field) {
if ( field.annotations == null ) return;
for ( Annotation annotation : field.annotations ) {
- TypeReference type = annotation.type;
- if ( type != null && new String(type.getLastToken()).equals("Getter") ) {
- new HandleGetter_ecj().apply(annotation, node, field);
- }
+ handlers.handle((CompilationUnitDeclaration) node.top().node, node, annotation);
+ }
+ }
+
+ @Override public void visitLocal(Node node, LocalDeclaration local) {
+ if ( local.annotations == null ) return;
+ for ( Annotation annotation : local.annotations ) {
+ handlers.handle((CompilationUnitDeclaration) node.top().node, node, annotation);
}
}
+ @Override public void visitMethod(Node node, AbstractMethodDeclaration method) {
+ if ( method.annotations == null ) return;
+ for ( Annotation annotation : method.annotations ) {
+ handlers.handle((CompilationUnitDeclaration) node.top().node, node, annotation);
+ }
+ }
+
+ @Override public void visitType(Node node, TypeDeclaration type) {
+ if ( type.annotations == null ) return;
+ for ( Annotation annotation : type.annotations ) {
+ handlers.handle((CompilationUnitDeclaration) node.top().node, node, annotation);
+ }
+ }
}
}
diff --git a/src/lombok/eclipse/handlers/HandleGetter_ecj.java b/src/lombok/eclipse/handlers/HandleGetter_ecj.java
index e61eb64b..9ce8d2d9 100644
--- a/src/lombok/eclipse/handlers/HandleGetter_ecj.java
+++ b/src/lombok/eclipse/handlers/HandleGetter_ecj.java
@@ -2,6 +2,9 @@ package lombok.eclipse.handlers;
import java.lang.reflect.Modifier;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseAST.Node;
import lombok.transformations.TransformationsUtil;
@@ -17,9 +20,12 @@ import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
+import org.mangosdk.spi.ProviderFor;
-public class HandleGetter_ecj {
- public void apply(Annotation annotation, Node node, FieldDeclaration field) {
+@ProviderFor(EclipseAnnotationHandler.class)
+public class HandleGetter_ecj implements EclipseAnnotationHandler<Getter> {
+ @Override public void handle(Getter annotation, Annotation ast, Node node) {
+ FieldDeclaration field = (FieldDeclaration) node.getEclipseNode();
TypeReference fieldType = field.type;
String getterName = TransformationsUtil.toGetterName(
new String(field.name), nameEquals(fieldType.getTypeName(), "boolean"));
@@ -30,7 +36,7 @@ public class HandleGetter_ecj {
}
MethodDeclaration method = new MethodDeclaration(parent.compilationResult);
- method.modifiers = Modifier.PUBLIC;
+ method.modifiers = toModifier(annotation.value());
method.returnType = field.type;
method.annotations = null;
method.arguments = null;
@@ -42,8 +48,8 @@ public class HandleGetter_ecj {
method.bits |= ASTNode.Bit24;
Expression fieldExpression = new SingleNameReference(field.name, (field.declarationSourceStart << 32) | field.declarationSourceEnd);
Statement returnStatement = new ReturnStatement(fieldExpression, field.sourceStart, field.sourceEnd);
- method.bodyStart = method.declarationSourceStart = method.sourceStart = annotation.sourceStart;
- method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = annotation.sourceEnd;
+ method.bodyStart = method.declarationSourceStart = method.sourceStart = ast.sourceStart;
+ method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = ast.sourceEnd;
method.statements = new Statement[] { returnStatement };
if ( parent.methods == null ) {
parent.methods = new AbstractMethodDeclaration[1];
@@ -56,6 +62,21 @@ public class HandleGetter_ecj {
}
}
+ private int toModifier(AccessLevel value) {
+ switch ( value ) {
+ case MODULE:
+ case PACKAGE:
+ return 0;
+ default:
+ case PUBLIC:
+ return Modifier.PUBLIC;
+ case PROTECTED:
+ return Modifier.PROTECTED;
+ case PRIVATE:
+ return Modifier.PRIVATE;
+ }
+ }
+
private boolean nameEquals(char[][] typeName, String string) {
StringBuilder sb = new StringBuilder();
boolean first = true;
@@ -67,4 +88,5 @@ public class HandleGetter_ecj {
return string.contentEquals(sb);
}
+
}
diff --git a/src/lombok/transformations/TypeLibrary.java b/src/lombok/transformations/TypeLibrary.java
index 00ae64b0..9b5c8e57 100644
--- a/src/lombok/transformations/TypeLibrary.java
+++ b/src/lombok/transformations/TypeLibrary.java
@@ -33,6 +33,7 @@ public class TypeLibrary {
}
public Collection<String> findCompatible(String typeReference) {
- return simpleToQualifiedMap.get(typeReference);
+ Set<String> result = simpleToQualifiedMap.get(typeReference);
+ return result == null ? Collections.<String>emptySet() : result;
}
}
diff --git a/src/lombok/transformations/TypeResolver.java b/src/lombok/transformations/TypeResolver.java
index 2a012f57..3c3617a6 100644
--- a/src/lombok/transformations/TypeResolver.java
+++ b/src/lombok/transformations/TypeResolver.java
@@ -6,23 +6,21 @@ import java.util.HashSet;
import java.util.Set;
import lombok.eclipse.EclipseAST;
+import lombok.eclipse.EclipseAST.Node;
-import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
-import org.eclipse.jdt.internal.compiler.parser.Parser;
public class TypeResolver {
private final TypeLibrary library;
- private final EclipseAST ast;
private Collection<String> imports;
- public TypeResolver(TypeLibrary library, Parser parser, EclipseAST ast) {
+ public TypeResolver(TypeLibrary library, EclipseAST.Node top) {
this.library = library;
- this.ast = ast;
- this.imports = makeImportList((CompilationUnitDeclaration) ast.top().getEclipseNode());
+ this.imports = makeImportList((CompilationUnitDeclaration) top.getEclipseNode());
}
private static Collection<String> makeImportList(CompilationUnitDeclaration declaration) {
@@ -33,8 +31,8 @@ public class TypeResolver {
}
return imports;
}
-
- public Collection<String> findTypeMatches(ASTNode context, TypeReference type) {
+
+ public Collection<String> findTypeMatches(Node context, TypeReference type) {
Collection<String> potentialMatches = library.findCompatible(toQualifiedName(type.getTypeName()));
if ( potentialMatches.isEmpty() ) return Collections.emptyList();
@@ -50,7 +48,14 @@ public class TypeResolver {
if ( potentialMatches.isEmpty() ) return Collections.emptyList();
//Find a lexically accessible type of the same simple name in the same Compilation Unit. If it exists: no matches.
-
+ Node n = context;
+ while ( n != null ) {
+ if ( n.getEclipseNode() instanceof TypeDeclaration ) {
+ char[] name = ((TypeDeclaration)n.getEclipseNode()).name;
+ if ( name != null && new String(name).equals(simpleName) ) return Collections.emptyList();
+ }
+ n = n.up();
+ }
// The potential matches we found by comparing the import statements is our matching set. Return it.
return potentialMatches;