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 +++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 30 deletions(-) (limited to 'src/lombok/eclipse/EclipseAST.java') 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); } -- cgit