From 6a02cb40137788e6f77919c762b72b3d5880d2da Mon Sep 17 00:00:00 2001 From: Roel Spilker Date: Mon, 9 Sep 2013 23:54:28 +0200 Subject: [jdk8support] We now handle doc comments internally, alleviating the need to try and keep up with the complete rewrites of the doc comment parser from java6 to java7 to java8. Still doesn't actually work in jdk8, but only because of a last-mile issue. (we communicate the doc comment via compilationUnit.docComments but that changed types in jdk8, we just need to make a wrapper to make that work). --- src/delombok/lombok/delombok/Delombok.java | 4 + .../lombok/delombok/DocCommentIntegrator.java | 97 ++++++++++++++++++++++ .../lombok/delombok/PrettyCommentsPrinter.java | 42 ++-------- src/utils/lombok/javac/CommentCatcher.java | 13 ++- src/utils/lombok/javac/Javac.java | 11 +++ 5 files changed, 131 insertions(+), 36 deletions(-) create mode 100644 src/delombok/lombok/delombok/DocCommentIntegrator.java (limited to 'src') diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index 1fae4560..0128e44f 100644 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -383,6 +383,10 @@ public class Delombok { return false; } + for (JCCompilationUnit unit : roots) { + catcher.setComments(unit, new DocCommentIntegrator().integrate(catcher.getComments(unit), unit)); + } + com.sun.tools.javac.util.List trees = compiler.enterTrees(toJavacList(roots)); JavaCompiler delegate = compiler.processAnnotations(trees); diff --git a/src/delombok/lombok/delombok/DocCommentIntegrator.java b/src/delombok/lombok/delombok/DocCommentIntegrator.java new file mode 100644 index 00000000..80aec16a --- /dev/null +++ b/src/delombok/lombok/delombok/DocCommentIntegrator.java @@ -0,0 +1,97 @@ +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 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 integrate(List comments, JCCompilationUnit unit) { + List out = new ArrayList(); + 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, 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) map_).put(node, docCommentContent); + return true; + } + + return false; + } + + private JCTree findJavadocableNodeOnOrAfter(JCCompilationUnit unit, int endPos) { + if (unit.pid != null && endPos <= unit.pid.pos) return null; + Iterator 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 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/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index 9978a681..525773f4 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -29,18 +29,14 @@ */ 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; @@ -49,19 +45,11 @@ import lombok.javac.CommentInfo.EndConnection; import lombok.javac.CommentInfo.StartConnection; import lombok.javac.JavacTreeMaker.TreeTag; import lombok.javac.JavacTreeMaker.TypeTag; -import static lombok.javac.Javac.*; -import static lombok.javac.JavacTreeMaker.TreeTag.treeTag; -import static lombok.javac.JavacTreeMaker.TypeTag.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.main.JavaCompiler; 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; @@ -113,10 +101,13 @@ 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.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. * @@ -198,13 +189,7 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { 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); - } + printComment(head); comments = comments.tail; head = comments.head; } @@ -213,17 +198,6 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { } } - private boolean noFurtherJavadocForthcoming(int until) { - List 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 consumeTrailingComments(int from) throws IOException { boolean prevNewLine = onNewLine; CommentInfo head = comments.head; diff --git a/src/utils/lombok/javac/CommentCatcher.java b/src/utils/lombok/javac/CommentCatcher.java index 48dd7e75..36d90e30 100644 --- a/src/utils/lombok/javac/CommentCatcher.java +++ b/src/utils/lombok/javac/CommentCatcher.java @@ -22,13 +22,14 @@ package lombok.javac; import java.lang.reflect.InvocationTargetException; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.WeakHashMap; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.List; public class CommentCatcher { private final JavaCompiler compiler; @@ -56,9 +57,17 @@ public class CommentCatcher { return compiler; } + public void setComments(JCCompilationUnit ast, List comments) { + if (comments != null) { + commentsMap.put(ast, comments); + } else { + commentsMap.remove(ast); + } + } + public List getComments(JCCompilationUnit ast) { List list = commentsMap.get(ast); - return list == null ? List.nil() : list; + return list == null ? Collections.emptyList() : list; } private static void registerCommentsCollectingScannerFactory(Context context) { diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index c90b8611..2f3c9be4 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -27,6 +27,7 @@ import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.HashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -196,6 +197,16 @@ public class Javac { } } + public static void initDocComments(JCCompilationUnit cu) { + try { + JCCOMPILATIONUNIT_DOCCOMMENTS.set(cu, new HashMap()); + } catch (IllegalArgumentException e) { + // That's fine - we're on JDK8, we'll fix that later. + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } + } + public static int getEndPosition(DiagnosticPosition pos, JCCompilationUnit top) { try { Object endPositions = JCCOMPILATIONUNIT_ENDPOSITIONS.get(top); -- cgit