From d0d2dd6f5d1b9bd33e9e127f8d66b3387f487271 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Sun, 28 Jul 2013 07:16:12 +0200 Subject: Some work on actually making lombok work on JDK8's javac. --- src/core/lombok/javac/JavacAST.java | 2 +- src/core/lombok/javac/JavacNode.java | 9 + .../lombok/javac/handlers/JavacHandlerUtil.java | 12 +- .../lombok/delombok/PrettyCommentsPrinter.java | 225 +++++++++++---------- src/utils/lombok/javac/JavacTreeMaker.java | 58 +++++- 5 files changed, 184 insertions(+), 122 deletions(-) (limited to 'src') diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index 1f3b04a4..e49d8ac8 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -375,7 +375,7 @@ public class JavacAST extends AST { if (pos == null) pos = astObject.pos(); } if (pos != null && attemptToRemoveErrorsInRange) { - removeFromDeferredDiagnostics(pos.getStartPosition(), pos.getEndPosition(top.endPositions)); + removeFromDeferredDiagnostics(pos.getStartPosition(), node.getEndPosition(pos)); } try { switch (kind) { diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java index 30a470a9..6eef36eb 100644 --- a/src/core/lombok/javac/JavacNode.java +++ b/src/core/lombok/javac/JavacNode.java @@ -51,6 +51,15 @@ public class JavacNode extends lombok.core.LombokNode docComments = (Map) dc; + String javadoc = docComments.get(from.get()); if (javadoc != null) { String[] filtered = copyMode.split(javadoc); - cu.docComments.put(to, filtered[0]); - cu.docComments.put(from.get(), filtered[1]); + docComments.put(to, filtered[0]); + docComments.put(from.get(), filtered[1]); } } } catch (Exception ignore) {} diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index fd0b0f0d..9978a681 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -131,12 +131,12 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { private static final TreeTag IMPORT = treeTag("IMPORT"); private static final TreeTag VARDEF = treeTag("VARDEF"); private static final TreeTag SELECT = treeTag("SELECT"); - + private static final Map OPERATORS; static { - Map map = new HashMap(); - + Map map = new HashMap(); + map.put(treeTag("POS"), "+"); map.put(treeTag("NEG"), "-"); map.put(treeTag("NOT"), "!"); @@ -165,132 +165,133 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { map.put(treeTag("MUL"), "*"); map.put(treeTag("DIV"), "/"); map.put(treeTag("MOD"), "%"); - - OPERATORS = map; + + OPERATORS = map; } - private List 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 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 comments) { this.out = out; - this.comments = comments; - this.cu = cu; + this.comments = comments; + this.cu = cu; + } + + private int endPos(JCTree tree) { + return getEndPosition(tree, cu); + } + + private void consumeComments(int until) throws IOException { + consumeComments(until, null); } - - 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(); - } - } + 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 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; + 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; - 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) */ @@ -304,19 +305,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. @@ -325,7 +326,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. @@ -334,7 +335,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 { diff --git a/src/utils/lombok/javac/JavacTreeMaker.java b/src/utils/lombok/javac/JavacTreeMaker.java index edbf55af..12baf5af 100644 --- a/src/utils/lombok/javac/JavacTreeMaker.java +++ b/src/utils/lombok/javac/JavacTreeMaker.java @@ -116,6 +116,18 @@ public class JavacTreeMaker { this.paramTypes = types; this.returnType = returnType; } + + @Override public String toString() { + StringBuilder out = new StringBuilder(); + out.append(returnType.getName()).append(" ").append(owner.getName()).append(".").append(name).append("("); + boolean f = true; + for (Class p : paramTypes) { + if (f) f = false; + else out.append(", "); + out.append(p.getName()); + } + return out.append(")").toString(); + } } private static class SchroedingerType { @@ -154,13 +166,23 @@ public class JavacTreeMaker { return value; } - static Object getFieldCached(ConcurrentMap, Field> cache, Object ref, String fieldName) { + private static Field NOSUCHFIELDEX_MARKER; + static { + try { + NOSUCHFIELDEX_MARKER = SchroedingerType.class.getDeclaredField("NOSUCHFIELDEX_MARKER"); + } catch (NoSuchFieldException e) { + throw Javac.sneakyThrow(e); + } + } + + static Object getFieldCached(ConcurrentMap, Field> cache, Object ref, String fieldName) throws NoSuchFieldException { Class c = ref.getClass(); Field field = cache.get(c); if (field == null) { try { field = c.getField(fieldName); } catch (NoSuchFieldException e) { + cache.putIfAbsent(c, NOSUCHFIELDEX_MARKER); throw Javac.sneakyThrow(e); } field.setAccessible(true); @@ -168,6 +190,7 @@ public class JavacTreeMaker { if (old != null) field = old; } + if (field == NOSUCHFIELDEX_MARKER) throw new NoSuchFieldException(fieldName); try { return field.get(ref); } catch (IllegalAccessException e) { @@ -179,17 +202,42 @@ public class JavacTreeMaker { public static class TypeTag extends SchroedingerType { private static final ConcurrentMap TYPE_TAG_CACHE = new ConcurrentHashMap(); private static final ConcurrentMap, Field> FIELD_CACHE = new ConcurrentHashMap, Field>(); + private static final Method TYPE_TYPETAG_METHOD; + + static { + Method m = null; + try { + m = Type.class.getDeclaredMethod("getTag"); + m.setAccessible(true); + } catch (NoSuchMethodException e) {} + TYPE_TYPETAG_METHOD = m; + } private TypeTag(Object value) { super(value); } public static TypeTag typeTag(JCTree o) { - return new TypeTag(getFieldCached(FIELD_CACHE, o, "typetag")); + try { + return new TypeTag(getFieldCached(FIELD_CACHE, o, "typetag")); + } catch (NoSuchFieldException e) { + throw Javac.sneakyThrow(e); + } } public static TypeTag typeTag(Type t) { - return new TypeTag(getFieldCached(FIELD_CACHE, t, "tag")); + try { + return new TypeTag(getFieldCached(FIELD_CACHE, t, "tag")); + } catch (NoSuchFieldException e) { + if (TYPE_TYPETAG_METHOD == null) throw new IllegalStateException("Type " + t.getClass() + " has neither 'tag' nor getTag()"); + try { + return new TypeTag(TYPE_TYPETAG_METHOD.invoke(t)); + } catch (IllegalAccessException ex) { + throw Javac.sneakyThrow(ex); + } catch (InvocationTargetException ex) { + throw Javac.sneakyThrow(ex.getCause()); + } + } } public static TypeTag typeTag(String identifier) { @@ -331,7 +379,7 @@ public class JavacTreeMaker { if (found == null) found = method; else throw new IllegalStateException("Lombok TreeMaker frontend issue: multiple matches when looking for method: " + m); } - if (found == null) throw new IllegalStateException("Lombok TreeMaker frontedn issue: no match when looking for method: " + m); + if (found == null) throw new IllegalStateException("Lombok TreeMaker frontend issue: no match when looking for method: " + m); found.setAccessible(true); Object marker = METHOD_CACHE.putIfAbsent(m, found); if (marker == null) return found; @@ -496,7 +544,7 @@ public class JavacTreeMaker { //javac versions: 6-8 private static final MethodId Throw = MethodId("Throw"); - public JCThrow Throw(JCTree expr) { + public JCThrow Throw(JCExpression expr) { return invoke(Throw, expr); } -- cgit