diff options
author | Roel Spilker <r.spilker@gmail.com> | 2009-11-27 04:18:28 +0100 |
---|---|---|
committer | Roel Spilker <r.spilker@gmail.com> | 2009-11-27 04:23:41 +0100 |
commit | 391db3dcecdd0d94eb76b656e655346891b02bb4 (patch) | |
tree | 592d79167f4f5a6ce92813cfd962fa51228d3ee0 /src | |
parent | e54c3f36e3122dfe34a119178cfcca2dcdbad998 (diff) | |
download | lombok-391db3dcecdd0d94eb76b656e655346891b02bb4.tar.gz lombok-391db3dcecdd0d94eb76b656e655346891b02bb4.tar.bz2 lombok-391db3dcecdd0d94eb76b656e655346891b02bb4.zip |
Thorough work on inserting comments in the proper place for delombok; should now work fine with GWT native methods!
NON-NLS-1 is still theoretically problematic, but that'll be a fix for another day.
Also added ability to recognize that nothing has changed, which will copy the original file instead of reparsing it.
Diffstat (limited to 'src')
14 files changed, 151 insertions, 16 deletions
diff --git a/src/core/lombok/javac/JavacTransformer.java b/src/core/lombok/javac/JavacTransformer.java index d004414d..5f145460 100644 --- a/src/core/lombok/javac/JavacTransformer.java +++ b/src/core/lombok/javac/JavacTransformer.java @@ -42,7 +42,7 @@ public class JavacTransformer { this.handlers = HandlerLibrary.load(messager); } - public void transform(Context context, Iterable<JCCompilationUnit> compilationUnits) { + public boolean transform(Context context, Iterable<JCCompilationUnit> compilationUnits) { List<JavacAST> asts = new ArrayList<JavacAST>(); for (JCCompilationUnit unit : compilationUnits) asts.add(new JavacAST(messager, context, unit)); @@ -57,6 +57,11 @@ public class JavacTransformer { for (JavacAST ast : asts) { ast.traverse(new AnnotationVisitor()); } + + for (JavacAST ast : asts) { + if (ast.isChanged()) return true; + } + return false; } private class AnnotationVisitor extends JavacASTAdapter { diff --git a/src/core/lombok/javac/handlers/HandleCleanup.java b/src/core/lombok/javac/handlers/HandleCleanup.java index 88a8e1d7..2c89d9ad 100644 --- a/src/core/lombok/javac/handlers/HandleCleanup.java +++ b/src/core/lombok/javac/handlers/HandleCleanup.java @@ -21,6 +21,7 @@ */ package lombok.javac.handlers; +import static lombok.javac.handlers.JavacHandlerUtil.markAnnotationAsProcessed; import lombok.Cleanup; import lombok.core.AnnotationValues; import lombok.core.AST.Kind; @@ -53,6 +54,7 @@ import com.sun.tools.javac.util.Name; @ProviderFor(JavacAnnotationHandler.class) public class HandleCleanup implements JavacAnnotationHandler<Cleanup> { @Override public boolean handle(AnnotationValues<Cleanup> annotation, JCAnnotation ast, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, Cleanup.class); String cleanupName = annotation.getInstance().value(); if (cleanupName.length() == 0) { annotationNode.addError("cleanupName cannot be the empty string."); diff --git a/src/core/lombok/javac/handlers/HandleData.java b/src/core/lombok/javac/handlers/HandleData.java index eef7f78d..a0315d08 100644 --- a/src/core/lombok/javac/handlers/HandleData.java +++ b/src/core/lombok/javac/handlers/HandleData.java @@ -59,6 +59,7 @@ import com.sun.tools.javac.util.List; @ProviderFor(JavacAnnotationHandler.class) public class HandleData implements JavacAnnotationHandler<Data> { @Override public boolean handle(AnnotationValues<Data> annotation, JCAnnotation ast, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, Data.class); JavacNode typeNode = annotationNode.up(); JCClassDecl typeDecl = null; if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl)typeNode.get(); diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index 61a4ef63..f388336d 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -72,6 +72,7 @@ public class HandleEqualsAndHashCode implements JavacAnnotationHandler<EqualsAnd } @Override public boolean handle(AnnotationValues<EqualsAndHashCode> annotation, JCAnnotation ast, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, EqualsAndHashCode.class); EqualsAndHashCode ann = annotation.getInstance(); List<String> excludes = List.from(ann.exclude()); List<String> includes = List.from(ann.of()); diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java index e60e426d..b0343eaf 100644 --- a/src/core/lombok/javac/handlers/HandleGetter.java +++ b/src/core/lombok/javac/handlers/HandleGetter.java @@ -80,8 +80,10 @@ public class HandleGetter implements JavacAnnotationHandler<Getter> { } @Override public boolean handle(AnnotationValues<Getter> annotation, JCAnnotation ast, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, Getter.class); JavacNode fieldNode = annotationNode.up(); AccessLevel level = annotation.getInstance().value(); + if (level == AccessLevel.NONE) return true; return createGetterForField(level, fieldNode, annotationNode, true); diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index 84032e9c..1d029f33 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -82,8 +82,10 @@ public class HandleSetter implements JavacAnnotationHandler<Setter> { } @Override public boolean handle(AnnotationValues<Setter> annotation, JCAnnotation ast, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, Setter.class); JavacNode fieldNode = annotationNode.up(); AccessLevel level = annotation.getInstance().value(); + if (level == AccessLevel.NONE) return true; return createSetterForField(level, fieldNode, annotationNode, true); diff --git a/src/core/lombok/javac/handlers/HandleSneakyThrows.java b/src/core/lombok/javac/handlers/HandleSneakyThrows.java index e7879dd1..8a185e87 100644 --- a/src/core/lombok/javac/handlers/HandleSneakyThrows.java +++ b/src/core/lombok/javac/handlers/HandleSneakyThrows.java @@ -22,6 +22,7 @@ package lombok.javac.handlers; import static lombok.javac.handlers.JavacHandlerUtil.chainDots; +import static lombok.javac.handlers.JavacHandlerUtil.markAnnotationAsProcessed; import java.util.ArrayList; import java.util.Collection; @@ -49,6 +50,7 @@ import com.sun.tools.javac.util.List; @ProviderFor(JavacAnnotationHandler.class) public class HandleSneakyThrows implements JavacAnnotationHandler<SneakyThrows> { @Override public boolean handle(AnnotationValues<SneakyThrows> annotation, JCAnnotation ast, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, SneakyThrows.class); Collection<String> exceptionNames = annotation.getRawExpressions("value"); List<JCExpression> memberValuePairs = ast.getArguments(); diff --git a/src/core/lombok/javac/handlers/HandleSynchronized.java b/src/core/lombok/javac/handlers/HandleSynchronized.java index c86d99c6..eaa0ad6d 100644 --- a/src/core/lombok/javac/handlers/HandleSynchronized.java +++ b/src/core/lombok/javac/handlers/HandleSynchronized.java @@ -51,10 +51,12 @@ public class HandleSynchronized implements JavacAnnotationHandler<Synchronized> private static final String STATIC_LOCK_NAME = "$LOCK"; @Override public boolean handle(AnnotationValues<Synchronized> annotation, JCAnnotation ast, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, Synchronized.class); JavacNode methodNode = annotationNode.up(); if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof JCMethodDecl)) { annotationNode.addError("@Synchronized is legal only on methods."); + return true; } @@ -62,6 +64,7 @@ public class HandleSynchronized implements JavacAnnotationHandler<Synchronized> if ((method.mods.flags & Flags.ABSTRACT) != 0) { annotationNode.addError("@Synchronized is legal only on concrete methods."); + return true; } boolean isStatic = (method.mods.flags & Flags.STATIC) != 0; diff --git a/src/core/lombok/javac/handlers/HandleToString.java b/src/core/lombok/javac/handlers/HandleToString.java index f7251ab8..dd3df620 100644 --- a/src/core/lombok/javac/handlers/HandleToString.java +++ b/src/core/lombok/javac/handlers/HandleToString.java @@ -68,6 +68,8 @@ public class HandleToString implements JavacAnnotationHandler<ToString> { } @Override public boolean handle(AnnotationValues<ToString> annotation, JCAnnotation ast, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, ToString.class); + ToString ann = annotation.getInstance(); List<String> excludes = List.from(ann.exclude()); List<String> includes = List.from(ann.of()); diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 34d8b849..caa8a998 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -21,6 +21,7 @@ */ package lombok.javac.handlers; +import java.lang.annotation.Annotation; import java.util.regex.Pattern; import lombok.AccessLevel; @@ -34,7 +35,9 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCImport; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; @@ -58,6 +61,54 @@ public class JavacHandlerUtil { } /** + * Removes the annotation from javac's AST, then removes it from lombok's AST, + * then removes any import statement that imports this exact annotation (not star imports). + */ + public static void markAnnotationAsProcessed(JavacNode annotation, Class<? extends Annotation> annotationType) { + JavacNode parentNode = annotation.directUp(); + switch (parentNode.getKind()) { + case FIELD: + case ARGUMENT: + case LOCAL: + JCVariableDecl variable = (JCVariableDecl) parentNode.get(); + variable.mods.annotations = filterList(variable.mods.annotations, annotation.get()); + break; + case METHOD: + JCMethodDecl method = (JCMethodDecl) parentNode.get(); + method.mods.annotations = filterList(method.mods.annotations, annotation.get()); + break; + default: + throw new IllegalStateException("Don't know how to remove annotations from: " + parentNode.getKind()); + } + parentNode.removeChild(annotation); + + JCCompilationUnit unit = (JCCompilationUnit) annotation.top().get(); + deleteImportFromCompilationUnit(unit, annotationType.getName()); + } + + private static void deleteImportFromCompilationUnit(JCCompilationUnit unit, String name) { + List<JCTree> newDefs = List.nil(); + + for (JCTree def : unit.defs) { + boolean delete = false; + if (def instanceof JCImport) { + JCImport imp0rt = (JCImport)def; + delete = (!imp0rt.staticImport && imp0rt.qualid.toString().equals(name)); + } + if (!delete) newDefs = newDefs.append(def); + } + unit.defs = newDefs; + } + + private static List<JCAnnotation> filterList(List<JCAnnotation> annotations, JCTree jcTree) { + List<JCAnnotation> newAnnotations = List.nil(); + for (JCAnnotation ann : annotations) { + if (jcTree != ann) newAnnotations = newAnnotations.append(ann); + } + return newAnnotations; + } + + /** * Translates the given field into all possible getter names. * Convenient wrapper around {@link TransformationsUtil#toAllGetterNames(CharSequence, boolean)}. */ diff --git a/src/delombok/lombok/delombok/Comment.java b/src/delombok/lombok/delombok/Comment.java index c264733f..55a5c46d 100644 --- a/src/delombok/lombok/delombok/Comment.java +++ b/src/delombok/lombok/delombok/Comment.java @@ -23,11 +23,21 @@ package lombok.delombok; public final class Comment { final int pos; + final int prevEndPos; final String content; + final int endPos; + final boolean newLine; - public Comment(int pos, String content) { + public Comment(int prevEndPos, int pos, int endPos, String content, boolean newLine) { this.pos = pos; + this.prevEndPos = prevEndPos; + this.endPos = endPos; this.content = content; + this.newLine = newLine; + } + + public boolean isConnected() { + return !newLine && prevEndPos == pos; } public String summary() { diff --git a/src/delombok/lombok/delombok/CommentCollectingScanner.java b/src/delombok/lombok/delombok/CommentCollectingScanner.java index 6f593c7f..c38aef24 100644 --- a/src/delombok/lombok/delombok/CommentCollectingScanner.java +++ b/src/delombok/lombok/delombok/CommentCollectingScanner.java @@ -80,6 +80,20 @@ public class CommentCollectingScanner extends Scanner { @Override protected void processComment(CommentStyle style) { - comments.add(pos(), new String(getRawCharacters(pos(), endPos()))); + int prevEndPos = prevEndPos(); + int pos = pos(); + boolean newLine = containsNewLine(prevEndPos, pos); + String content = new String(getRawCharacters(pos, endPos())); + comments.add(prevEndPos, pos, endPos(), content, newLine); + } + + + private boolean containsNewLine(int from, int to) { + for (char c : getRawCharacters(from, to)) { + if (c == '\n' || c == '\r') { + return true; + } + } + return false; } }
\ No newline at end of file diff --git a/src/delombok/lombok/delombok/CommentPreservingParser.java b/src/delombok/lombok/delombok/CommentPreservingParser.java index 51df5ed1..9fd8778c 100644 --- a/src/delombok/lombok/delombok/CommentPreservingParser.java +++ b/src/delombok/lombok/delombok/CommentPreservingParser.java @@ -24,11 +24,13 @@ package lombok.delombok; import java.io.IOException; import java.io.Writer; import java.util.Collections; +import java.util.Date; import javax.annotation.processing.Messager; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; +import javax.tools.JavaFileObject; import javax.tools.Diagnostic.Kind; import lombok.javac.JavacTransformer; @@ -52,7 +54,7 @@ public class CommentPreservingParser { this.encoding = encoding; } - public ParseResult parseFile(String fileName) throws IOException { + public ParseResult parse(String fileName, boolean forceProcessing) throws IOException { Context context = new Context(); Options.instance(context).put(OptionName.ENCODING, encoding); @@ -74,9 +76,8 @@ public class CommentPreservingParser { @SuppressWarnings("deprecation") JCCompilationUnit cu = compiler.parse(fileName); - new JavacTransformer(messager).transform(context, Collections.singleton(cu)); - - return new ParseResult(comments.comments, cu); + boolean changed = new JavacTransformer(messager).transform(context, Collections.singleton(cu)); + return new ParseResult(comments.comments, cu, forceProcessing || changed); } private static final Messager messager = new Messager() { @@ -100,21 +101,33 @@ public class CommentPreservingParser { static class Comments { List<Comment> comments = List.nil(); - void add(int pos, String content) { - comments = comments.append(new Comment(pos, content)); + void add(int prevEndPos, int pos, int endPos, String content, boolean newLine) { + comments = comments.append(new Comment(prevEndPos, pos, endPos, content, newLine)); } } public static class ParseResult { private final List<Comment> comments; private final JCCompilationUnit compilationUnit; + private final boolean changed; - private ParseResult(List<Comment> comments, JCCompilationUnit compilationUnit) { + private ParseResult(List<Comment> comments, JCCompilationUnit compilationUnit, boolean changed) { this.comments = comments; this.compilationUnit = compilationUnit; + this.changed = changed; } - public void print(Writer out) { + public void print(Writer out) throws IOException { + if (!changed) { + JavaFileObject sourceFile = compilationUnit.getSourceFile(); + if (sourceFile != null) { + out.write(sourceFile.getCharContent(true).toString()); + System.out.println(out.toString()); + return; + } + } + + out.write("// Generated by delombok at " + new Date() + "\n"); compilationUnit.accept(new PrettyCommentsPrinter(out, compilationUnit, comments)); } } diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index 2fb62e53..611dd417 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -179,7 +179,32 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { align(); } } - + + private void consumeTrailingComments(int from) throws IOException { + boolean shouldIndent = !newLine; + Comment head = comments.head; + while (comments.nonEmpty() && head.prevEndPos == from) { + from = head.endPos; + if (!head.isConnected()) { + if (head.newLine) { + if (!newLine) { + println(); + align(); + } + } + else { + print(" "); + } + } + print(head.content); + comments = comments.tail; + head = comments.head; + } + if (newLine && shouldIndent) { + align(); + } + } + /** The output stream on which trees are printed. */ Writer out; @@ -277,15 +302,17 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { if (tree == null) print("/*missing*/"); else { consumeComments(tree.pos); - tree.accept(this); - consumeComments(endPos(tree)); + tree.accept(this); + int endPos = endPos(tree); + consumeTrailingComments(endPos); + consumeComments(endPos); } } catch (UncheckedIOException ex) { IOException e = new IOException(ex.getMessage()); e.initCause(ex); throw e; } finally { - this.prec = prevPrec; + this.prec = prevPrec; } } @@ -301,7 +328,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void printStat(JCTree tree) throws IOException { printExpr(tree, TreeInfo.notExpression); } - + /** Derived visitor method: print list of expression trees, separated by given string. * @param sep the separator string */ |