aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/javac-source.zipbin0 -> 1839929 bytes
-rw-r--r--src/lombok/core/AST.java268
-rw-r--r--src/lombok/core/AnnotationValues.java281
-rw-r--r--src/lombok/core/TypeResolver.java (renamed from src/lombok/eclipse/TypeResolver.java)53
-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/handlers/HandleGetter_ecj.java11
-rw-r--r--src/lombok/javac/HandlerLibrary.java227
-rw-r--r--src/lombok/javac/JavacAST.java329
-rw-r--r--src/lombok/javac/JavacASTAdapter.java35
-rw-r--r--src/lombok/javac/JavacASTVisitor.java182
-rw-r--r--src/lombok/javac/JavacAnnotationHandler.java6
-rw-r--r--src/lombok/javac/JavacNode.java63
-rw-r--r--src/lombok/javac/apt/Processor.java66
-rw-r--r--src/lombok/javac/handlers/HandleGetter_javac.java27
-rw-r--r--src/lombok/javac/handlers/PKG.java9
21 files changed, 1565 insertions, 714 deletions
diff --git a/contrib/javac-source.zip b/contrib/javac-source.zip
new file mode 100644
index 00000000..7d989ac6
--- /dev/null
+++ b/contrib/javac-source.zip
Binary files differ
diff --git a/src/lombok/core/AST.java b/src/lombok/core/AST.java
new file mode 100644
index 00000000..99902672
--- /dev/null
+++ b/src/lombok/core/AST.java
@@ -0,0 +1,268 @@
+package lombok.core;
+
+import static lombok.Lombok.sneakyThrow;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+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;
+
+public abstract class AST<N> {
+ public enum Kind {
+ COMPILATION_UNIT, TYPE, FIELD, INITIALIZER, METHOD, ANNOTATION, ARGUMENT, LOCAL, STATEMENT;
+ }
+
+ private Node top;
+ private final String fileName;
+ private Map<N, Void> identityDetector = new IdentityHashMap<N, Void>();
+ private Map<N, Node> nodeMap = new IdentityHashMap<N, Node>();
+
+ protected AST(String fileName) {
+ this.fileName = fileName == null ? "(unknown).java" : fileName;
+ }
+
+ protected void setTop(Node top) {
+ this.top = top;
+ }
+
+ public abstract String getPackageDeclaration();
+
+ public abstract Collection<String> getImportStatements();
+
+ protected <T extends Node> T putInMap(T parent) {
+ nodeMap.put(parent.get(), parent);
+ identityDetector.put(parent.get(), null);
+ return parent;
+ }
+
+ protected Map<N, Node> getNodeMap() {
+ return nodeMap;
+ }
+
+ protected void clearState() {
+ identityDetector = new IdentityHashMap<N, Void>();
+ nodeMap = new IdentityHashMap<N, Node>();
+ }
+
+ protected boolean alreadyHandled(N node) {
+ return identityDetector.containsKey(node);
+ }
+
+ protected void setAsHandled(N node) {
+ identityDetector.put(node, null);
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public Node top() {
+ return top;
+ }
+
+ public Node get(N node) {
+ return nodeMap.get(node);
+ }
+
+ public abstract class Node {
+ protected final Kind kind;
+ protected final N node;
+ protected final Collection<? extends Node> children;
+ protected Node parent;
+ protected boolean handled;
+ protected boolean isStructurallySignificant;
+
+ protected Node(N node, Collection<? extends Node> children, Kind kind) {
+ this.kind = kind;
+ this.node = node;
+ this.children = children == null ? Collections.<Node>emptyList() : children;
+ for ( Node child : this.children ) child.parent = this;
+ this.isStructurallySignificant = calculateIsStructurallySignificant();
+ }
+
+ public String getPackageDeclaration() {
+ return AST.this.getPackageDeclaration();
+ }
+
+ public Collection<String> getImportStatements() {
+ return AST.this.getImportStatements();
+ }
+
+ protected abstract boolean calculateIsStructurallySignificant();
+
+ public N get() {
+ return node;
+ }
+
+ public Kind getKind() {
+ return kind;
+ }
+
+ /**
+ * Return the name of your type (simple name), method, field, or local variable. Return null if this
+ * node doesn't really have a name, such as initializers, while statements, etc.
+ */
+ public abstract String getName();
+
+ /** Returns the structurally significant node that encloses this one.
+ *
+ * @see #isStructurallySignificant()
+ */
+ public Node up() {
+ Node result = (Node)parent;
+ while ( result != null && !result.isStructurallySignificant ) result = (Node)result.parent;
+ return result;
+ }
+
+ /**
+ * 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.
+ */
+ public Node directUp() {
+ return parent;
+ }
+
+ public Collection<? extends Node> down() {
+ return children;
+ }
+
+ public boolean isHandled() {
+ return handled;
+ }
+
+ public Node setHandled() {
+ this.handled = true;
+ return this;
+ }
+
+ public Node top() {
+ return top;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public abstract void addError(String message);
+
+ public abstract void addWarning(String message);
+
+ /**
+ * 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;
+ }
+ }
+
+ protected static class FieldAccess {
+ public final Field field;
+ public 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>>();
+ protected 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 == Object.class || c == null ) return;
+ for ( Field f : c.getDeclaredFields() ) {
+ if ( Modifier.isStatic(f.getModifiers()) ) continue;
+ Class<?> t = f.getType();
+ int dim = 0;
+
+ if ( t.isArray() ) {
+ while ( t.isArray() ) {
+ dim++;
+ t = t.getComponentType();
+ }
+ } else if ( Collection.class.isAssignableFrom(t) ) {
+ while ( Collection.class.isAssignableFrom(t) ) {
+ dim++;
+ t = getComponentType(f.getGenericType());
+ }
+ }
+
+ for ( Class<?> statementType : getStatementTypes() ) {
+ if ( statementType.isAssignableFrom(t) ) {
+ f.setAccessible(true);
+ fields.add(new FieldAccess(f, dim));
+ break;
+ }
+ }
+ }
+ getFields(c.getSuperclass(), fields);
+ }
+
+ private Class<?> getComponentType(Type type) {
+ if ( type instanceof ParameterizedType ) {
+ Type component = ((ParameterizedType)type).getActualTypeArguments()[0];
+ return component instanceof Class<?> ? (Class<?>)component : Object.class;
+ } else return Object.class;
+ }
+
+ protected abstract Collection<Class<? extends N>> getStatementTypes();
+
+ protected <T extends Node> Collection<T> buildWithField(Class<T> nodeType, N statement, FieldAccess fa) {
+ List<T> list = new ArrayList<T>();
+ buildWithField0(nodeType, statement, fa, list);
+ return list;
+ }
+
+ private <T extends Node> void buildWithField0(Class<T> nodeType, N child, FieldAccess fa, Collection<T> list) {
+ try {
+ Object o = fa.field.get(child);
+ if ( o == null ) return;
+ if ( fa.dim == 0 ) {
+ Node node = buildStatement(o);
+ if ( node != null ) list.add(nodeType.cast(node));
+ } else if ( o.getClass().isArray() ) buildWithArray(nodeType, o, list, fa.dim);
+ else if ( Collection.class.isInstance(o) ) buildWithCollection(nodeType, o, list, fa.dim);
+ } catch ( IllegalAccessException e ) {
+ sneakyThrow(e);
+ }
+ }
+
+ private <T extends Node> void buildWithArray(Class<T> nodeType, Object array, Collection<T> list, int dim) {
+ if ( dim == 1 ) for ( Object v : (Object[])array ) {
+ if ( v == null ) continue;
+ Node node = buildStatement(v);
+ if ( node != null ) list.add(nodeType.cast(node));
+ } else for ( Object v : (Object[])array ) {
+ buildWithArray(nodeType, v, list, dim-1);
+ }
+ }
+
+ private <T extends Node> void buildWithCollection(Class<T> nodeType, Object collection, Collection<T> list, int dim) {
+ if ( dim == 1 ) for ( Object v : (Collection<?>)collection ) {
+ if ( v == null ) continue;
+ Node node = buildStatement(v);
+ if ( node != null ) list.add(nodeType.cast(node));
+ } else for ( Object v : (Collection<?>)collection ) {
+ buildWithCollection(nodeType, v, list, dim-1);
+ }
+ }
+
+ protected abstract Node buildStatement(Object statement);
+}
diff --git a/src/lombok/core/AnnotationValues.java b/src/lombok/core/AnnotationValues.java
new file mode 100644
index 00000000..ec17e34f
--- /dev/null
+++ b/src/lombok/core/AnnotationValues.java
@@ -0,0 +1,281 @@
+package lombok.core;
+
+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.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class AnnotationValues<A extends Annotation> {
+ private final Class<A> type;
+ private final Map<String, AnnotationValue> values;
+ private final AST<?>.Node ast;
+
+ public static class AnnotationValue {
+ public final List<String> raws;
+ public final List<Object> valueGuesses;
+ private final AST<?>.Node node;
+
+ /**
+ * 'raw' should be the exact expression, for example '5+7', 'AccessLevel.PUBLIC', or 'int.class'.
+ * 'valueGuess' should be a likely guess at the real value intended.
+ *
+ * For classes, supply the class name (qualified or not) as a string.<br />
+ * For enums, supply the simple name part (everything after the last dot) as a string.<br />
+ */
+ public AnnotationValue(AST<?>.Node node, String raw, Object valueGuess) {
+ this.node = node;
+ this.raws = Collections.singletonList(raw);
+ this.valueGuesses = Collections.singletonList(valueGuess);
+ }
+
+ /** When the value is an array type. */
+ public AnnotationValue(AST<?>.Node node, List<String> raws, List<Object> valueGuesses) {
+ this.node = node;
+ this.raws = raws;
+ this.valueGuesses = valueGuesses;
+ }
+
+ /**
+ * Override this if you want more specific behaviour (e.g. get the source position just right).
+ *
+ * @param message English message with the problem.
+ * @param valueIdx The index into the values for this annotation key that caused the problem.
+ * -1 for a problem that applies to all values, otherwise the 0-based index into an array of values.
+ * If there is no array for this value (e.g. value=1 instead of value={1,2}), then always -1 or 0.
+ */
+ public void setError(String message, int valueIdx) {
+ node.addError(message);
+ }
+ }
+
+ public AnnotationValues(Class<A> type, Map<String, AnnotationValue> values, AST<?>.Node ast) {
+ this.type = type;
+ this.values = values;
+ this.ast = ast;
+ }
+
+ public static class AnnotationValueDecodeFail extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public final int idx;
+ public final AnnotationValue owner;
+
+ public AnnotationValueDecodeFail(AnnotationValue owner, String msg, int idx) {
+ super(msg);
+ this.idx = idx;
+ this.owner = owner;
+ }
+ }
+
+ private static AnnotationValueDecodeFail makeNoDefaultFail(AnnotationValue owner, Method method) {
+ return new AnnotationValueDecodeFail(owner,
+ "No value supplied but " + method.getName() + " has no default either.", -1);
+ }
+
+ @SuppressWarnings("unchecked")
+ public A getInstance() throws AnnotationValueDecodeFail {
+ InvocationHandler invocations = new InvocationHandler() {
+ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ AnnotationValue v = values.get(method.getName());
+ if ( v == null ) {
+ Object defaultValue = method.getDefaultValue();
+ if ( defaultValue != null ) return defaultValue;
+ throw makeNoDefaultFail(v, method);
+ }
+
+ boolean isArray = false;
+ Class<?> expected = method.getReturnType();
+ Object array = null;
+ if ( expected.isArray() ) {
+ isArray = true;
+ expected = expected.getComponentType();
+ array = Array.newInstance(expected, 1);
+ }
+
+ if ( !isArray && v.valueGuesses.size() > 1 ) {
+ System.out.println(v.valueGuesses.size() + ": " + v.valueGuesses);
+ throw new AnnotationValueDecodeFail(v,
+ "Expected a single value, but " + method.getName() + " has an array of values", -1);
+ }
+
+ if ( v.valueGuesses.size() == 0 && !isArray ) {
+ Object defaultValue = method.getDefaultValue();
+ if ( defaultValue == null ) throw makeNoDefaultFail(v, method);
+ return defaultValue;
+ }
+
+ int idx = 0;
+ for ( Object guess : v.valueGuesses ) {
+ Object result = guess == null ? null : guessToType(guess, expected, v, idx);
+ if ( !isArray ) {
+ if ( result == null ) {
+ Object defaultValue = method.getDefaultValue();
+ if ( defaultValue == null ) throw makeNoDefaultFail(v, method);
+ return defaultValue;
+ } else return result;
+ } else {
+ if ( result == null ) {
+ if ( v.valueGuesses.size() == 1 ) {
+ Object defaultValue = method.getDefaultValue();
+ if ( defaultValue == null ) throw makeNoDefaultFail(v, method);
+ return defaultValue;
+ } else throw new AnnotationValueDecodeFail(v,
+ "I can't make sense of this annotation value. Try using a fully qualified literal.", idx);
+ }
+ Array.set(array, idx++, result);
+ }
+ }
+
+ return array;
+ }
+ };
+
+ return (A) Proxy.newProxyInstance(type.getClassLoader(), new Class[] { type }, invocations);
+ }
+
+ private Object guessToType(Object guess, Class<?> expected, AnnotationValue v, int pos) {
+ if ( expected == int.class ) {
+ if ( guess instanceof Integer || guess instanceof Short || guess instanceof Byte ) {
+ return ((Number)guess).intValue();
+ }
+ }
+
+ if ( expected == long.class ) {
+ if ( guess instanceof Long || guess instanceof Integer || guess instanceof Short || guess instanceof Byte ) {
+ return ((Number)guess).longValue();
+ }
+ }
+
+ if ( expected == short.class ) {
+ if ( guess instanceof Integer || guess instanceof Short || guess instanceof Byte ) {
+ int intVal = ((Number)guess).intValue();
+ int shortVal = ((Number)guess).shortValue();
+ if ( shortVal == intVal ) return shortVal;
+ }
+ }
+
+ if ( expected == byte.class ) {
+ if ( guess instanceof Integer || guess instanceof Short || guess instanceof Byte ) {
+ int intVal = ((Number)guess).intValue();
+ int byteVal = ((Number)guess).byteValue();
+ if ( byteVal == intVal ) return byteVal;
+ }
+ }
+
+ if ( expected == double.class ) {
+ if ( guess instanceof Number ) return ((Number)guess).doubleValue();
+ }
+
+ if ( expected == float.class ) {
+ if ( guess instanceof Number ) return ((Number)guess).floatValue();
+ }
+
+ if ( expected == boolean.class ) {
+ if ( guess instanceof Boolean ) return ((Boolean)guess).booleanValue();
+ }
+
+ if ( expected == char.class ) {
+ if ( guess instanceof Character ) return ((Character)guess).charValue();
+ }
+
+ if ( expected == String.class ) {
+ if ( guess instanceof String ) return expected;
+ }
+
+ if ( Enum.class.isAssignableFrom(expected) ) {
+ if ( guess instanceof String ) {
+ for ( Object enumConstant : expected.getEnumConstants() ) {
+ String target = ((Enum<?>)enumConstant).name();
+ if ( target.equals(guess) ) return enumConstant;
+ }
+ throw new AnnotationValueDecodeFail(v,
+ "Can't translate " + guess + " to an enum of type " + expected, pos);
+ }
+ }
+
+ if ( Class.class == expected ) {
+ if ( guess instanceof String ) try {
+ return Class.forName(toFQ((String)guess));
+ } catch ( ClassNotFoundException e ) {
+ throw new AnnotationValueDecodeFail(v,
+ "Can't translate " + guess + " to a class object.", pos);
+ }
+ }
+
+ throw new AnnotationValueDecodeFail(v,
+ "Can't translate a " + guess.getClass() + " to the expected " + expected, pos);
+ }
+
+ public List<String> getRawExpressions(String annotationMethodName) {
+ AnnotationValue v = values.get(annotationMethodName);
+ return v == null ? Collections.<String>emptyList() : v.raws;
+ }
+
+ public String getRawExpression(String annotationMethodName) {
+ List<String> l = getRawExpressions(annotationMethodName);
+ return l.isEmpty() ? null : l.get(0);
+ }
+
+ public List<String> getProbableFQTypes(String annotationMethodName) {
+ List<String> result = new ArrayList<String>();
+ AnnotationValue v = values.get(annotationMethodName);
+ if ( v == null ) return Collections.emptyList();
+
+ for ( Object o : v.valueGuesses ) result.add(o == null ? null : toFQ(o.toString()));
+ return result;
+ }
+
+ private String toFQ(String typeName) {
+ Class<?> c;
+ boolean fqn = typeName.indexOf('.') > -1;
+ String prefix = fqn ? typeName.substring(0, typeName.indexOf('.')) : typeName;
+
+ for ( String im : ast.getImportStatements() ) {
+ int idx = im.lastIndexOf('.');
+ String simple = im;
+ if ( idx > -1 ) simple = im.substring(idx+1);
+ if ( simple.equals(prefix) ) {
+ return im + typeName.substring(prefix.length());
+ }
+ }
+
+ c = tryClass(typeName);
+ if ( c != null ) return c.getName();
+
+ c = tryClass("java.lang." + typeName);
+ if ( c != null ) return c.getName();
+
+ //Try star imports
+ for ( String im : ast.getImportStatements() ) {
+ if ( im.endsWith(".*") ) {
+ c = tryClass(im.substring(0, im.length() -1) + typeName);
+ if ( c != null ) return c.getName();
+ }
+ }
+
+ if ( !fqn ) {
+ String pkg = ast.getPackageDeclaration();
+ if ( pkg != null ) return pkg + "." + typeName;
+ }
+
+ return null;
+ }
+
+ private Class<?> tryClass(String name) {
+ try {
+ return Class.forName(name);
+ } catch ( ClassNotFoundException e ) {
+ return null;
+ }
+ }
+
+ public String getProbableFQType(String annotationMethodName) {
+ List<String> l = getProbableFQTypes(annotationMethodName);
+ return l.isEmpty() ? null : l.get(0);
+ }
+}
diff --git a/src/lombok/eclipse/TypeResolver.java b/src/lombok/core/TypeResolver.java
index 41618513..1e356f89 100644
--- a/src/lombok/eclipse/TypeResolver.java
+++ b/src/lombok/core/TypeResolver.java
@@ -1,44 +1,35 @@
-package lombok.eclipse;
+package lombok.core;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-import lombok.core.TypeLibrary;
-import lombok.eclipse.EclipseAST.Node;
-
-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 lombok.core.AST.Kind;
public class TypeResolver {
private final TypeLibrary library;
private Collection<String> imports;
-
- public TypeResolver(TypeLibrary library, EclipseAST.Node top) {
+ public TypeResolver(TypeLibrary library, String packageString, Collection<String> importStrings) {
this.library = library;
- this.imports = makeImportList((CompilationUnitDeclaration) top.getEclipseNode());
+ this.imports = makeImportList(packageString, importStrings);
}
- private static Collection<String> makeImportList(CompilationUnitDeclaration declaration) {
+ private static Collection<String> makeImportList(String packageString, Collection<String> importStrings) {
Set<String> imports = new HashSet<String>();
- if ( declaration.currentPackage != null ) imports.add(toQualifiedName(declaration.currentPackage.getImportName()) + ".*");
- if ( declaration.imports != null ) for ( ImportReference importStatement : declaration.imports ) {
- imports.add(toQualifiedName(importStatement.getImportName()));
- }
+ if ( packageString != null ) imports.add(packageString + ".*");
+ imports.addAll(importStrings == null ? Collections.<String>emptySet() : importStrings);
return imports;
}
- public Collection<String> findTypeMatches(Node context, TypeReference type) {
- Collection<String> potentialMatches = library.findCompatible(toQualifiedName(type.getTypeName()));
+ public Collection<String> findTypeMatches(AST<?>.Node context, String typeRef) {
+ Collection<String> potentialMatches = library.findCompatible(typeRef);
if ( potentialMatches.isEmpty() ) return Collections.emptyList();
- if ( type.getTypeName().length > 1 ) return potentialMatches;
-
- String simpleName = new String(type.getTypeName()[0]);
+ int idx = typeRef.indexOf('.');
+ if ( idx > -1 ) return potentialMatches;
+ String simpleName = typeRef.substring(idx+1);
//If there's an import statement that explicitly imports a 'Getter' that isn't any of our potentials, return no matches.
if ( nameConflictInImportList(simpleName, potentialMatches) ) return Collections.emptyList();
@@ -48,11 +39,11 @@ 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;
+ AST<?>.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();
+ if ( n.getKind() == Kind.TYPE ) {
+ String name = n.getName();
+ if ( name != null && name.equals(simpleName) ) return Collections.emptyList();
}
n = n.up();
}
@@ -65,7 +56,7 @@ public class TypeResolver {
Set<String> results = new HashSet<String>();
for ( String importedType : imports ) {
- Collection<String> reduced = library.findCompatible(importedType);
+ Collection<String> reduced = new HashSet<String>(library.findCompatible(importedType));
reduced.retainAll(potentialMatches);
results.addAll(reduced);
}
@@ -87,14 +78,4 @@ public class TypeResolver {
int idx = typeName.lastIndexOf('.');
return idx == -1 ? typeName : typeName.substring(idx+1);
}
-
- private 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/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(