From eebc3450e4272688e09d1eadbaa61ea171fff1f7 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 15 Jun 2009 22:32:44 +0200 Subject: 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. --- src/lombok/eclipse/EclipseAST.java | 92 +++++++++++++++++++---------- src/lombok/eclipse/EclipseASTAdapter.java | 3 + src/lombok/eclipse/EclipseASTVisitor.java | 19 ++++++ src/lombok/eclipse/TransformEclipseAST.java | 1 + 4 files changed, 85 insertions(+), 30 deletions(-) (limited to 'src/lombok/eclipse') diff --git a/src/lombok/eclipse/EclipseAST.java b/src/lombok/eclipse/EclipseAST.java index 8730849b..5450a9a9 100644 --- a/src/lombok/eclipse/EclipseAST.java +++ b/src/lombok/eclipse/EclipseAST.java @@ -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 children; boolean handled; + private final boolean isStructurallySignificant; Node(ASTNode node, Collection children) { this.node = node; this.children = children == null ? Collections.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 Collection 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 buildTree(AbstractMethodDeclaration[] children) { @@ -305,52 +348,40 @@ public class EclipseAST { if ( children == null ) return Collections.emptyList(); List childNodes = new ArrayList(); 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 buildTree(Statement[] children) { if ( children == null ) return Collections.emptyList(); List childNodes = new ArrayList(); - 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 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.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 childNodes = new ArrayList(); - 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 drill(Statement child) { + private Node drill(Statement statement) { List childNodes = new ArrayList(); - 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, Collection> fieldsOfASTClasses = new HashMap, Collection>(); private Collection fieldsOf(Class c) { Collection fields = fieldsOfASTClasses.get(c); @@ -376,6 +408,7 @@ public class EclipseAST { private void getFields(Class c, Collection 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 buildWithField(Statement child, FieldAccess fa) { - if ( Modifier.isStatic(fa.field.getModifiers()) ) return Collections.emptyList(); + private Collection buildWithField(Statement statement, FieldAccess fa) { List list = new ArrayList(); - buildWithField(child, fa, list); + buildWithField(statement, fa, list); return list; } private void buildWithField(Statement child, FieldAccess fa, Collection 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 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); } diff --git a/src/lombok/eclipse/EclipseASTAdapter.java b/src/lombok/eclipse/EclipseASTAdapter.java index a76380cf..50fded89 100644 --- a/src/lombok/eclipse/EclipseASTAdapter.java +++ b/src/lombok/eclipse/EclipseASTAdapter.java @@ -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) {} } diff --git a/src/lombok/eclipse/EclipseASTVisitor.java b/src/lombok/eclipse/EclipseASTVisitor.java index aff1cc38..ac4d0e33 100644 --- a/src/lombok/eclipse/EclipseASTVisitor.java +++ b/src/lombok/eclipse/EclipseASTVisitor.java @@ -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("", 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("", statement.getClass()); + } } } diff --git a/src/lombok/eclipse/TransformEclipseAST.java b/src/lombok/eclipse/TransformEclipseAST.java index c9690953..f606733c 100644 --- a/src/lombok/eclipse/TransformEclipseAST.java +++ b/src/lombok/eclipse/TransformEclipseAST.java @@ -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); } -- cgit