aboutsummaryrefslogtreecommitdiff
path: root/src/lombok/eclipse
diff options
context:
space:
mode:
Diffstat (limited to 'src/lombok/eclipse')
-rw-r--r--src/lombok/eclipse/Eclipse.java10
-rw-r--r--src/lombok/eclipse/EclipseAST.java370
-rw-r--r--src/lombok/eclipse/EclipseASTAdapter.java4
-rw-r--r--src/lombok/eclipse/EclipseASTVisitor.java32
-rw-r--r--src/lombok/eclipse/EclipseAnnotationHandler.java4
-rw-r--r--src/lombok/eclipse/HandlerLibrary.java287
-rw-r--r--src/lombok/eclipse/TransformEclipseAST.java15
-rw-r--r--src/lombok/eclipse/TypeResolver.java100
-rw-r--r--src/lombok/eclipse/handlers/HandleGetter_ecj.java11
9 files changed, 296 insertions, 537 deletions
diff --git a/src/lombok/eclipse/Eclipse.java b/src/lombok/eclipse/Eclipse.java
index e1ff95cd..961b9536 100644
--- a/src/lombok/eclipse/Eclipse.java
+++ b/src/lombok/eclipse/Eclipse.java
@@ -31,4 +31,14 @@ public class Eclipse {
log.log(new Status(IStatus.ERROR, bundleName, message, error));
}
+
+ static String toQualifiedName(char[][] typeName) {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for ( char[] c : typeName ) {
+ sb.append(first ? "" : ".").append(c);
+ first = false;
+ }
+ return sb.toString();
+ }
}
diff --git a/src/lombok/eclipse/EclipseAST.java b/src/lombok/eclipse/EclipseAST.java
index 3fdd02e4..53a993ec 100644
--- a/src/lombok/eclipse/EclipseAST.java
+++ b/src/lombok/eclipse/EclipseAST.java
@@ -1,17 +1,13 @@
package lombok.eclipse;
-import static lombok.Lombok.sneakyThrow;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
+import lombok.core.AST;
+
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.apt.dispatch.AptProblem;
@@ -22,24 +18,44 @@ import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.Clinit;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.Initializer;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
import org.eclipse.jdt.internal.compiler.util.Util;
-public class EclipseAST {
+public class EclipseAST extends AST<ASTNode> {
+ @Override public String getPackageDeclaration() {
+ CompilationUnitDeclaration cud = (CompilationUnitDeclaration) top().get();
+ ImportReference pkg = cud.currentPackage;
+ return pkg == null ? null : Eclipse.toQualifiedName(pkg.getImportName());
+ }
+
+ @Override public Collection<String> getImportStatements() {
+ List<String> imports = new ArrayList<String>();
+ CompilationUnitDeclaration cud = (CompilationUnitDeclaration) top().get();
+ if ( cud.imports == null ) return imports;
+ for ( ImportReference imp : cud.imports ) {
+ if ( imp == null ) continue;
+ imports.add(Eclipse.toQualifiedName(imp.getImportName()));
+ }
+
+ return imports;
+ }
+
public void traverse(EclipseASTVisitor visitor) {
Node current = top();
- visitor.visitCompilationUnit(current, (CompilationUnitDeclaration)current.node);
+ visitor.visitCompilationUnit(current, (CompilationUnitDeclaration)current.get());
traverseChildren(visitor, current);
- visitor.endVisitCompilationUnit(current, (CompilationUnitDeclaration)current.node);
+ visitor.endVisitCompilationUnit(current, (CompilationUnitDeclaration)current.get());
}
private void traverseChildren(EclipseASTVisitor visitor, Node node) {
- for ( Node child : node.children ) {
- ASTNode n = child.node;
+ for ( Node child : node.down() ) {
+ ASTNode n = child.get();
if ( n instanceof TypeDeclaration ) {
visitor.visitType(child, (TypeDeclaration)n);
traverseChildren(visitor, child);
@@ -57,20 +73,33 @@ public class EclipseAST {
visitor.visitMethod(child, (AbstractMethodDeclaration)n);
traverseChildren(visitor, child);
visitor.endVisitMethod(child, (AbstractMethodDeclaration)n);
+ } else if ( n instanceof Argument ) {
+ ASTNode parent = child.up().get();
+ AbstractMethodDeclaration method = null;
+ if ( parent instanceof AbstractMethodDeclaration ) method = (AbstractMethodDeclaration)parent;
+ else System.out.println("Weird, this isn't a desc of method: " + parent.getClass() + ": " + parent);
+ visitor.visitMethodArgument(child, (Argument)n, method);
+ traverseChildren(visitor, child);
+ visitor.endVisitMethodArgument(child, (Argument)n, method);
} else if ( n instanceof LocalDeclaration ) {
visitor.visitLocal(child, (LocalDeclaration)n);
traverseChildren(visitor, child);
visitor.endVisitLocal(child, (LocalDeclaration)n);
} else if ( n instanceof Annotation ) {
Node parent = child.up();
- if ( parent.node instanceof TypeDeclaration )
- visitor.visitAnnotationOnType((TypeDeclaration)parent.node, child, (Annotation)n);
- else if ( parent.node instanceof AbstractMethodDeclaration )
- visitor.visitAnnotationOnMethod((AbstractMethodDeclaration)parent.node, child, (Annotation)n);
- else if ( parent.node instanceof FieldDeclaration )
- visitor.visitAnnotationOnField((FieldDeclaration)parent.node, child, (Annotation)n);
- else if ( parent.node instanceof LocalDeclaration )
- visitor.visitAnnotationOnLocal((LocalDeclaration)parent.node, child, (Annotation)n);
+ if ( parent.get() instanceof TypeDeclaration )
+ visitor.visitAnnotationOnType((TypeDeclaration)parent.get(), child, (Annotation)n);
+ else if ( parent.get() instanceof AbstractMethodDeclaration )
+ visitor.visitAnnotationOnMethod((AbstractMethodDeclaration)parent.get(), child, (Annotation)n);
+ else if ( parent.get() instanceof FieldDeclaration )
+ visitor.visitAnnotationOnField((FieldDeclaration)parent.get(), child, (Annotation)n);
+ else if ( parent.get() instanceof Argument )
+ visitor.visitAnnotationOnMethodArgument(
+ (Argument)parent.get(),
+ (AbstractMethodDeclaration)parent.directUp().get(),
+ child, (Annotation)n);
+ else if ( parent.get() instanceof LocalDeclaration )
+ visitor.visitAnnotationOnLocal((LocalDeclaration)parent.get(), child, (Annotation)n);
} else if ( n instanceof Statement ) {
visitor.visitStatement(child, (Statement)n);
traverseChildren(visitor, child);
@@ -83,16 +112,12 @@ public class EclipseAST {
return completeParse;
}
- public String getFileName() {
- return fileName;
- }
-
- public Node top() {
- return top;
+ @Override public Node top() {
+ return (Node) super.top();
}
public Node get(ASTNode node) {
- return nodeMap.get(node);
+ return (Node) super.get(node);
}
private class ParseProblem {
@@ -111,14 +136,14 @@ public class EclipseAST {
}
void addToCompilationResult() {
- addProblemToCompilationResult(getFileName(), (CompilationUnitDeclaration) top().getEclipseNode(),
- isWarning, message, node.getEclipseNode(), sourceStart, sourceEnd);
+ addProblemToCompilationResult(getFileName(), (CompilationUnitDeclaration) top().get(),
+ isWarning, message, node.get(), sourceStart, sourceEnd);
}
}
- public void propagateProblems() {
+ private void propagateProblems() {
if ( queuedProblems.isEmpty() ) return;
- CompilationUnitDeclaration cud = (CompilationUnitDeclaration) top().getEclipseNode();
+ CompilationUnitDeclaration cud = (CompilationUnitDeclaration) top().get();
if ( cud.compilationResult == null ) return;
for ( ParseProblem problem : queuedProblems ) problem.addToCompilationResult();
queuedProblems.clear();
@@ -152,59 +177,44 @@ public class EclipseAST {
ast.compilationResult.record(ecProblem, null);
}
- public final class Node {
- final ASTNode node;
- Node parent;
- final Collection<Node> children;
- boolean handled;
- private final boolean isStructurallySignificant;
+ public final class Node extends AST<ASTNode>.Node {
+ Node(ASTNode node, Collection<Node> children, Kind kind) {
+ super(node, children, kind);
+ }
- Node(ASTNode node, Collection<Node> children) {
- this.node = node;
- this.children = children == null ? Collections.<Node>emptyList() : children;
- this.isStructurallySignificant = calculateIsStructurallySignificant();
+ @Override public String getName() {
+ final char[] n;
+ if ( node instanceof TypeDeclaration ) n = ((TypeDeclaration)node).name;
+ else if ( node instanceof FieldDeclaration ) n = ((FieldDeclaration)node).name;
+ else if ( node instanceof AbstractMethodDeclaration ) n = ((AbstractMethodDeclaration)node).selector;
+ else if ( node instanceof LocalDeclaration ) n = ((LocalDeclaration)node).name;
+ else n = null;
+
+ return n == null ? null : new String(n);
}
- public void addError(String message) {
- this.addError(message, this.getEclipseNode().sourceStart, this.getEclipseNode().sourceEnd);
+ @Override public void addError(String message) {
+ this.addError(message, this.get().sourceStart, this.get().sourceEnd);
}
public void addError(String message, int sourceStart, int sourceEnd) {
addProblem(new ParseProblem(false, message, this, sourceStart, sourceEnd));
}
- public void addWarning(String message) {
- this.addWarning(message, this.getEclipseNode().sourceStart, this.getEclipseNode().sourceEnd);
+ @Override public void addWarning(String message) {
+ this.addWarning(message, this.get().sourceStart, this.get().sourceEnd);
}
public void addWarning(String message, int sourceStart, int sourceEnd) {
addProblem(new ParseProblem(true, message, this, sourceStart, sourceEnd));
}
- public ASTNode getEclipseNode() {
- return node;
- }
-
- /** Returns the structurally significant node that encloses this one.
- *
- * @see #isStructurallySignificant()
- */
- public Node up() {
- Node result = parent;
- while ( result != null && !result.isStructurallySignificant() ) result = result.parent;
- return result;
- }
-
- /**
- * Structurally significant means: LocalDeclaration, TypeDeclaration, MethodDeclaration, ConstructorDeclaration,
- * FieldDeclaration, Initializer, and CompilationUnitDeclaration.
- * The rest is e.g. if statements, while loops, etc.
- */
- public boolean isStructurallySignificant() {
- return isStructurallySignificant;
+ /** {@inheritDoc} */
+ @Override public Node up() {
+ return (Node) super.up();
}
- private boolean calculateIsStructurallySignificant() {
+ @Override protected boolean calculateIsStructurallySignificant() {
if ( node instanceof TypeDeclaration ) return true;
if ( node instanceof AbstractMethodDeclaration ) return true;
if ( node instanceof FieldDeclaration ) return true;
@@ -213,33 +223,20 @@ public class EclipseAST {
return false;
}
- /**
- * Returns the direct parent node in the AST tree of this node. For example, a local variable declaration's
- * direct parent can be e.g. an If block, but its up() Node is the Method that contains it.
- */
+ /** {@inheritDoc} */
public Node directUp() {
- return parent;
- }
-
- public Collection<Node> down() {
- return children;
- }
-
- public boolean isHandled() {
- return handled;
+ return (Node) super.directUp();
}
- public Node setHandled() {
- this.handled = true;
- return this;
+ /** {@inheritDoc} */
+ @SuppressWarnings("unchecked")
+ @Override public Collection<Node> down() {
+ return (Collection<Node>) children;
}
- public Node top() {
- return top;
- }
-
- public String getFileName() {
- return fileName;
+ /** {@inheritDoc} */
+ @Override public Node top() {
+ return (Node) super.top();
}
public boolean isCompleteParse() {
@@ -247,33 +244,33 @@ public class EclipseAST {
}
}
- private final Map<ASTNode, Void> identityDetector = new IdentityHashMap<ASTNode, Void>();
- private Map<ASTNode, Node> nodeMap = new HashMap<ASTNode, Node>();
private final CompilationUnitDeclaration compilationUnitDeclaration;
- private final String fileName;
- private Node top;
private boolean completeParse;
public EclipseAST(CompilationUnitDeclaration ast) {
+ super(toFileName(ast));
this.compilationUnitDeclaration = ast;
- this.fileName = ast.compilationResult.fileName == null ? "(unknown).java" : new String(ast.compilationResult.fileName);
- this.top = buildTree(ast);
+ setTop(buildCompilationUnit(ast));
this.completeParse = isComplete(ast);
}
+ private static String toFileName(CompilationUnitDeclaration ast) {
+ return ast.compilationResult.fileName == null ? null : new String(ast.compilationResult.fileName);
+ }
+
public void reparse() {
propagateProblems();
if ( completeParse ) return;
boolean newCompleteParse = isComplete(compilationUnitDeclaration);
if ( !newCompleteParse ) return;
- Map<ASTNode, Node> oldMap = nodeMap;
- nodeMap = new HashMap<ASTNode, Node>();
- this.top = buildTree(compilationUnitDeclaration);
+ Map<ASTNode, AST<ASTNode>.Node> oldMap = getNodeMap();
+ clearState();
+ setTop(buildCompilationUnit(compilationUnitDeclaration));
//Retain 'handled' flags.
- for ( Map.Entry<ASTNode, Node> e : nodeMap.entrySet() ) {
- Node oldEntry = oldMap.get(e.getKey());
- if ( oldEntry != null && oldEntry.handled ) e.getValue().handled = true;
+ for ( Map.Entry<ASTNode, AST<ASTNode>.Node> e : getNodeMap().entrySet() ) {
+ Node oldEntry = (Node) oldMap.get(e.getKey());
+ if ( oldEntry != null && oldEntry.isHandled() ) e.getValue().setHandled();
}
this.completeParse = true;
@@ -283,44 +280,36 @@ public class EclipseAST {
return (unit.bits & ASTNode.HasAllMethodBodies) > 0;
}
- private Node putInMap(Node parent) {
- for ( Node child : parent.children ) child.parent = parent;
- nodeMap.put(parent.node, parent);
- identityDetector.put(parent.node, null);
- return parent;
- }
-
- private Node buildTree(CompilationUnitDeclaration top) {
- identityDetector.clear();
- Collection<Node> children = buildTree(top.types);
- return putInMap(new Node(top, children));
+ private Node buildCompilationUnit(CompilationUnitDeclaration top) {
+ Collection<Node> children = buildTypes(top.types);
+ return putInMap(new Node(top, children, Kind.COMPILATION_UNIT));
}
private void addIfNotNull(Collection<Node> collection, Node n) {
if ( n != null ) collection.add(n);
}
- private Collection<Node> buildTree(TypeDeclaration[] children) {
+ private Collection<Node> buildTypes(TypeDeclaration[] children) {
if ( children == null ) return Collections.emptyList();
List<Node> childNodes = new ArrayList<Node>();
- for ( TypeDeclaration type : children ) addIfNotNull(childNodes, buildTree(type));
+ for ( TypeDeclaration type : children ) addIfNotNull(childNodes, buildType(type));
return childNodes;
}
- private Node buildTree(TypeDeclaration type) {
- if ( identityDetector.containsKey(type) ) return null;
+ private Node buildType(TypeDeclaration type) {
+ if ( alreadyHandled(type) ) return null;
List<Node> childNodes = new ArrayList<Node>();
- childNodes.addAll(buildTree(type.fields));
- childNodes.addAll(buildTree(type.memberTypes));
- childNodes.addAll(buildTree(type.methods));
- childNodes.addAll(buildTree(type.annotations));
- return putInMap(new Node(type, childNodes));
+ childNodes.addAll(buildFields(type.fields));
+ childNodes.addAll(buildTypes(type.memberTypes));
+ childNodes.addAll(buildMethods(type.methods));
+ childNodes.addAll(buildAnnotations(type.annotations));
+ return putInMap(new Node(type, childNodes, Kind.TYPE));
}
- private Collection<Node> buildTree(FieldDeclaration[] children) {
+ private Collection<Node> buildFields(FieldDeclaration[] children) {
if ( children == null ) return Collections.emptyList();
List<Node> childNodes = new ArrayList<Node>();
- for ( FieldDeclaration child : children ) addIfNotNull(childNodes, buildTree(child));
+ for ( FieldDeclaration child : children ) addIfNotNull(childNodes, buildField(child));
return childNodes;
}
@@ -329,152 +318,97 @@ public class EclipseAST {
else return Collections.singleton(item);
}
- private Node buildTree(FieldDeclaration field) {
- if ( field instanceof Initializer ) return buildTree((Initializer)field);
- if ( identityDetector.containsKey(field) ) return null;
+ private Node buildField(FieldDeclaration field) {
+ if ( field instanceof Initializer ) return buildInitializer((Initializer)field);
+ if ( alreadyHandled(field) ) return null;
List<Node> childNodes = new ArrayList<Node>();
- addIfNotNull(childNodes, buildWithStatement(field.initialization));
- childNodes.addAll(buildTree(field.annotations));
- return putInMap(new Node(field, childNodes));
+ addIfNotNull(childNodes, buildStatement(field.initialization));
+ childNodes.addAll(buildAnnotations(field.annotations));
+ return putInMap(new Node(field, childNodes, Kind.FIELD));
}
- private Node buildTree(Initializer initializer) {
- if ( identityDetector.containsKey(initializer) ) return null;
- return putInMap(new Node(initializer, singleton(buildWithStatement(initializer.block))));
+ private Node buildInitializer(Initializer initializer) {
+ if ( alreadyHandled(initializer) ) return null;
+ return putInMap(new Node(initializer, singleton(buildStatement(initializer.block)), Kind.INITIALIZER));
}
- private Collection<Node> buildTree(AbstractMethodDeclaration[] children) {
+ private Collection<Node> buildMethods(AbstractMethodDeclaration[] children) {
if ( children == null ) return Collections.emptyList();
List<Node> childNodes = new ArrayList<Node>();
- for (AbstractMethodDeclaration method : children ) addIfNotNull(childNodes, buildTree(method));
+ for (AbstractMethodDeclaration method : children ) addIfNotNull(childNodes, buildMethod(method));
return childNodes;
}
- private Node buildTree(AbstractMethodDeclaration method) {
- if ( identityDetector.containsKey(method) ) return null;
+ private Node buildMethod(AbstractMethodDeclaration method) {
+ if ( alreadyHandled(method) ) return null;
List<Node> childNodes = new ArrayList<Node>();
- childNodes.addAll(buildTree(method.arguments));
- childNodes.addAll(buildTree(method.statements));
- childNodes.addAll(buildTree(method.annotations));
- return putInMap(new Node(method, childNodes));
+ childNodes.addAll(buildArguments(method.arguments));
+ childNodes.addAll(buildStatements(method.statements));
+ childNodes.addAll(buildAnnotations(method.annotations));
+ return putInMap(new Node(method, childNodes, Kind.METHOD));
}
//Arguments are a kind of LocalDeclaration. They can definitely contain lombok annotations, so we care about them.
- private Collection<Node> buildTree(Argument[] children) {
+ private Collection<Node> buildArguments(Argument[] children) {
if ( children == null ) return Collections.emptyList();
List<Node> childNodes = new ArrayList<Node>();
for ( LocalDeclaration local : children ) {
- addIfNotNull(childNodes, buildTree(local));
+ addIfNotNull(childNodes, buildLocal(local));
}
return childNodes;
}
- private Node buildTree(LocalDeclaration local) {
- if ( identityDetector.containsKey(local) ) return null;
+ private Node buildLocal(LocalDeclaration local) {
+ if ( alreadyHandled(local) ) return null;
List<Node> childNodes = new ArrayList<Node>();
- addIfNotNull(childNodes, buildWithStatement(local.initialization));
- childNodes.addAll(buildTree(local.annotations));
- return putInMap(new Node(local, childNodes));
+ addIfNotNull(childNodes, buildStatement(local.initialization));
+ childNodes.addAll(buildAnnotations(local.annotations));
+ return putInMap(new Node(local, childNodes, Kind.LOCAL));
}
- private Collection<Node> buildTree(Annotation[] annotations) {
+ private Collection<Node> buildAnnotations(Annotation[] annotations) {
if ( annotations == null ) return Collections.emptyList();
List<Node> elements = new ArrayList<Node>();
for ( Annotation an : annotations ) {
if ( an == null ) continue;
- elements.add(putInMap(new Node(an, null)));
+ if ( alreadyHandled(an) ) continue;
+ elements.add(putInMap(new Node(an, null, Kind.ANNOTATION)));
}
return elements;
}
- private Collection<Node> buildTree(Statement[] children) {
+ private Collection<Node> buildStatements(Statement[] children) {
if ( children == null ) return Collections.emptyList();
List<Node> childNodes = new ArrayList<Node>();
- for ( Statement child : children ) addIfNotNull(childNodes, buildWithStatement(child));
+ for ( Statement child : children ) addIfNotNull(childNodes, buildStatement(child));
return childNodes;
}
//Almost anything is a statement, so this method has a different name to avoid overloading confusion
- private Node buildWithStatement(Statement child) {
- if ( child == null || identityDetector.containsKey(child) ) return null;
- if ( child instanceof TypeDeclaration ) return buildTree((TypeDeclaration)child);
+ private Node buildStatement(Statement child) {
+ if ( child == null || alreadyHandled(child) ) return null;
+ if ( child instanceof TypeDeclaration ) return buildType((TypeDeclaration)child);
- if ( child instanceof LocalDeclaration ) return buildTree((LocalDeclaration)child);
+ if ( child instanceof LocalDeclaration ) return buildLocal((LocalDeclaration)child);
//We drill down because LocalDeclarations and TypeDeclarations can occur anywhere, even in, say,
//an if block, or even the expression on an assert statement!
- identityDetector.put(child, null);
+ setAsHandled(child);
return drill(child);
}
- private Node drill(Statement statement) {
+ protected Node drill(Statement statement) {
List<Node> childNodes = new ArrayList<Node>();
- for ( FieldAccess fa : fieldsOf(statement.getClass()) ) childNodes.addAll(buildWithField(statement, fa));
- return putInMap(new Node(statement, childNodes));
- }
-
- private static class FieldAccess {
- final Field field;
- final int dim;
-
- FieldAccess(Field field, int dim) {
- this.field = field;
- this.dim = dim;
- }
- }
-
- private static Map<Class<?>, Collection<FieldAccess>> fieldsOfASTClasses = new HashMap<Class<?>, Collection<FieldAccess>>();
- private Collection<FieldAccess> fieldsOf(Class<?> c) {
- Collection<FieldAccess> fields = fieldsOfASTClasses.get(c);
- if ( fields != null ) return fields;
-
- fields = new ArrayList<FieldAccess>();
- getFields(c, fields);
- fieldsOfASTClasses.put(c, fields);
- return fields;
- }
-
- private void getFields(Class<?> c, Collection<FieldAccess> fields) {
- if ( c == ASTNode.class || c == null ) return;
- for ( Field f : c.getDeclaredFields() ) {
- if ( Modifier.isStatic(f.getModifiers()) ) continue;
- Class<?> t = f.getType();
- int dim = 0;
- while ( t.isArray() ) {
- dim++;
- t = t.getComponentType();
- }
- if ( Statement.class.isAssignableFrom(t) ) {
- f.setAccessible(true);
- fields.add(new FieldAccess(f, dim));
- }
- }
- getFields(c.getSuperclass(), fields);
+ for ( FieldAccess fa : fieldsOf(statement.getClass()) ) childNodes.addAll(buildWithField(Node.class, statement, fa));
+ return putInMap(new Node(statement, childNodes, Kind.STATEMENT));
}
- private Collection<Node> buildWithField(Statement statement, FieldAccess fa) {
- List<Node> list = new ArrayList<Node>();
- buildWithField(statement, fa, list);
- return list;
+ @Override protected Collection<Class<? extends ASTNode>> getStatementTypes() {
+ return Collections.<Class<? extends ASTNode>>singleton(Statement.class);
}
- private void buildWithField(Statement child, FieldAccess fa, Collection<Node> list) {
- try {
- Object o = fa.field.get(child);
- if ( fa.dim == 0 ) addIfNotNull(list, buildWithStatement((Statement)o));
- else buildWithArray(o, list, fa.dim);
- } catch ( IllegalAccessException e ) {
- sneakyThrow(e);
- }
- }
-
- private void buildWithArray(Object array, Collection<Node> list, int dim) {
- if ( array == null ) return;
- if ( dim == 1 ) for ( Object v : (Object[])array ) {
- addIfNotNull(list, buildWithStatement((Statement)v));
- } else for ( Object v : (Object[])array ) {
- buildWithArray(v, list, dim-1);
- }
+ @Override protected Node buildStatement(Object node) {
+ return buildStatement((Statement)node);
}
}
diff --git a/src/lombok/eclipse/EclipseASTAdapter.java b/src/lombok/eclipse/EclipseASTAdapter.java
index 1bd5ae3d..61d161d1 100644
--- a/src/lombok/eclipse/EclipseASTAdapter.java
+++ b/src/lombok/eclipse/EclipseASTAdapter.java
@@ -4,6 +4,7 @@ import lombok.eclipse.EclipseAST.Node;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Initializer;
@@ -25,6 +26,9 @@ public abstract class EclipseASTAdapter implements EclipseASTVisitor {
@Override public void visitMethod(Node methodNode, AbstractMethodDeclaration method) {}
@Override public void visitAnnotationOnMethod(AbstractMethodDeclaration method, Node annotationNode, Annotation annotation) {}
@Override public void endVisitMethod(Node methodNode, AbstractMethodDeclaration method) {}
+ @Override public void visitMethodArgument(Node argNode, Argument arg, AbstractMethodDeclaration method) {}
+ @Override public void visitAnnotationOnMethodArgument(Argument arg, AbstractMethodDeclaration method, Node annotationNode, Annotation annotation) {}
+ @Override public void endVisitMethodArgument(Node argNode, Argument arg, AbstractMethodDeclaration method) {}
@Override public void visitLocal(Node localNode, LocalDeclaration local) {}
@Override public void visitAnnotationOnLocal(LocalDeclaration local, Node annotationNode, Annotation annotation) {}
@Override public void endVisitLocal(Node localNode, LocalDeclaration local) {}
diff --git a/src/lombok/eclipse/EclipseASTVisitor.java b/src/lombok/eclipse/EclipseASTVisitor.java
index 9ab56ebe..0c55d222 100644
--- a/src/lombok/eclipse/EclipseASTVisitor.java
+++ b/src/lombok/eclipse/EclipseASTVisitor.java
@@ -60,8 +60,14 @@ public interface EclipseASTVisitor {
void endVisitMethod(Node methodNode, AbstractMethodDeclaration method);
/**
- * Visits a local declaration - that is, something like 'int x = 10;' on the method level. Also called
- * for method parameter (those would be Arguments, a subclass of LocalDeclaration).
+ * Visits a method argument
+ */
+ void visitMethodArgument(Node argNode, Argument arg, AbstractMethodDeclaration method);
+ void visitAnnotationOnMethodArgument(Argument arg, AbstractMethodDeclaration method, Node annotationNode, Annotation annotation);
+ void endVisitMethodArgument(Node argNode, Argument arg, AbstractMethodDeclaration method);
+
+ /**
+ * Visits a local declaration - that is, something like 'int x = 10;' on the method level.
*/
void visitLocal(Node localNode, LocalDeclaration local);
void visitAnnotationOnLocal(LocalDeclaration local, Node annotationNode, Annotation annotation);
@@ -69,8 +75,6 @@ public interface EclipseASTVisitor {
/**
* Visits a statement that isn't any of the other visit methods (e.g. TypeDeclaration).
- * @param node
- * @param statement
*/
void visitStatement(Node statementNode, Statement statement);
void endVisitStatement(Node statementNode, Statement statement);
@@ -171,9 +175,22 @@ public interface EclipseASTVisitor {
print("</%s %s>", type, str(method.selector));
}
+ @Override public void visitMethodArgument(Node node, Argument arg, AbstractMethodDeclaration method) {
+ print("<METHODARG %s %s = %s>", str(arg.type), str(arg.name), arg.initialization);
+ indent++;
+ }
+
+ @Override public void visitAnnotationOnMethodArgument(Argument arg, AbstractMethodDeclaration method, Node node, Annotation annotation) {
+ print("<ANNOTATION: %s />", annotation);
+ }
+
+ @Override public void endVisitMethodArgument(Node node, Argument arg, AbstractMethodDeclaration method) {
+ indent--;
+ print("</METHODARG %s %s>", str(arg.type), str(arg.name));
+ }
+
@Override public void visitLocal(Node node, LocalDeclaration local) {
- String type = local instanceof Argument ? "ARGUMENT" : "LOCAL";
- print("<%s %s %s = %s>", type, str(local.type), str(local.name), local.initialization);
+ print("<LOCAL %s %s = %s>", str(local.type), str(local.name), local.initialization);
indent++;
}
@@ -182,9 +199,8 @@ public interface EclipseASTVisitor {
}
@Override public void endVisitLocal(Node node, LocalDeclaration local) {
- String type = local instanceof Argument ? "ARGUMENT" : "LOCAL";
indent--;
- print("</%s %s %s>", type, str(local.type), str(local.name));
+ print("</LOCAL %s %s>", str(local.type), str(local.name));
}
@Override public void visitStatement(Node node, Statement statement) {
diff --git a/src/lombok/eclipse/EclipseAnnotationHandler.java b/src/lombok/eclipse/EclipseAnnotationHandler.java
index c6cc23be..816ba61c 100644
--- a/src/lombok/eclipse/EclipseAnnotationHandler.java
+++ b/src/lombok/eclipse/EclipseAnnotationHandler.java
@@ -1,5 +1,7 @@
package lombok.eclipse;
+import lombok.core.AnnotationValues;
+
public interface EclipseAnnotationHandler<T extends java.lang.annotation.Annotation> {
- void handle(T annotation, org.eclipse.jdt.internal.compiler.ast.Annotation ast, EclipseAST.Node annotationNode);
+ void handle(AnnotationValues<T> annotation, org.eclipse.jdt.internal.compiler.ast.Annotation ast, EclipseAST.Node annotationNode);
}
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();