diff options
Diffstat (limited to 'src/delombok')
-rw-r--r-- | src/delombok/lombok/delombok/Delombok.java | 31 | ||||
-rw-r--r-- | src/delombok/lombok/delombok/DelombokApp.java | 3 | ||||
-rw-r--r-- | src/delombok/lombok/delombok/DocCommentIntegrator.java | 127 | ||||
-rw-r--r-- | src/delombok/lombok/delombok/LombokOptionsFactory.java | 57 | ||||
-rw-r--r-- | src/delombok/lombok/delombok/PrettyCommentsPrinter.java | 547 |
5 files changed, 441 insertions, 324 deletions
diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index f4e02786..0128e44f 100644 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -52,7 +52,6 @@ import lombok.javac.LombokOptions; import com.sun.tools.javac.comp.Todo; import com.sun.tools.javac.main.JavaCompiler; -import com.sun.tools.javac.main.OptionName; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.util.Context; import com.zwitserloot.cmdreader.CmdReader; @@ -359,12 +358,12 @@ public class Delombok { } public boolean delombok() throws IOException { - LombokOptions options = LombokOptions.replaceWithDelombokOptions(context); - options.put(OptionName.ENCODING, charset.name()); - if (classpath != null) options.put(OptionName.CLASSPATH, classpath); - if (sourcepath != null) options.put(OptionName.SOURCEPATH, sourcepath); - if (bootclasspath != null) options.put(OptionName.BOOTCLASSPATH, bootclasspath); - options.put("compilePolicy", "attr"); + LombokOptions options = LombokOptionsFactory.getDelombokOptions(context); + options.putJavacOption("ENCODING", charset.name()); + if (classpath != null) options.putJavacOption("CLASSPATH", classpath); + if (sourcepath != null) options.putJavacOption("SOURCEPATH", sourcepath); + if (bootclasspath != null) options.putJavacOption("BOOTCLASSPATH", bootclasspath); + options.put("compilePolicy", "check"); CommentCatcher catcher = CommentCatcher.create(context); JavaCompiler compiler = catcher.getCompiler(); @@ -375,10 +374,7 @@ public class Delombok { compiler.initProcessAnnotations(Collections.singleton(new lombok.javac.apt.Processor())); for (File fileToParse : filesToParse) { - - @SuppressWarnings("deprecation") - JCCompilationUnit unit = compiler.parse(fileToParse.getAbsolutePath()); - + @SuppressWarnings("deprecation") JCCompilationUnit unit = compiler.parse(fileToParse.getAbsolutePath()); baseMap.put(unit, fileToBase.get(fileToParse)); roots.add(unit); } @@ -387,8 +383,17 @@ public class Delombok { return false; } - JavaCompiler delegate = compiler.processAnnotations(compiler.enterTrees(toJavacList(roots))); - callFlowMethodOnJavaCompiler(delegate, callAttributeMethodOnJavaCompiler(delegate, delegate.todo)); + for (JCCompilationUnit unit : roots) { + catcher.setComments(unit, new DocCommentIntegrator().integrate(catcher.getComments(unit), unit)); + } + + com.sun.tools.javac.util.List<JCCompilationUnit> trees = compiler.enterTrees(toJavacList(roots)); + + JavaCompiler delegate = compiler.processAnnotations(trees); + + Object care = callAttributeMethodOnJavaCompiler(delegate, delegate.todo); + + callFlowMethodOnJavaCompiler(delegate, care); for (JCCompilationUnit unit : roots) { DelombokResult result = new DelombokResult(catcher.getComments(unit), unit, force || options.isChanged(unit)); if (verbose) feedback.printf("File: %s [%s]\n", unit.sourcefile.getName(), result.isChanged() ? "delomboked" : "unchanged"); diff --git a/src/delombok/lombok/delombok/DelombokApp.java b/src/delombok/lombok/delombok/DelombokApp.java index e0d6ef1c..276bd7de 100644 --- a/src/delombok/lombok/delombok/DelombokApp.java +++ b/src/delombok/lombok/delombok/DelombokApp.java @@ -84,10 +84,9 @@ public class DelombokApp extends LombokApp { return null; } - @SuppressWarnings("resource") // The jar file is used for the lifetime of the classLoader, therefore the lifetime of delombok. // Since we only read from it, not closing it should not be a problem. - final JarFile toolsJarFile = new JarFile(toolsJar); + @SuppressWarnings({"resource", "all"}) final JarFile toolsJarFile = new JarFile(toolsJar); ClassLoader loader = new ClassLoader() { private Class<?> loadStreamAsClass(String name, boolean resolve, InputStream in) throws ClassNotFoundException { diff --git a/src/delombok/lombok/delombok/DocCommentIntegrator.java b/src/delombok/lombok/delombok/DocCommentIntegrator.java new file mode 100644 index 00000000..0955a003 --- /dev/null +++ b/src/delombok/lombok/delombok/DocCommentIntegrator.java @@ -0,0 +1,127 @@ +package lombok.delombok; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import lombok.javac.CommentInfo; +import lombok.javac.Javac; +import lombok.javac.handlers.JavacHandlerUtil; + +import com.sun.tools.javac.parser.Tokens.Comment; +import com.sun.tools.javac.tree.DocCommentTable; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; + +public class DocCommentIntegrator { + /** + * Returns the same comment list as when this integrator was created, minus all doc comments that have been successfully integrated into the compilation unit. + */ + public List<CommentInfo> integrate(List<CommentInfo> comments, JCCompilationUnit unit) { + List<CommentInfo> out = new ArrayList<CommentInfo>(); + CommentInfo lastExcisedComment = null; + JCTree lastNode = null; + + for (CommentInfo cmt : comments) { + if (!cmt.isJavadoc()) { + out.add(cmt); + continue; + } + + JCTree node = findJavadocableNodeOnOrAfter(unit, cmt.endPos); + if (node == null) { + out.add(cmt); + continue; + } + + if (node == lastNode) { + out.add(lastExcisedComment); + } + if (!attach(unit, node, cmt)) { + out.add(cmt); + } else { + lastNode = node; + lastExcisedComment = cmt; + } + } + return out; + } + + private static final Pattern CONTENT_STRIPPER = Pattern.compile("^(?:\\s*\\*)?[ \\t]*(.*?)$", Pattern.MULTILINE); + @SuppressWarnings("unchecked") private boolean attach(JCCompilationUnit top, final JCTree node, CommentInfo cmt) { + String docCommentContent = cmt.content; + if (docCommentContent.startsWith("/**")) docCommentContent = docCommentContent.substring(3); + if (docCommentContent.endsWith("*/")) docCommentContent = docCommentContent.substring(0, docCommentContent.length() -2); + docCommentContent = CONTENT_STRIPPER.matcher(docCommentContent).replaceAll("$1"); + docCommentContent = docCommentContent.trim(); + + if (Javac.getDocComments(top) == null) Javac.initDocComments(top); + + Object map_ = Javac.getDocComments(top); + if (map_ instanceof Map) { + ((Map<JCTree, String>) map_).put(node, docCommentContent); + return true; + } else if (Javac.instanceOfDocCommentTable(map_)) { + CommentAttacher_8.attach(node, docCommentContent, map_); + return true; + } + + return false; + } + + /* Container for code which will cause class loader exceptions on javac below 8. By being in a separate class, we avoid the problem. */ + private static class CommentAttacher_8 { + static void attach(final JCTree node, String docCommentContent, Object map_) { + final String docCommentContent_ = docCommentContent; + ((DocCommentTable) map_).putComment(node, new Comment() { + @Override public String getText() { + return docCommentContent_; + } + + @Override public int getSourcePos(int index) { + return -1; + } + + @Override public CommentStyle getStyle() { + return CommentStyle.JAVADOC; + } + + @Override public boolean isDeprecated() { + return JavacHandlerUtil.nodeHasDeprecatedFlag(node); + } + }); + } + } + + private JCTree findJavadocableNodeOnOrAfter(JCCompilationUnit unit, int endPos) { + if (unit.pid != null && endPos <= unit.pid.pos) return null; + Iterator<JCTree> it = unit.defs.iterator(); + + while (it.hasNext()) { + JCTree node = it.next(); + if (node.pos < endPos) { + if (node instanceof JCClassDecl) { + com.sun.tools.javac.util.List<JCTree> defs = ((JCClassDecl) node).defs; + if (!defs.isEmpty()) while (!defs.tail.isEmpty()) defs = defs.tail; + if (defs.head != null && defs.head.pos >= endPos) { + // The associated node is IN this class declaration, so, replace the iterator. + // There's no point looking beyond this member in the current iteration 'context' + // so we don't need to save the old ref. Just start over inside this type declaration. + it = ((JCClassDecl) node).defs.iterator(); + } + } + continue; + } + + if (node instanceof JCMethodDecl || node instanceof JCClassDecl || node instanceof JCVariableDecl) return node; + return null; + } + + return null; + } +} diff --git a/src/delombok/lombok/delombok/LombokOptionsFactory.java b/src/delombok/lombok/delombok/LombokOptionsFactory.java new file mode 100644 index 00000000..e581593f --- /dev/null +++ b/src/delombok/lombok/delombok/LombokOptionsFactory.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.delombok; + +import lombok.javac.Javac; +import lombok.javac.Javac6BasedLombokOptions; +import lombok.javac.Javac8BasedLombokOptions; +import lombok.javac.LombokOptions; + +import com.sun.tools.javac.util.Context; + +public class LombokOptionsFactory { + enum LombokOptionCompilerVersion { + JDK7_AND_LOWER { + @Override LombokOptions createAndRegisterOptions(Context context) { + return Javac6BasedLombokOptions.replaceWithDelombokOptions(context); + } + }, + + JDK8 { + @Override LombokOptions createAndRegisterOptions(Context context) { + return Javac8BasedLombokOptions.replaceWithDelombokOptions(context); + } + }; + + abstract LombokOptions createAndRegisterOptions(Context context); + } + + public static LombokOptions getDelombokOptions(Context context) { + LombokOptions options; + if (Javac.getJavaCompilerVersion() < 8) { + options = LombokOptionCompilerVersion.JDK7_AND_LOWER.createAndRegisterOptions(context); + } else { + options = LombokOptionCompilerVersion.JDK8.createAndRegisterOptions(context); + } + return options; + } +} diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index 1bb2ce23..f9152e68 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -29,34 +29,27 @@ */ package lombok.delombok; -import static com.sun.tools.javac.code.Flags.ANNOTATION; -import static com.sun.tools.javac.code.Flags.ENUM; -import static com.sun.tools.javac.code.Flags.INTERFACE; -import static com.sun.tools.javac.code.Flags.SYNTHETIC; -import static com.sun.tools.javac.code.Flags.StandardFlags; -import static com.sun.tools.javac.code.Flags.VARARGS; +import static com.sun.tools.javac.code.Flags.*; +import static lombok.javac.Javac.*; +import static lombok.javac.JavacTreeMaker.TreeTag.treeTag; +import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; import java.io.IOException; import java.io.Writer; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import lombok.javac.CommentInfo; -import lombok.javac.Javac; import lombok.javac.CommentInfo.EndConnection; import lombok.javac.CommentInfo.StartConnection; +import lombok.javac.JavacTreeMaker.TreeTag; +import lombok.javac.JavacTreeMaker.TypeTag; import com.sun.source.tree.Tree; -import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.TypeTags; import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.TreeInfo; -import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCArrayAccess; import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; @@ -108,10 +101,14 @@ import com.sun.tools.javac.tree.JCTree.JCWhileLoop; import com.sun.tools.javac.tree.JCTree.JCWildcard; import com.sun.tools.javac.tree.JCTree.LetExpr; import com.sun.tools.javac.tree.JCTree.TypeBoundKind; +import com.sun.tools.javac.tree.DocCommentTable; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.Convert; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Position; +//import com.sun.tools.javac.code.TypeTags; /** Prints out a tree as an indented Java source program. * @@ -122,214 +119,177 @@ import com.sun.tools.javac.util.Position; */ @SuppressWarnings("all") // Mainly sun code that has other warning settings public class PrettyCommentsPrinter extends JCTree.Visitor { - - private static final Method GET_TAG_METHOD; - private static final Field TAG_FIELD; + private static final TreeTag PARENS = treeTag("PARENS"); + private static final TreeTag IMPORT = treeTag("IMPORT"); + private static final TreeTag VARDEF = treeTag("VARDEF"); + private static final TreeTag SELECT = treeTag("SELECT"); - private static final int PARENS = Javac.getCtcInt(JCTree.class, "PARENS"); - private static final int IMPORT = Javac.getCtcInt(JCTree.class, "IMPORT"); - private static final int VARDEF = Javac.getCtcInt(JCTree.class, "VARDEF"); - private static final int SELECT = Javac.getCtcInt(JCTree.class, "SELECT"); - - private static final Map<Integer, String> OPERATORS; + private static final Map<TreeTag, String> OPERATORS; static { - Method m = null; - Field f = null; - try { - m = JCTree.class.getDeclaredMethod("getTag"); - } - catch (NoSuchMethodException e) { - try { - f = JCTree.class.getDeclaredField("tag"); - } - catch (NoSuchFieldException e1) { - e1.printStackTrace(); - } - } - GET_TAG_METHOD = m; - TAG_FIELD = f; - - Map<Integer, String> map = new HashMap<Integer, String>(); - - map.put(Javac.getCtcInt(JCTree.class, "POS"), "+"); - map.put(Javac.getCtcInt(JCTree.class, "NEG"), "-"); - map.put(Javac.getCtcInt(JCTree.class, "NOT"), "!"); - map.put(Javac.getCtcInt(JCTree.class, "COMPL"), "~"); - map.put(Javac.getCtcInt(JCTree.class, "PREINC"), "++"); - map.put(Javac.getCtcInt(JCTree.class, "PREDEC"), "--"); - map.put(Javac.getCtcInt(JCTree.class, "POSTINC"), "++"); - map.put(Javac.getCtcInt(JCTree.class, "POSTDEC"), "--"); - map.put(Javac.getCtcInt(JCTree.class, "NULLCHK"), "<*nullchk*>"); - map.put(Javac.getCtcInt(JCTree.class, "OR"), "||"); - map.put(Javac.getCtcInt(JCTree.class, "AND"), "&&"); - map.put(Javac.getCtcInt(JCTree.class, "EQ"), "=="); - map.put(Javac.getCtcInt(JCTree.class, "NE"), "!="); - map.put(Javac.getCtcInt(JCTree.class, "LT"), "<"); - map.put(Javac.getCtcInt(JCTree.class, "GT"), ">"); - map.put(Javac.getCtcInt(JCTree.class, "LE"), "<="); - map.put(Javac.getCtcInt(JCTree.class, "GE"), ">="); - map.put(Javac.getCtcInt(JCTree.class, "BITOR"), "|"); - map.put(Javac.getCtcInt(JCTree.class, "BITXOR"), "^"); - map.put(Javac.getCtcInt(JCTree.class, "BITAND"), "&"); - map.put(Javac.getCtcInt(JCTree.class, "SL"), "<<"); - map.put(Javac.getCtcInt(JCTree.class, "SR"), ">>"); - map.put(Javac.getCtcInt(JCTree.class, "USR"), ">>>"); - map.put(Javac.getCtcInt(JCTree.class, "PLUS"), "+"); - map.put(Javac.getCtcInt(JCTree.class, "MINUS"), "-"); - map.put(Javac.getCtcInt(JCTree.class, "MUL"), "*"); - map.put(Javac.getCtcInt(JCTree.class, "DIV"), "/"); - map.put(Javac.getCtcInt(JCTree.class, "MOD"), "%"); - - OPERATORS = map; + Map<TreeTag, String> map = new HashMap<TreeTag, String>(); + + map.put(treeTag("POS"), "+"); + map.put(treeTag("NEG"), "-"); + map.put(treeTag("NOT"), "!"); + map.put(treeTag("COMPL"), "~"); + map.put(treeTag("PREINC"), "++"); + map.put(treeTag("PREDEC"), "--"); + map.put(treeTag("POSTINC"), "++"); + map.put(treeTag("POSTDEC"), "--"); + map.put(treeTag("NULLCHK"), "<*nullchk*>"); + map.put(treeTag("OR"), "||"); + map.put(treeTag("AND"), "&&"); + map.put(treeTag("EQ"), "=="); + map.put(treeTag("NE"), "!="); + map.put(treeTag("LT"), "<"); + map.put(treeTag("GT"), ">"); + map.put(treeTag("LE"), "<="); + map.put(treeTag("GE"), ">="); + map.put(treeTag("BITOR"), "|"); + map.put(treeTag("BITXOR"), "^"); + map.put(treeTag("BITAND"), "&"); + map.put(treeTag("SL"), "<<"); + map.put(treeTag("SR"), ">>"); + map.put(treeTag("USR"), ">>>"); + map.put(treeTag("PLUS"), "+"); + map.put(treeTag("MINUS"), "-"); + map.put(treeTag("MUL"), "*"); + map.put(treeTag("DIV"), "/"); + map.put(treeTag("MOD"), "%"); + + map.put(treeTag("BITOR_ASG"), "|="); + map.put(treeTag("BITXOR_ASG"), "^="); + map.put(treeTag("BITAND_ASG"), "&="); + map.put(treeTag("SL_ASG"), "<<="); + map.put(treeTag("SR_ASG"), ">>="); + map.put(treeTag("USR_ASG"), ">>>="); + map.put(treeTag("PLUS_ASG"), "+="); + map.put(treeTag("MINUS_ASG"), "-="); + map.put(treeTag("MUL_ASG"), "*="); + map.put(treeTag("DIV_ASG"), "/="); + map.put(treeTag("MOD_ASG"), "%="); + + OPERATORS = map; } - static int getTag(JCTree tree) { - if (GET_TAG_METHOD != null) { - try { - return (Integer)GET_TAG_METHOD.invoke(tree); - } - catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - catch (InvocationTargetException e) { - throw new RuntimeException(e.getCause()); - } - } - try { - return TAG_FIELD.getInt(tree); - } - catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - private List<CommentInfo> comments; - private final JCCompilationUnit cu; - private boolean onNewLine = true; - private boolean aligned = false; - private boolean inParams = false; - - private boolean needsSpace = false; - private boolean needsNewLine = false; - private boolean needsAlign = false; - + private List<CommentInfo> comments; + private final JCCompilationUnit cu; + private boolean onNewLine = true; + private boolean aligned = false; + private boolean inParams = false; + + private boolean needsSpace = false; + private boolean needsNewLine = false; + private boolean needsAlign = false; + public PrettyCommentsPrinter(Writer out, JCCompilationUnit cu, List<CommentInfo> comments) { this.out = out; - this.comments = comments; - this.cu = cu; + this.comments = comments; + this.cu = cu; } - - private int endPos(JCTree tree) { - return tree.getEndPosition(cu.endPositions); - } - private void consumeComments(int until) throws IOException { - consumeComments(until, null); - } - private void consumeComments(int until, JCTree tree) throws IOException { - boolean prevNewLine = onNewLine; - boolean found = false; - CommentInfo head = comments.head; - while (comments.nonEmpty() && head.pos < until) { - if (tree != null && docComments != null && docComments.containsKey(tree) && head.isJavadoc() && noFurtherJavadocForthcoming(until)) { - // This is (presumably) the exact same javadoc that has already been associated with the node that we're just about to - // print. These javadoc can be modified by lombok handlers, and as such we should NOT print them from the consumed comments db, - // and instead print the actual javadoc associated with the upcoming node (which the visit method for that node will take care of). - } else { - printComment(head); - } - comments = comments.tail; - head = comments.head; - } - if (!onNewLine && prevNewLine) { - println(); - } - } + private int endPos(JCTree tree) { + return getEndPosition(tree, cu); + } - private boolean noFurtherJavadocForthcoming(int until) { - List<CommentInfo> c = comments; - if (c.nonEmpty()) c = c.tail; - while (c.nonEmpty()) { - if (c.head.pos >= until) return true; - if (c.head.isJavadoc()) return false; - c = c.tail; - } - return true; + private void consumeComments(int until) throws IOException { + consumeComments(until, null); } - + + private void consumeComments(int until, JCTree tree) throws IOException { + boolean prevNewLine = onNewLine; + boolean found = false; + CommentInfo head = comments.head; + while (comments.nonEmpty() && head.pos < until) { + printComment(head); + comments = comments.tail; + head = comments.head; + } + if (!onNewLine && prevNewLine) { + println(); + } + } + private void consumeTrailingComments(int from) throws IOException { - boolean prevNewLine = onNewLine; - CommentInfo head = comments.head; - boolean stop = false; - while (comments.nonEmpty() && head.prevEndPos == from && !stop && !(head.start == StartConnection.ON_NEXT_LINE || head.start == StartConnection.START_OF_LINE)) { - from = head.endPos; - printComment(head); - stop = (head.end == EndConnection.ON_NEXT_LINE); - comments = comments.tail; - head = comments.head; - } - if (!onNewLine && prevNewLine) { - println(); - } - } - - private void printComment(CommentInfo comment) throws IOException { - prepareComment(comment.start); - print(comment.content); - switch (comment.end) { - case ON_NEXT_LINE: - if (!aligned) { - needsNewLine = true; - needsAlign = true; - } - break; - case AFTER_COMMENT: - needsSpace = true; - break; - case DIRECT_AFTER_COMMENT: - // do nothing - break; - } + boolean prevNewLine = onNewLine; + CommentInfo head = comments.head; + boolean stop = false; + while (comments.nonEmpty() && head.prevEndPos == from && !stop && !(head.start == StartConnection.ON_NEXT_LINE || head.start == StartConnection.START_OF_LINE)) { + from = head.endPos; + printComment(head); + stop = (head.end == EndConnection.ON_NEXT_LINE); + comments = comments.tail; + head = comments.head; + } + if (!onNewLine && prevNewLine) { + println(); + } + } + + private void printComment(CommentInfo comment) throws IOException { + prepareComment(comment.start); + print(comment.content); + switch (comment.end) { + case ON_NEXT_LINE: + if (!aligned) { + needsNewLine = true; + needsAlign = true; + } + break; + case AFTER_COMMENT: + needsSpace = true; + break; + case DIRECT_AFTER_COMMENT: + // do nothing + break; + } + } + + private void prepareComment(StartConnection start) throws IOException { + switch (start) { + case DIRECT_AFTER_PREVIOUS: + needsSpace = false; + break; + case AFTER_PREVIOUS: + needsSpace = true; + break; + case START_OF_LINE: + needsNewLine = true; + needsAlign = false; + break; + case ON_NEXT_LINE: + if (!aligned) { + needsNewLine = true; + needsAlign = true; + } + break; + } } - - private void prepareComment(StartConnection start) throws IOException { - switch (start) { - case DIRECT_AFTER_PREVIOUS: - needsSpace = false; - break; - case AFTER_PREVIOUS: - needsSpace = true; - break; - case START_OF_LINE: - needsNewLine = true; - needsAlign = false; - break; - case ON_NEXT_LINE: - if (!aligned) { - needsNewLine = true; - needsAlign = true; - } - break; - } - } /** The output stream on which trees are printed. */ Writer out; - + /** The current left margin. */ int lmargin = 0; - + /** The enclosing class name. */ Name enclClassName; - + /** A hashtable mapping trees to their documentation comments * (can be null) */ Map<JCTree, String> docComments = null; + DocCommentTable docTable = null; + + String getJavadocFor(JCTree node) { + if (docComments != null) return docComments.get(node); + if (docTable != null) return docTable.getCommentText(node); + return null; + } /** Align code to be indented to left margin. */ @@ -339,19 +299,19 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { needsAlign = false; for (int i = 0; i < lmargin; i++) out.write("\t"); } - + /** Increase left margin by indentation width. */ void indent() { lmargin++; } - + /** Decrease left margin by indentation width. */ void undent() { lmargin--; } - + /** Enter a new precedence level. Emit a `(' if new precedence level * is less than precedence level so far. * @param contextPrec The precedence level in force so far. @@ -360,7 +320,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { void open(int contextPrec, int ownPrec) throws IOException { if (ownPrec < contextPrec) out.write("("); } - + /** Leave precedence level. Emit a `(' if inner precedence level * is less than precedence level we revert to. * @param contextPrec The precedence level we revert to. @@ -369,7 +329,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { void close(int contextPrec, int ownPrec) throws IOException { if (ownPrec < contextPrec) out.write(")"); } - + /** Print string, replacing all non-ascii character with unicode escapes. */ public void print(Object s) throws IOException { @@ -524,31 +484,28 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { * @param tree The tree for which a documentation comment should be printed. */ public void printDocComment(JCTree tree) throws IOException { - if (docComments != null) { - String dc = docComments.get(tree); - if (dc != null) { - print("/**"); println(); - int pos = 0; - int endpos = lineEndPos(dc, pos); - boolean atStart = true; - while (pos < dc.length()) { - String line = dc.substring(pos, endpos); - if (line.trim().isEmpty() && atStart) { - atStart = false; - continue; - } - atStart = false; - align(); - print(" *"); - if (pos < dc.length() && dc.charAt(pos) > ' ') print(" "); - print(dc.substring(pos, endpos)); println(); - pos = endpos + 1; - endpos = lineEndPos(dc, pos); - } - align(); print(" */"); println(); - align(); + String dc = getJavadocFor(tree); + if (dc == null) return; + print("/**"); println(); + int pos = 0; + int endpos = lineEndPos(dc, pos); + boolean atStart = true; + while (pos < dc.length()) { + String line = dc.substring(pos, endpos); + if (line.trim().isEmpty() && atStart) { + atStart = false; + continue; } + atStart = false; + align(); + print(" *"); + if (pos < dc.length() && dc.charAt(pos) > ' ') print(" "); + print(dc.substring(pos, endpos)); println(); + pos = endpos + 1; + endpos = lineEndPos(dc, pos); } + align(); print(" */"); println(); + align(); } //where static int lineEndPos(String s, int start) { @@ -633,7 +590,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { /** Is the given tree an enumerator definition? */ boolean isEnumerator(JCTree t) { - return getTag(t) == VARDEF && (((JCVariableDecl) t).mods.flags & ENUM) != 0; + return VARDEF.equals(treeTag(t)) && (((JCVariableDecl) t).mods.flags & ENUM) != 0; } /** Print unit consisting of package clause and import statements in toplevel, @@ -644,7 +601,9 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { * toplevel tree. */ public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException { - docComments = tree.docComments; + Object dc = getDocComments(tree); + if (dc instanceof Map) this.docComments = (Map) dc; + else if (dc instanceof DocCommentTable) this.docTable = (DocCommentTable) dc; printDocComment(tree); if (tree.pid != null) { consumeComments(tree.pos, tree); @@ -655,9 +614,9 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { } boolean firstImport = true; for (List<JCTree> l = tree.defs; - l.nonEmpty() && (cdef == null || getTag(l.head) == IMPORT); + l.nonEmpty() && (cdef == null || IMPORT.equals(treeTag(l.head))); l = l.tail) { - if (getTag(l.head) == IMPORT) { + if (IMPORT.equals(treeTag(l.head))) { JCImport imp = (JCImport)l.head; Name name = TreeInfo.name(imp.qualid); if (name == name.table.fromChars(new char[] {'*'}, 0, 1) || @@ -741,9 +700,9 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { else print("class " + tree.name); printTypeParameters(tree.typarams); - if (tree.getExtendsClause() != null) { + if (getExtendsClause(tree) != null) { print(" extends "); - printExpr(tree.getExtendsClause()); + printExpr(getExtendsClause(tree)); } if (tree.implementing.nonEmpty()) { print(" implements "); @@ -826,7 +785,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitVarDef(JCVariableDecl tree) { try { - if (docComments != null && docComments.get(tree) != null) { + if (getJavadocFor(tree) != null) { println(); align(); } printDocComment(tree); @@ -876,7 +835,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { printStat(tree.body); align(); print(" while "); - if (getTag(tree.cond) == PARENS) { + if (PARENS.equals(treeTag(tree.cond))) { printExpr(tree.cond); } else { print("("); @@ -892,7 +851,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitWhileLoop(JCWhileLoop tree) { try { print("while "); - if (getTag(tree.cond) == PARENS) { + if (PARENS.equals(treeTag(tree.cond))) { printExpr(tree.cond); } else { print("("); @@ -910,7 +869,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { try { print("for ("); if (tree.init.nonEmpty()) { - if (getTag(tree.init.head) == VARDEF) { + if (VARDEF.equals(treeTag(tree.init.head))) { printExpr(tree.init.head); for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) { JCVariableDecl vdef = (JCVariableDecl)l.head; @@ -957,7 +916,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitSwitch(JCSwitch tree) { try { print("switch "); - if (getTag(tree.selector) == PARENS) { + if (PARENS.equals(treeTag(tree.selector))) { printExpr(tree.selector); } else { print("("); @@ -996,7 +955,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitSynchronized(JCSynchronized tree) { try { print("synchronized "); - if (getTag(tree.lock) == PARENS) { + if (PARENS.equals(treeTag(tree.lock))) { printExpr(tree.lock); } else { print("("); @@ -1077,7 +1036,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitIf(JCIf tree) { try { print("if "); - if (getTag(tree.cond) == PARENS) { + if (PARENS.equals(treeTag(tree.cond))) { printExpr(tree.cond); } else { print("("); @@ -1173,7 +1132,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitApply(JCMethodInvocation tree) { try { if (!tree.typeargs.isEmpty()) { - if (getTag(tree.meth) == SELECT) { + if (SELECT.equals(treeTag(tree.meth))) { JCFieldAccess left = (JCFieldAccess)tree.meth; printExpr(left.selected); print(".<"); @@ -1277,7 +1236,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { } } - public String operatorName(int tag) { + public String operatorName(TreeTag tag) { String result = OPERATORS.get(tag); if (result == null) throw new Error(); return result; @@ -1287,7 +1246,8 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { try { open(prec, TreeInfo.assignopPrec); printExpr(tree.lhs, TreeInfo.assignopPrec + 1); - print(" " + operatorName(getTag(tree) - JCTree.ASGOffset) + "= "); + String opname = operatorName(treeTag(tree)); + print(" " + opname + " "); printExpr(tree.rhs, TreeInfo.assignopPrec); close(prec, TreeInfo.assignopPrec); } catch (IOException e) { @@ -1297,10 +1257,10 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { public void visitUnary(JCUnary tree) { try { - int ownprec = TreeInfo.opPrec(getTag(tree)); - String opname = operatorName(getTag(tree)); + int ownprec = isOwnPrec(tree); + String opname = operatorName(treeTag(tree)); open(prec, ownprec); - if (getTag(tree) <= Javac.getCtcInt(JCTree.class, "PREDEC")) { + if (isPrefixUnary(tree)) { print(opname); printExpr(tree.arg, ownprec); } else { @@ -1312,11 +1272,19 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { throw new UncheckedIOException(e); } } - + + private int isOwnPrec(JCExpression tree) { + return treeTag(tree).getOperatorPrecedenceLevel(); + } + + private boolean isPrefixUnary(JCUnary tree) { + return treeTag(tree).isPrefixUnaryOp(); + } + public void visitBinary(JCBinary tree) { try { - int ownprec = TreeInfo.opPrec(getTag(tree)); - String opname = operatorName(getTag(tree)); + int ownprec = isOwnPrec(tree); + String opname = operatorName(treeTag(tree)); open(prec, ownprec); printExpr(tree.lhs, ownprec); print(" " + opname + " "); @@ -1381,78 +1349,39 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { } public void visitLiteral(JCLiteral tree) { + TypeTag typeTag = typeTag(tree); try { - switch (tree.typetag) { - case TypeTags.INT: - print(tree.value.toString()); - break; - case TypeTags.LONG: - print(tree.value + "L"); - break; - case TypeTags.FLOAT: - print(tree.value + "F"); - break; - case TypeTags.DOUBLE: - print(tree.value.toString()); - break; - case TypeTags.CHAR: - print("\'" + - Convert.quote( - String.valueOf((char)((Number)tree.value).intValue())) + - "\'"); - break; - case TypeTags.BOOLEAN: - print(((Number)tree.value).intValue() == 1 ? "true" : "false"); - break; - case TypeTags.BOT: - print("null"); - break; - default: - print("\"" + Convert.quote(tree.value.toString()) + "\""); - break; + if (CTC_INT.equals(typeTag)) print(tree.value.toString()); + else if (CTC_LONG.equals(typeTag)) print(tree.value + "L"); + else if (CTC_FLOAT.equals(typeTag)) print(tree.value + "F"); + else if (CTC_DOUBLE.equals(typeTag)) print(tree.value.toString()); + else if (CTC_CHAR.equals(typeTag)) { + print("\'" + Convert.quote(String.valueOf((char)((Number)tree.value).intValue())) + "\'"); } + else if (CTC_BOOLEAN.equals(typeTag)) print(((Number)tree.value).intValue() == 1 ? "true" : "false"); + else if (CTC_BOT.equals(typeTag)) print("null"); + else print("\"" + Convert.quote(tree.value.toString()) + "\""); } catch (IOException e) { throw new UncheckedIOException(e); } } - public void visitTypeIdent(JCPrimitiveTypeTree tree) { - try { - switch(tree.typetag) { - case TypeTags.BYTE: - print("byte"); - break; - case TypeTags.CHAR: - print("char"); - break; - case TypeTags.SHORT: - print("short"); - break; - case TypeTags.INT: - print("int"); - break; - case TypeTags.LONG: - print("long"); - break; - case TypeTags.FLOAT: - print("float"); - break; - case TypeTags.DOUBLE: - print("double"); - break; - case TypeTags.BOOLEAN: - print("boolean"); - break; - case TypeTags.VOID: - print("void"); - break; - default: - print("error"); - break; - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } + public void visitTypeIdent(JCPrimitiveTypeTree tree) { + TypeTag typetag = typeTag(tree); + try { + if (CTC_BYTE.equals(typetag)) print ("byte"); + else if (CTC_CHAR.equals(typetag)) print ("char"); + else if (CTC_SHORT.equals(typetag)) print ("short"); + else if (CTC_INT.equals(typetag)) print ("int"); + else if (CTC_LONG.equals(typetag)) print ("long"); + else if (CTC_FLOAT.equals(typetag)) print ("float"); + else if (CTC_DOUBLE.equals(typetag)) print ("double"); + else if (CTC_BOOLEAN.equals(typetag)) print ("boolean"); + else if (CTC_VOID.equals(typetag)) print ("void"); + else print("error"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } } public void visitTypeArray(JCArrayTypeTree tree) { |