package lombok.eclipse; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintStream; import java.lang.reflect.Modifier; 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.Block; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; 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; //TODO expand javadoc public interface EclipseASTVisitor { /** * Called at the very beginning and end. */ void visitCompilationUnit(Node top, CompilationUnitDeclaration unit); void endVisitCompilationUnit(Node top, CompilationUnitDeclaration unit); /** * Called when visiting a type (a class, interface, annotation, enum, etcetera). */ void visitType(Node typeNode, TypeDeclaration type); void visitAnnotationOnType(TypeDeclaration type, Node annotationNode, Annotation annotation); void endVisitType(Node typeNode, TypeDeclaration type); /** * Called when visiting a field of a class. * Even though in eclipse initializers (both instance and static) are represented as Initializer objects, * which are a subclass of FieldDeclaration, those do NOT result in a call to this method. They result * in a call to the visitInitializer method. */ void visitField(Node fieldNode, FieldDeclaration field); void visitAnnotationOnField(FieldDeclaration field, Node annotationNode, Annotation annotation); void endVisitField(Node fieldNode, FieldDeclaration field); /** * Called for static and instance initializers. You can tell the difference via the modifier flag on the * ASTNode (8 for static, 0 for not static). The content is in the 'block', not in the 'initialization', * which would always be null for an initializer instance. */ void visitInitializer(Node initializerNode, Initializer initializer); void endVisitInitializer(Node initializerNode, Initializer initializer); /** * Called for both methods (MethodDeclaration) and constructors (ConstructorDeclaration), but not for * Clinit objects, which are a vestigial eclipse thing that never contain anything. Static initializers * show up as 'Initializer', in the visitInitializer method, with modifier bit STATIC set. */ void visitMethod(Node methodNode, AbstractMethodDeclaration method); void visitAnnotationOnMethod(AbstractMethodDeclaration method, Node annotationNode, Annotation annotation); void endVisitMethod(Node methodNode, AbstractMethodDeclaration method); /** * 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); void endVisitLocal(Node localNode, LocalDeclaration local); /** * Visits a statement that isn't any of the other visit methods (e.g. TypeDeclaration). */ void visitStatement(Node statementNode, Statement statement); void endVisitStatement(Node statementNode, Statement statement); public static class Printer implements EclipseASTVisitor { private final PrintStream out; public Printer() { this(System.out); } public Printer(File file) throws FileNotFoundException { this(new PrintStream(file)); } public Printer(PrintStream out) { this.out = out; } int indent = 0; private void print(String text, Object... params) { StringBuilder sb = new StringBuilder(); for ( int i = 0 ; i < indent ; i++ ) sb.append(" "); out.printf(sb.append(text).append('\n').toString(), params); out.flush(); } private String str(char[] c) { if ( c == null ) return "(NULL)"; else return new String(c); } private String str(TypeReference type) { if ( type == null ) return "(NULL)"; char[][] c = type.getTypeName(); StringBuilder sb = new StringBuilder(); boolean first = true; for ( char[] d : c ) { sb.append(first ? "" : ".").append(new String(d)); first = false; } return sb.toString(); } @Override public void visitCompilationUnit(Node node, CompilationUnitDeclaration unit) { out.println("---------------------------------------------------------"); out.println(node.isCompleteParse() ? "COMPLETE" : "incomplete"); print("", node.getFileName()); indent++; } @Override public void endVisitCompilationUnit(Node node, CompilationUnitDeclaration unit) { indent--; print(""); } @Override public void visitType(Node node, TypeDeclaration type) { print("", str(type.name)); indent++; } @Override public void visitAnnotationOnType(TypeDeclaration type, Node node, Annotation annotation) { print("", annotation); } @Override public void endVisitType(Node node, TypeDeclaration type) { indent--; print("", str(type.name)); } @Override public void visitInitializer(Node node, Initializer initializer) { Block block = initializer.block; boolean s = (block != null && block.statements != null); print("<%s INITIALIZER: %s>", (initializer.modifiers & Modifier.STATIC) != 0 ? "static" : "instance", s ? "filled" : "blank"); indent++; } @Override public void endVisitInitializer(Node node, Initializer initializer) { indent--; print("", (initializer.modifiers & Modifier.STATIC) != 0 ? "static" : "instance"); } @Override public void visitField(Node node, FieldDeclaration field) { print("", str(field.type), str(field.name), field.initialization); indent++; } @Override public void visitAnnotationOnField(FieldDeclaration field, Node node, Annotation annotation) { print("", annotation); } @Override public void endVisitField(Node node, FieldDeclaration field) { indent--; print("", str(field.type), str(field.name)); } @Override public void visitMethod(Node node, AbstractMethodDeclaration method) { String type = method instanceof ConstructorDeclaration ? "CONSTRUCTOR" : "METHOD"; print("<%s %s: %s>", type, str(method.selector), method.statements != null ? "filled" : "blank"); indent++; } @Override public void visitAnnotationOnMethod(AbstractMethodDeclaration method, Node node, Annotation annotation) { print("", annotation); } @Override public void endVisitMethod(Node node, AbstractMethodDeclaration method) { String type = method instanceof ConstructorDeclaration ? "CONSTRUCTOR" : "METHOD"; indent--; print("", type, str(method.selector)); } @Override public void visitMethodArgument(Node node, Argument arg, AbstractMethodDeclaration method) { print("", str(arg.type), str(arg.name), arg.initialization); indent++; } @Override public void visitAnnotationOnMethodArgument(Argument arg, AbstractMethodDeclaration method, Node node, Annotation annotation) { print("", annotation); } @Override public void endVisitMethodArgument(Node node, Argument arg, AbstractMethodDeclaration method) { indent--; print("", str(arg.type), str(arg.name)); } @Override public void visitLocal(Node node, LocalDeclaration local) { print("", str(local.type), str(local.name), local.initialization); indent++; } @Override public void visitAnnotationOnLocal(LocalDeclaration local, Node node, Annotation annotation) { print("", annotation); } @Override public void endVisitLocal(Node node, LocalDeclaration local) { indent--; print("", str(local.type), str(local.name)); } @Override public void visitStatement(Node node, Statement statement) { print("<%s>", statement.getClass()); indent++; print("%s", statement); } @Override public void endVisitStatement(Node node, Statement statement) { indent--; print("", statement.getClass()); } } }