mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 18:15:55 +00:00
all eclipse AST Statements objects are now part of the custom AST we build for lombok.
This way something like @AutoClose on a local var declaration can walk up one node, find all mentions of the variable, and add a close call right after the last mention.
This commit is contained in:
1 parent
d2ffd52636
commit
eebc3450e4
4 files changed
+85
-30
No files matched your search
@@ -60,6 +60,10 @@ public class EclipseAST {
|
||||
visitor.visitLocal(child, (LocalDeclaration)n);
|
||||
traverseChildren(visitor, child);
|
||||
visitor.endVisitLocal(child, (LocalDeclaration)n);
|
||||
} else if ( n instanceof Statement ) {
|
||||
visitor.visitStatement(child, (Statement)n);
|
||||
traverseChildren(visitor, child);
|
||||
visitor.endVisitStatement(node, (Statement)n);
|
||||
} else throw new AssertionError("Can't be reached");
|
||||
}
|
||||
}
|
||||
@@ -142,10 +146,12 @@ public class EclipseAST {
|
||||
Node parent;
|
||||
final Collection<Node> children;
|
||||
boolean handled;
|
||||
private final boolean isStructurallySignificant;
|
||||
|
||||
Node(ASTNode node, Collection<Node> children) {
|
||||
this.node = node;
|
||||
this.children = children == null ? Collections.<Node>emptyList() : children;
|
||||
this.isStructurallySignificant = calculateIsStructurallySignificant();
|
||||
}
|
||||
|
||||
public void addError(String message) {
|
||||
@@ -168,7 +174,39 @@ public class EclipseAST {
|
||||
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;
|
||||
}
|
||||
|
||||
private boolean calculateIsStructurallySignificant() {
|
||||
if ( node instanceof TypeDeclaration ) return true;
|
||||
if ( node instanceof AbstractMethodDeclaration ) return true;
|
||||
if ( node instanceof FieldDeclaration ) return true;
|
||||
if ( node instanceof LocalDeclaration ) return true;
|
||||
if ( node instanceof CompilationUnitDeclaration ) return true;
|
||||
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.
|
||||
*/
|
||||
public Node directUp() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@@ -274,15 +312,20 @@ public class EclipseAST {
|
||||
return childNodes;
|
||||
}
|
||||
|
||||
private static <T> Collection<T> singleton(T item) {
|
||||
if ( item == null ) return Collections.emptyList();
|
||||
else return Collections.singleton(item);
|
||||
}
|
||||
|
||||
private Node buildTree(FieldDeclaration field) {
|
||||
if ( field instanceof Initializer ) return buildTree((Initializer)field);
|
||||
if ( identityDetector.containsKey(field) ) return null;
|
||||
return putInMap(new Node(field, buildWithStatement(field.initialization)));
|
||||
return putInMap(new Node(field, singleton(buildWithStatement(field.initialization))));
|
||||
}
|
||||
|
||||
private Node buildTree(Initializer initializer) {
|
||||
if ( identityDetector.containsKey(initializer) ) return null;
|
||||
return putInMap(new Node(initializer, buildWithStatement(initializer.block)));
|
||||
return putInMap(new Node(initializer, singleton(buildWithStatement(initializer.block))));
|
||||
}
|
||||
|
||||
private Collection<Node> buildTree(AbstractMethodDeclaration[] children) {
|
||||
@@ -305,52 +348,40 @@ public class EclipseAST {
|
||||
if ( children == null ) return Collections.emptyList();
|
||||
List<Node> childNodes = new ArrayList<Node>();
|
||||
for ( LocalDeclaration local : children ) {
|
||||
if ( !identityDetector.containsKey(local) ) {
|
||||
addIfNotNull(childNodes, buildTree(local));
|
||||
childNodes.addAll(buildWithStatement(local.initialization));
|
||||
}
|
||||
addIfNotNull(childNodes, buildTree(local));
|
||||
}
|
||||
return childNodes;
|
||||
}
|
||||
|
||||
private Node buildTree(LocalDeclaration local) {
|
||||
if ( identityDetector.containsKey(local) ) return null;
|
||||
return putInMap(new Node(local, null));
|
||||
return putInMap(new Node(local, singleton(buildWithStatement(local.initialization))));
|
||||
}
|
||||
|
||||
private Collection<Node> buildTree(Statement[] children) {
|
||||
if ( children == null ) return Collections.emptyList();
|
||||
List<Node> childNodes = new ArrayList<Node>();
|
||||
for ( Statement child : children ) childNodes.addAll(buildWithStatement(child));
|
||||
for ( Statement child : children ) addIfNotNull(childNodes, buildWithStatement(child));
|
||||
return childNodes;
|
||||
}
|
||||
|
||||
//Almost anything is a statement, so this method has a different name to avoid overloading confusion
|
||||
private Collection<Node> buildWithStatement(Statement child) {
|
||||
if ( child == null || identityDetector.containsKey(child) ) return Collections.emptyList();
|
||||
if ( child instanceof TypeDeclaration ) {
|
||||
Node n = buildTree((TypeDeclaration)child);
|
||||
return n == null ? Collections.<Node>emptyList() : Collections.singleton(n);
|
||||
}
|
||||
private Node buildWithStatement(Statement child) {
|
||||
if ( child == null || identityDetector.containsKey(child) ) return null;
|
||||
if ( child instanceof TypeDeclaration ) return buildTree((TypeDeclaration)child);
|
||||
|
||||
if ( child instanceof LocalDeclaration ) return buildTree((LocalDeclaration)child);
|
||||
|
||||
if ( child instanceof LocalDeclaration ) {
|
||||
List<Node> childNodes = new ArrayList<Node>();
|
||||
addIfNotNull(childNodes, buildTree((LocalDeclaration)child));
|
||||
identityDetector.put(child, null);
|
||||
childNodes.addAll(buildWithStatement(((LocalDeclaration)child).initialization));
|
||||
return childNodes;
|
||||
}
|
||||
//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);
|
||||
return drill(child);
|
||||
}
|
||||
|
||||
private Collection<Node> drill(Statement child) {
|
||||
private Node drill(Statement statement) {
|
||||
List<Node> childNodes = new ArrayList<Node>();
|
||||
for ( FieldAccess fa : fieldsOf(child.getClass()) ) childNodes.addAll(buildWithField(child, fa));
|
||||
return childNodes;
|
||||
for ( FieldAccess fa : fieldsOf(statement.getClass()) ) childNodes.addAll(buildWithField(statement, fa));
|
||||
return new Node(statement, childNodes);
|
||||
}
|
||||
|
||||
private static class FieldAccess {
|
||||
@@ -362,6 +393,7 @@ public class EclipseAST {
|
||||
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);
|
||||
@@ -376,6 +408,7 @@ public class EclipseAST {
|
||||
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() ) {
|
||||
@@ -390,17 +423,16 @@ public class EclipseAST {
|
||||
getFields(c.getSuperclass(), fields);
|
||||
}
|
||||
|
||||
private Collection<Node> buildWithField(Statement child, FieldAccess fa) {
|
||||
if ( Modifier.isStatic(fa.field.getModifiers()) ) return Collections.emptyList();
|
||||
private Collection<Node> buildWithField(Statement statement, FieldAccess fa) {
|
||||
List<Node> list = new ArrayList<Node>();
|
||||
buildWithField(child, fa, list);
|
||||
buildWithField(statement, fa, list);
|
||||
return list;
|
||||
}
|
||||
|
||||
private void buildWithField(Statement child, FieldAccess fa, Collection<Node> list) {
|
||||
try {
|
||||
Object o = fa.field.get(child);
|
||||
if ( fa.dim == 0 ) list.addAll(buildWithStatement((Statement)o));
|
||||
if ( fa.dim == 0 ) addIfNotNull(list, buildWithStatement((Statement)o));
|
||||
else buildWithArray(o, list, fa.dim);
|
||||
} catch ( IllegalAccessException e ) {
|
||||
sneakyThrow(e);
|
||||
@@ -410,7 +442,7 @@ public class EclipseAST {
|
||||
private void buildWithArray(Object array, Collection<Node> list, int dim) {
|
||||
if ( array == null ) return;
|
||||
if ( dim == 1 ) for ( Object v : (Object[])array ) {
|
||||
list.addAll(buildWithStatement((Statement)v));
|
||||
addIfNotNull(list, buildWithStatement((Statement)v));
|
||||
} else for ( Object v : (Object[])array ) {
|
||||
buildWithArray(v, list, dim-1);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Initializer;
|
||||
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
|
||||
|
||||
public abstract class EclipseASTAdapter implements EclipseASTVisitor {
|
||||
@@ -22,4 +23,6 @@ public abstract class EclipseASTAdapter implements EclipseASTVisitor {
|
||||
@Override public void endVisitMethod(Node node, AbstractMethodDeclaration method) {}
|
||||
@Override public void visitLocal(Node node, LocalDeclaration local) {}
|
||||
@Override public void endVisitLocal(Node node, LocalDeclaration local) {}
|
||||
@Override public void visitStatement(Node node, Statement statement) {}
|
||||
@Override public void endVisitStatement(Node node, Statement statement) {}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Initializer;
|
||||
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
|
||||
@@ -60,6 +61,14 @@ public interface EclipseASTVisitor {
|
||||
void visitLocal(Node node, LocalDeclaration declaration);
|
||||
void endVisitLocal(Node node, LocalDeclaration declaration);
|
||||
|
||||
/**
|
||||
* Visits a statement that isn't any of the other visit methods (e.g. TypeDeclaration).
|
||||
* @param node
|
||||
* @param statement
|
||||
*/
|
||||
void visitStatement(Node node, Statement statement);
|
||||
void endVisitStatement(Node node, Statement statement);
|
||||
|
||||
public static class EclipseASTPrinter implements EclipseASTVisitor {
|
||||
int indent = 0;
|
||||
private void print(String text, Object... params) {
|
||||
@@ -155,5 +164,15 @@ public interface EclipseASTVisitor {
|
||||
indent--;
|
||||
print("</%s %s %s>", type, str(local.type), str(local.name));
|
||||
}
|
||||
|
||||
@Override public void visitStatement(Node node, Statement statement) {
|
||||
print("<%s>", statement.getClass());
|
||||
indent++;
|
||||
}
|
||||
|
||||
@Override public void endVisitStatement(Node node, Statement statement) {
|
||||
indent--;
|
||||
print("</%s>", statement.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,6 +77,7 @@ public class TransformEclipseAST {
|
||||
String message = "Lombok can't parse this source: " + t.toString();
|
||||
|
||||
EclipseAST.addProblemToCompilationResult(fileName, ast, false, message, ast, 0, 0);
|
||||
t.printStackTrace();
|
||||
} catch ( Throwable t2 ) {
|
||||
Eclipse.error("Can't create an error in the problems dialog while adding: " + t.toString(), t2);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user