aboutsummaryrefslogtreecommitdiff
path: root/src/lombok/eclipse/HandlerLibrary.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/lombok/eclipse/HandlerLibrary.java')
-rw-r--r--src/lombok/eclipse/HandlerLibrary.java287
1 files changed, 86 insertions, 201 deletions
diff --git a/src/lombok/eclipse/HandlerLibrary.java b/src/lombok/eclipse/HandlerLibrary.java
index 8a7f6edc..2e3e4541 100644
--- a/src/lombok/eclipse/HandlerLibrary.java
+++ b/src/lombok/eclipse/HandlerLibrary.java
@@ -1,34 +1,36 @@
package lombok.eclipse;
+import static lombok.eclipse.Eclipse.toQualifiedName;
+
import java.lang.annotation.Annotation;
-import java.lang.reflect.Array;
-import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
+import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
+import lombok.core.AnnotationValues;
import lombok.core.SpiLoadUtil;
import lombok.core.TypeLibrary;
+import lombok.core.TypeResolver;
+import lombok.core.AnnotationValues.AnnotationValue;
+import lombok.core.AnnotationValues.AnnotationValueDecodeFail;
import lombok.eclipse.EclipseAST.Node;
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 {
@@ -43,11 +45,56 @@ public class HandlerLibrary {
this.annotationClass = annotationClass;
}
- @SuppressWarnings("unchecked")
- public void handle(Object annInstance,
- org.eclipse.jdt.internal.compiler.ast.Annotation annotation,
- Node annotationNode) {
- handler.handle((T) annInstance, annotation, annotationNode);
+ public void handle(org.eclipse.jdt.internal.compiler.ast.Annotation annotation,
+ final Node annotationNode) {
+ Map<String, AnnotationValue> values = new HashMap<String, AnnotationValue>();
+
+ final MemberValuePair[] pairs = annotation.memberValuePairs();
+ for ( Method m : annotationClass.getDeclaredMethods() ) {
+ if ( !Modifier.isPublic(m.getModifiers()) ) continue;
+ String name = m.getName();
+ List<String> raws = new ArrayList<String>();
+ List<Object> guesses = new ArrayList<Object>();
+ Expression fullExpression = null;
+ Expression[] expressions = null;
+
+ if ( pairs != null ) for ( MemberValuePair pair : pairs ) {
+ char[] n = pair.name;
+ String mName = n == null ? "value" : new String(name);
+ if ( !mName.equals(name) ) continue;
+ fullExpression = pair.value;
+ }
+
+ if ( fullExpression != null ) {
+ if ( fullExpression instanceof ArrayInitializer ) {
+ expressions = ((ArrayInitializer)fullExpression).expressions;
+ } else expressions = new Expression[] { fullExpression };
+ for ( Expression ex : expressions ) {
+ StringBuffer sb = new StringBuffer();
+ ex.print(0, sb);
+ raws.add(sb.toString());
+ guesses.add(calculateValue(ex));
+ }
+ }
+
+ final Expression fullExpr = fullExpression;
+ final Expression[] exprs = expressions;
+
+ values.put(name, new AnnotationValue(annotationNode, raws, guesses) {
+ @Override public void setError(String message, int valueIdx) {
+ Expression ex;
+ if ( valueIdx == -1 ) ex = fullExpr;
+ else ex = exprs[valueIdx];
+
+ int sourceStart = ex.sourceStart;
+ int sourceEnd = ex.sourceEnd;
+
+ annotationNode.addError(message, sourceStart, sourceEnd);
+ }
+ });
+ }
+
+ handler.handle(new AnnotationValues<T>(annotationClass, values, annotationNode), annotation, annotationNode);
}
}
@@ -56,192 +103,32 @@ public class HandlerLibrary {
private Collection<EclipseASTVisitor> visitorHandlers = new ArrayList<EclipseASTVisitor>();
- @SuppressWarnings("unchecked")
- public <A extends Annotation> A createAnnotation(Class<A> target,
- CompilationUnitDeclaration ast,
- org.eclipse.jdt.internal.compiler.ast.Annotation node) throws AnnotationValueDecodeFail {
- 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(pair, 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(MemberValuePair pair,
- CompilationUnitDeclaration ast, Class<?> type, Expression e) throws AnnotationValueDecodeFail {
+ private static Object calculateValue(Expression e) {
if ( e instanceof Literal ) {
((Literal)e).computeConstant();
- return convertConstant(pair, type, e.constant);
- } else if ( e instanceof ArrayInitializer ) {
- if ( !type.isArray() ) throw new AnnotationValueDecodeFail(pair, "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(pair, ast, component, expressions[i]);
+ switch ( e.constant.typeID() ) {
+ case TypeIds.T_int: return e.constant.intValue();
+ case TypeIds.T_byte: return e.constant.byteValue();
+ case TypeIds.T_short: return e.constant.shortValue();
+ case TypeIds.T_char: return e.constant.charValue();
+ case TypeIds.T_float: return e.constant.floatValue();
+ case TypeIds.T_double: return e.constant.doubleValue();
+ case TypeIds.T_boolean: return e.constant.booleanValue();
+ case TypeIds.T_long: return e.constant.longValue();
+ case TypeIds.T_JavaLangString: return e.constant.stringValue();
+ default: return null;
}
- return values;
} else if ( e instanceof ClassLiteralAccess ) {
- if ( type == Class.class ) return toClass(pair, ast, str(((ClassLiteralAccess)e).type.getTypeName()));
- else throw new AnnotationValueDecodeFail(pair, "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) ) return toEnum(pair, type, s);
- throw new AnnotationValueDecodeFail(pair, "Lombok annotations must contain literals only.");
- } else {
- throw new AnnotationValueDecodeFail(pair, "Lombok could not decode this annotation parameter.");
- }
- }
-
- private Enum<?> toEnum(MemberValuePair pair, Class<?> enumType, String ref) throws AnnotationValueDecodeFail {
- 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;
+ return Eclipse.toQualifiedName(((ClassLiteralAccess)e).type.getTypeName());
+ } else if ( e instanceof SingleNameReference ) {
+ return new String(((SingleNameReference)e).token);
+ } else if ( e instanceof QualifiedNameReference ) {
+ String qName = Eclipse.toQualifiedName(((QualifiedNameReference)e).tokens);
+ int idx = qName.lastIndexOf('.');
+ return idx == -1 ? qName : qName.substring(idx+1);
}
- throw new AnnotationValueDecodeFail(pair, "I can't figure out which enum constant you mean.");
- }
-
- private Class<?> toClass(MemberValuePair pair, CompilationUnitDeclaration ast, String typeName) throws AnnotationValueDecodeFail {
- 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;
- if ( !fqn ) {
- c = tryClass(typeName);
- if ( c != null ) return c;
- }
-
- //Try star imports
- for ( ImportReference ref : ast.imports ) {
- String im = str(ref.tokens);
- if ( im.endsWith(".*") ) {
- c = tryClass(im.substring(0, im.length() -1) + typeName);
- if ( c != null ) return c;
- }
- }
-
- throw new AnnotationValueDecodeFail(pair, "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(MemberValuePair pair, Class<?> type, Constant constant) throws AnnotationValueDecodeFail {
- 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 AnnotationValueDecodeFail(pair, "Expected a constant of some sort here (a number or a string)");
- }
- if ( !Expression.isConstantValueRepresentable(constant, constant.typeID(), targetTypeID) ) {
- throw new AnnotationValueDecodeFail(pair, "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 AnnotationValueDecodeFail extends Exception {
- private static final long serialVersionUID = 1L;
-
- MemberValuePair pair;
-
- AnnotationValueDecodeFail(MemberValuePair pair, String msg) {
- super(msg);
- this.pair = pair;
- }
- }
-
- 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();
+ return null;
}
public static HandlerLibrary load() {
@@ -284,22 +171,20 @@ public class HandlerLibrary {
public void handle(CompilationUnitDeclaration ast, EclipseAST.Node annotationNode,
org.eclipse.jdt.internal.compiler.ast.Annotation annotation) {
- TypeResolver resolver = new TypeResolver(typeLibrary, annotationNode.top());
+ String pkgName = annotationNode.getPackageDeclaration();
+ Collection<String> imports = annotationNode.getImportStatements();
+
+ TypeResolver resolver = new TypeResolver(typeLibrary, pkgName, imports);
TypeReference rawType = annotation.type;
if ( rawType == null ) return;
- for ( String fqn : resolver.findTypeMatches(annotationNode, annotation.type) ) {
+ for ( String fqn : resolver.findTypeMatches(annotationNode, toQualifiedName(annotation.type.getTypeName())) ) {
AnnotationHandlerContainer<?> container = annotationHandlers.get(fqn);
if ( container == null ) continue;
- Object annInstance;
- try {
- annInstance = createAnnotation(container.annotationClass, ast, annotation);
- } catch ( AnnotationValueDecodeFail e ) {
- annotationNode.addError(e.getMessage(), e.pair.sourceStart, e.pair.sourceEnd);
- return;
- }
try {
- container.handle(annInstance, annotation, annotationNode);
+ container.handle(annotation, annotationNode);
+ } catch ( AnnotationValueDecodeFail fail ) {
+ fail.owner.setError(fail.getMessage(), fail.idx);
} catch ( Throwable t ) {
Eclipse.error(String.format("Lombok annotation handler %s failed", container.handler.getClass()), t);
}