mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-14 10:18:46 +00:00
Now everything works; handlers are called via SPI, and annotations are being parsed. w00t!
This commit is contained in:
1 parent
40e35d6f79
commit
6372983000
7 files changed
+409
-33
No files matched your search
@@ -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) {}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user