From 1c77e9aaad1554280f9620de799bd20ab29de6ea Mon Sep 17 00:00:00 2001 From: Roel Spilker Date: Wed, 25 Nov 2009 11:40:36 +0100 Subject: Work in progress on delombok. --- src/delombok/lombok/delombok/Comment.java | 36 + .../lombok/delombok/PrettyCommentsPrinter.java | 1355 ++++++++++++++++++++ src/delombok/lombok/delombok/PrettyPrinter.java | 199 +++ 3 files changed, 1590 insertions(+) create mode 100644 src/delombok/lombok/delombok/Comment.java create mode 100644 src/delombok/lombok/delombok/PrettyCommentsPrinter.java create mode 100644 src/delombok/lombok/delombok/PrettyPrinter.java (limited to 'src') diff --git a/src/delombok/lombok/delombok/Comment.java b/src/delombok/lombok/delombok/Comment.java new file mode 100644 index 00000000..6f6910b4 --- /dev/null +++ b/src/delombok/lombok/delombok/Comment.java @@ -0,0 +1,36 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * 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; + +class Comment { + final int pos; + final String content; + + Comment(int pos, String content) { + this.pos = pos; + this.content = content; + } + + public String summary() { + return String.format("%d: %s", pos, content); + } +} diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java new file mode 100644 index 00000000..68e503a7 --- /dev/null +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -0,0 +1,1355 @@ +/* + * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +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 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.Map; + +import com.sun.source.tree.Tree; +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; +import com.sun.tools.javac.tree.JCTree.JCAssert; +import com.sun.tools.javac.tree.JCTree.JCAssign; +import com.sun.tools.javac.tree.JCTree.JCAssignOp; +import com.sun.tools.javac.tree.JCTree.JCBinary; +import com.sun.tools.javac.tree.JCTree.JCBlock; +import com.sun.tools.javac.tree.JCTree.JCBreak; +import com.sun.tools.javac.tree.JCTree.JCCase; +import com.sun.tools.javac.tree.JCTree.JCCatch; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCConditional; +import com.sun.tools.javac.tree.JCTree.JCContinue; +import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop; +import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; +import com.sun.tools.javac.tree.JCTree.JCErroneous; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCExpressionStatement; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import com.sun.tools.javac.tree.JCTree.JCForLoop; +import com.sun.tools.javac.tree.JCTree.JCIdent; +import com.sun.tools.javac.tree.JCTree.JCIf; +import com.sun.tools.javac.tree.JCTree.JCImport; +import com.sun.tools.javac.tree.JCTree.JCInstanceOf; +import com.sun.tools.javac.tree.JCTree.JCLabeledStatement; +import com.sun.tools.javac.tree.JCTree.JCLiteral; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.JCModifiers; +import com.sun.tools.javac.tree.JCTree.JCNewArray; +import com.sun.tools.javac.tree.JCTree.JCNewClass; +import com.sun.tools.javac.tree.JCTree.JCParens; +import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree; +import com.sun.tools.javac.tree.JCTree.JCReturn; +import com.sun.tools.javac.tree.JCTree.JCSkip; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCSwitch; +import com.sun.tools.javac.tree.JCTree.JCSynchronized; +import com.sun.tools.javac.tree.JCTree.JCThrow; +import com.sun.tools.javac.tree.JCTree.JCTry; +import com.sun.tools.javac.tree.JCTree.JCTypeApply; +import com.sun.tools.javac.tree.JCTree.JCTypeCast; +import com.sun.tools.javac.tree.JCTree.JCTypeParameter; +import com.sun.tools.javac.tree.JCTree.JCUnary; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +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.util.Convert; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Name; + +/** Prints out a tree as an indented Java source program. + * + *

This is NOT part of any API supported by Sun Microsystems. If + * you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class PrettyCommentsPrinter extends JCTree.Visitor { + + private static final Method GET_TAG_METHOD; + private static final Field TAG_FIELD; + static { + Method m = null; + Field f = null; + try { + m = JCTree.class.getDeclaredMethod("getTag"); + System.out.println("Using getTag method"); + } + catch (NoSuchMethodException e) { + try { + f = JCTree.class.getDeclaredField("tag"); + System.out.println("Using tag field"); + } + catch (NoSuchFieldException e1) { + e1.printStackTrace(); + } + } + GET_TAG_METHOD = m; + TAG_FIELD = f; + } + + 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 comments; + private final JCCompilationUnit cu; + private boolean newLine = true; + + public PrettyCommentsPrinter(Writer out, List comments, JCCompilationUnit cu) { + this.out = out; + this.comments = comments; + this.cu = cu; + } + + private int endPos(JCTree tree) { + return tree.getEndPosition(cu.endPositions); + } + + private void consumeComments(int till) throws IOException { + boolean shouldIndent = !newLine; + while (comments.nonEmpty() && comments.head.pos < till) { + if (newLine) { + align(); + } + print(comments.head.content); + println(); + comments = comments.tail; + } + if (newLine && shouldIndent) { + align(); + } + } + + /** The output stream on which trees are printed. + */ + Writer out; + + /** Indentation width (can be reassigned from outside). + */ + public int width = 4; + + /** 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 docComments = null; + + /** Align code to be indented to left margin. + */ + void align() throws IOException { + newLine = false; + for (int i = 0; i < lmargin; i++) out.write(" "); + } + + /** Increase left margin by indentation width. + */ + void indent() { + lmargin = lmargin + width; + } + + /** Decrease left margin by indentation width. + */ + void undent() { + lmargin = lmargin - width; + } + + /** 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. + * @param ownPrec The new precedence level. + */ + 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. + * @param ownPrec The inner precedence level. + */ + 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 { + newLine = false; + out.write(Convert.escapeUnicode(s.toString())); + } + + /** Print new line. + */ + public void println() throws IOException { + newLine = true; + out.write(lineSep); + } + + String lineSep = System.getProperty("line.separator"); + + /************************************************************************** + * Traversal methods + *************************************************************************/ + + /** Exception to propogate IOException through visitXXX methods */ + private static class UncheckedIOException extends Error { + static final long serialVersionUID = -4032692679158424751L; + UncheckedIOException(IOException e) { + super(e.getMessage(), e); + } + } + + /** Visitor argument: the current precedence level. + */ + int prec; + + /** Visitor method: print expression tree. + * @param prec The current precedence level. + */ + public void printExpr(JCTree tree, int prec) throws IOException { + + int prevPrec = this.prec; + try { + this.prec = prec; + if (tree == null) print("/*missing*/"); + else { + consumeComments(tree.pos); + tree.accept(this); + consumeComments(endPos(tree)); + } + } catch (UncheckedIOException ex) { + IOException e = new IOException(ex.getMessage()); + e.initCause(ex); + throw e; + } finally { + this.prec = prevPrec; + } + } + + /** Derived visitor method: print expression tree at minimum precedence level + * for expression. + */ + public void printExpr(JCTree tree) throws IOException { + printExpr(tree, TreeInfo.noPrec); + } + + /** Derived visitor method: print statement tree. + */ + 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 + */ + public void printExprs(List trees, String sep) throws IOException { + if (trees.nonEmpty()) { + printExpr(trees.head); + for (List l = trees.tail; l.nonEmpty(); l = l.tail) { + print(sep); + printExpr(l.head); + } + } + } + + /** Derived visitor method: print list of expression trees, separated by commas. + */ + public void printExprs(List trees) throws IOException { + printExprs(trees, ", "); + } + + /** Derived visitor method: print list of statements, each on a separate line. + */ + public void printStats(List trees) throws IOException { + for (List l = trees; l.nonEmpty(); l = l.tail) { + align(); + printStat(l.head); + println(); + } + } + + /** Print a set of modifiers. + */ + public void printFlags(long flags) throws IOException { + if ((flags & SYNTHETIC) != 0) print("/*synthetic*/ "); + print(TreeInfo.flagNames(flags)); + if ((flags & StandardFlags) != 0) print(" "); + if ((flags & ANNOTATION) != 0) print("@"); + } + + public void printAnnotations(List trees) throws IOException { + for (List l = trees; l.nonEmpty(); l = l.tail) { + printStat(l.head); + println(); + align(); + } + } + + /** Print documentation comment, if it exists + * @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); + while (pos < dc.length()) { + 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) { + int pos = s.indexOf('\n', start); + if (pos < 0) pos = s.length(); + return pos; + } + + /** If type parameter list is non-empty, print it enclosed in "<...>" brackets. + */ + public void printTypeParameters(List trees) throws IOException { + if (trees.nonEmpty()) { + print("<"); + printExprs(trees); + print(">"); + } + } + + /** Print a block. + */ + public void printBlock(List stats, JCTree container) throws IOException { + print("{"); + println(); + indent(); + printStats(stats); + consumeComments(endPos(container)); + undent(); + align(); + print("}"); + } + + /** Print a block. + */ + public void printEnumBody(List stats) throws IOException { + print("{"); + println(); + indent(); + boolean first = true; + for (List l = stats; l.nonEmpty(); l = l.tail) { + if (isEnumerator(l.head)) { + if (!first) { + print(","); + println(); + } + align(); + printStat(l.head); + first = false; + } + } + print(";"); + println(); + for (List l = stats; l.nonEmpty(); l = l.tail) { + if (!isEnumerator(l.head)) { + align(); + printStat(l.head); + println(); + } + } + undent(); + align(); + print("}"); + } + + /** Is the given tree an enumerator definition? */ + boolean isEnumerator(JCTree t) { + return getTag(t) == JCTree.VARDEF && (((JCVariableDecl) t).mods.flags & ENUM) != 0; + } + + /** Print unit consisting of package clause and import statements in toplevel, + * followed by class definition. if class definition == null, + * print all definitions in toplevel. + * @param tree The toplevel tree + * @param cdef The class definition, which is assumed to be part of the + * toplevel tree. + */ + public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException { + docComments = tree.docComments; + printDocComment(tree); + if (tree.pid != null) { + print("package "); + printExpr(tree.pid); + print(";"); + println(); + } + boolean firstImport = true; + for (List l = tree.defs; + l.nonEmpty() && (cdef == null || getTag(l.head) == JCTree.IMPORT); + l = l.tail) { + if (getTag(l.head) == JCTree.IMPORT) { + JCImport imp = (JCImport)l.head; + Name name = TreeInfo.name(imp.qualid); + if (name == name.table.asterisk || + cdef == null || + isUsed(TreeInfo.symbol(imp.qualid), cdef)) { + if (firstImport) { + firstImport = false; + println(); + } + printStat(imp); + } + } else { + printStat(l.head); + } + } + if (cdef != null) { + printStat(cdef); + println(); + } + } + // where + boolean isUsed(final Symbol t, JCTree cdef) { + class UsedVisitor extends TreeScanner { + public void scan(JCTree tree) { + if (tree!=null && !result) tree.accept(this); + } + boolean result = false; + public void visitIdent(JCIdent tree) { + if (tree.sym == t) result = true; + } + } + UsedVisitor v = new UsedVisitor(); + v.scan(cdef); + return v.result; + } + + /************************************************************************** + * Visitor methods + *************************************************************************/ + + public void visitTopLevel(JCCompilationUnit tree) { + try { + printUnit(tree, null); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitImport(JCImport tree) { + try { + print("import "); + if (tree.staticImport) print("static "); + printExpr(tree.qualid); + print(";"); + println(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitClassDef(JCClassDecl tree) { + try { + consumeComments(tree.pos); + println(); align(); + printDocComment(tree); + printAnnotations(tree.mods.annotations); + printFlags(tree.mods.flags & ~INTERFACE); + Name enclClassNamePrev = enclClassName; + enclClassName = tree.name; + if ((tree.mods.flags & INTERFACE) != 0) { + print("interface " + tree.name); + printTypeParameters(tree.typarams); + if (tree.implementing.nonEmpty()) { + print(" extends "); + printExprs(tree.implementing); + } + } else { + if ((tree.mods.flags & ENUM) != 0) + print("enum " + tree.name); + else + print("class " + tree.name); + printTypeParameters(tree.typarams); + if (tree.extending != null) { + print(" extends "); + printExpr(tree.extending); + } + if (tree.implementing.nonEmpty()) { + print(" implements "); + printExprs(tree.implementing); + } + } + print(" "); + if ((tree.mods.flags & ENUM) != 0) { + printEnumBody(tree.defs); + } else { + printBlock(tree.defs, tree); + } + enclClassName = enclClassNamePrev; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitMethodDef(JCMethodDecl tree) { + try { + // when producing source output, omit anonymous constructors + if (tree.name == tree.name.table.init && + enclClassName == null) return; + println(); align(); + printDocComment(tree); + printExpr(tree.mods); + printTypeParameters(tree.typarams); + if (tree.name == tree.name.table.init) { + print(enclClassName != null ? enclClassName : tree.name); + } else { + printExpr(tree.restype); + print(" " + tree.name); + } + print("("); + printExprs(tree.params); + print(")"); + if (tree.thrown.nonEmpty()) { + print(" throws "); + printExprs(tree.thrown); + } + if (tree.body != null) { + print(" "); + printStat(tree.body); + } else { + print(";"); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitVarDef(JCVariableDecl tree) { + try { + if (docComments != null && docComments.get(tree) != null) { + println(); align(); + } + printDocComment(tree); + if ((tree.mods.flags & ENUM) != 0) { + print("/*public static final*/ "); + print(tree.name); + if (tree.init != null) { + print(" /* = "); + printExpr(tree.init); + print(" */"); + } + } else { + printExpr(tree.mods); + if ((tree.mods.flags & VARARGS) != 0) { + printExpr(((JCArrayTypeTree) tree.vartype).elemtype); + print("... " + tree.name); + } else { + printExpr(tree.vartype); + print(" " + tree.name); + } + if (tree.init != null) { + print(" = "); + printExpr(tree.init); + } + if (prec == TreeInfo.notExpression) print(";"); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitSkip(JCSkip tree) { + try { + print(";"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitBlock(JCBlock tree) { + try { + consumeComments(tree.pos); + printFlags(tree.flags); + printBlock(tree.stats, tree); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitDoLoop(JCDoWhileLoop tree) { + try { + print("do "); + printStat(tree.body); + align(); + print(" while "); + if (getTag(tree.cond) == JCTree.PARENS) { + printExpr(tree.cond); + } else { + print("("); + printExpr(tree.cond); + print(")"); + } + print(";"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitWhileLoop(JCWhileLoop tree) { + try { + print("while "); + if (getTag(tree.cond) == JCTree.PARENS) { + printExpr(tree.cond); + } else { + print("("); + printExpr(tree.cond); + print(")"); + } + print(" "); + printStat(tree.body); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitForLoop(JCForLoop tree) { + try { + print("for ("); + if (tree.init.nonEmpty()) { + if (getTag(tree.init.head) == JCTree.VARDEF) { + printExpr(tree.init.head); + for (List l = tree.init.tail; l.nonEmpty(); l = l.tail) { + JCVariableDecl vdef = (JCVariableDecl)l.head; + print(", " + vdef.name + " = "); + printExpr(vdef.init); + } + } else { + printExprs(tree.init); + } + } + print("; "); + if (tree.cond != null) printExpr(tree.cond); + print("; "); + printExprs(tree.step); + print(") "); + printStat(tree.body); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitForeachLoop(JCEnhancedForLoop tree) { + try { + print("for ("); + printExpr(tree.var); + print(" : "); + printExpr(tree.expr); + print(") "); + printStat(tree.body); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitLabelled(JCLabeledStatement tree) { + try { + print(tree.label + ": "); + printStat(tree.body); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitSwitch(JCSwitch tree) { + try { + print("switch "); + if (getTag(tree.selector) == JCTree.PARENS) { + printExpr(tree.selector); + } else { + print("("); + printExpr(tree.selector); + print(")"); + } + print(" {"); + println(); + printStats(tree.cases); + align(); + print("}"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitCase(JCCase tree) { + try { + if (tree.pat == null) { + print("default"); + } else { + print("case "); + printExpr(tree.pat); + } + print(": "); + println(); + indent(); + printStats(tree.stats); + undent(); + align(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitSynchronized(JCSynchronized tree) { + try { + print("synchronized "); + if (getTag(tree.lock) == JCTree.PARENS) { + printExpr(tree.lock); + } else { + print("("); + printExpr(tree.lock); + print(")"); + } + print(" "); + printStat(tree.body); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitTry(JCTry tree) { + try { + print("try "); + printStat(tree.body); + for (List l = tree.catchers; l.nonEmpty(); l = l.tail) { + printStat(l.head); + } + if (tree.finalizer != null) { + print(" finally "); + printStat(tree.finalizer); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitCatch(JCCatch tree) { + try { + print(" catch ("); + printExpr(tree.param); + print(") "); + printStat(tree.body); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitConditional(JCConditional tree) { + try { + open(prec, TreeInfo.condPrec); + printExpr(tree.cond, TreeInfo.condPrec); + print(" ? "); + printExpr(tree.truepart, TreeInfo.condPrec); + print(" : "); + printExpr(tree.falsepart, TreeInfo.condPrec); + close(prec, TreeInfo.condPrec); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitIf(JCIf tree) { + try { + print("if "); + if (getTag(tree.cond) == JCTree.PARENS) { + printExpr(tree.cond); + } else { + print("("); + printExpr(tree.cond); + print(")"); + } + print(" "); + printStat(tree.thenpart); + if (tree.elsepart != null) { + print(" else "); + printStat(tree.elsepart); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitExec(JCExpressionStatement tree) { + try { + printExpr(tree.expr); + if (prec == TreeInfo.notExpression) print(";"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitBreak(JCBreak tree) { + try { + print("break"); + if (tree.label != null) print(" " + tree.label); + print(";"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitContinue(JCContinue tree) { + try { + print("continue"); + if (tree.label != null) print(" " + tree.label); + print(";"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitReturn(JCReturn tree) { + try { + print("return"); + if (tree.expr != null) { + print(" "); + printExpr(tree.expr); + } + print(";"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitThrow(JCThrow tree) { + try { + print("throw "); + printExpr(tree.expr); + print(";"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitAssert(JCAssert tree) { + try { + print("assert "); + printExpr(tree.cond); + if (tree.detail != null) { + print(" : "); + printExpr(tree.detail); + } + print(";"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitApply(JCMethodInvocation tree) { + try { + if (!tree.typeargs.isEmpty()) { + if (getTag(tree.meth) == JCTree.SELECT) { + JCFieldAccess left = (JCFieldAccess)tree.meth; + printExpr(left.selected); + print(".<"); + printExprs(tree.typeargs); + print(">" + left.name); + } else { + print("<"); + printExprs(tree.typeargs); + print(">"); + printExpr(tree.meth); + } + } else { + printExpr(tree.meth); + } + print("("); + printExprs(tree.args); + print(")"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitNewClass(JCNewClass tree) { + try { + if (tree.encl != null) { + printExpr(tree.encl); + print("."); + } + print("new "); + if (!tree.typeargs.isEmpty()) { + print("<"); + printExprs(tree.typeargs); + print(">"); + } + printExpr(tree.clazz); + print("("); + printExprs(tree.args); + print(")"); + if (tree.def != null) { + Name enclClassNamePrev = enclClassName; + enclClassName = + tree.def.name != null ? tree.def.name : + tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.empty ? tree.type.tsym.name : + null; + if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/"); + printBlock(tree.def.defs, tree.def); + enclClassName = enclClassNamePrev; + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitNewArray(JCNewArray tree) { + try { + if (tree.elemtype != null) { + print("new "); + JCTree elem = tree.elemtype; + if (elem instanceof JCArrayTypeTree) + printBaseElementType((JCArrayTypeTree) elem); + else + printExpr(elem); + for (List l = tree.dims; l.nonEmpty(); l = l.tail) { + print("["); + printExpr(l.head); + print("]"); + } + if (elem instanceof JCArrayTypeTree) + printBrackets((JCArrayTypeTree) elem); + } + if (tree.elems != null) { + if (tree.elemtype != null) print("[]"); + print("{"); + printExprs(tree.elems); + print("}"); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitParens(JCParens tree) { + try { + print("("); + printExpr(tree.expr); + print(")"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitAssign(JCAssign tree) { + try { + open(prec, TreeInfo.assignPrec); + printExpr(tree.lhs, TreeInfo.assignPrec + 1); + print(" = "); + printExpr(tree.rhs, TreeInfo.assignPrec); + close(prec, TreeInfo.assignPrec); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public String operatorName(int tag) { + switch(tag) { + case JCTree.POS: return "+"; + case JCTree.NEG: return "-"; + case JCTree.NOT: return "!"; + case JCTree.COMPL: return "~"; + case JCTree.PREINC: return "++"; + case JCTree.PREDEC: return "--"; + case JCTree.POSTINC: return "++"; + case JCTree.POSTDEC: return "--"; + case JCTree.NULLCHK: return "<*nullchk*>"; + case JCTree.OR: return "||"; + case JCTree.AND: return "&&"; + case JCTree.EQ: return "=="; + case JCTree.NE: return "!="; + case JCTree.LT: return "<"; + case JCTree.GT: return ">"; + case JCTree.LE: return "<="; + case JCTree.GE: return ">="; + case JCTree.BITOR: return "|"; + case JCTree.BITXOR: return "^"; + case JCTree.BITAND: return "&"; + case JCTree.SL: return "<<"; + case JCTree.SR: return ">>"; + case JCTree.USR: return ">>>"; + case JCTree.PLUS: return "+"; + case JCTree.MINUS: return "-"; + case JCTree.MUL: return "*"; + case JCTree.DIV: return "/"; + case JCTree.MOD: return "%"; + default: throw new Error(); + } + } + + public void visitAssignop(JCAssignOp tree) { + try { + open(prec, TreeInfo.assignopPrec); + printExpr(tree.lhs, TreeInfo.assignopPrec + 1); + print(" " + operatorName(getTag(tree) - JCTree.ASGOffset) + "= "); + printExpr(tree.rhs, TreeInfo.assignopPrec); + close(prec, TreeInfo.assignopPrec); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitUnary(JCUnary tree) { + try { + int ownprec = TreeInfo.opPrec(getTag(tree)); + String opname = operatorName(getTag(tree)); + open(prec, ownprec); + if (getTag(tree) <= JCTree.PREDEC) { + print(opname); + printExpr(tree.arg, ownprec); + } else { + printExpr(tree.arg, ownprec); + print(opname); + } + close(prec, ownprec); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitBinary(JCBinary tree) { + try { + int ownprec = TreeInfo.opPrec(getTag(tree)); + String opname = operatorName(getTag(tree)); + open(prec, ownprec); + printExpr(tree.lhs, ownprec); + print(" " + opname + " "); + printExpr(tree.rhs, ownprec + 1); + close(prec, ownprec); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitTypeCast(JCTypeCast tree) { + try { + open(prec, TreeInfo.prefixPrec); + print("("); + printExpr(tree.clazz); + print(")"); + printExpr(tree.expr, TreeInfo.prefixPrec); + close(prec, TreeInfo.prefixPrec); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitTypeTest(JCInstanceOf tree) { + try { + open(prec, TreeInfo.ordPrec); + printExpr(tree.expr, TreeInfo.ordPrec); + print(" instanceof "); + printExpr(tree.clazz, TreeInfo.ordPrec + 1); + close(prec, TreeInfo.ordPrec); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitIndexed(JCArrayAccess tree) { + try { + printExpr(tree.indexed, TreeInfo.postfixPrec); + print("["); + printExpr(tree.index); + print("]"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitSelect(JCFieldAccess tree) { + try { + printExpr(tree.selected, TreeInfo.postfixPrec); + print("." + tree.name); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitIdent(JCIdent tree) { + try { + print(tree.name); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitLiteral(JCLiteral 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; + } + } 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 visitTypeArray(JCArrayTypeTree tree) { + try { + printBaseElementType(tree); + printBrackets(tree); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + // Prints the inner element type of a nested array + private void printBaseElementType(JCArrayTypeTree tree) throws IOException { + JCTree elem = tree.elemtype; + while (elem instanceof JCWildcard) + elem = ((JCWildcard) elem).inner; + if (elem instanceof JCArrayTypeTree) + printBaseElementType((JCArrayTypeTree) elem); + else + printExpr(elem); + } + + // prints the brackets of a nested array in reverse order + private void printBrackets(JCArrayTypeTree tree) throws IOException { + JCTree elem; + while (true) { + elem = tree.elemtype; + print("[]"); + if (!(elem instanceof JCArrayTypeTree)) break; + tree = (JCArrayTypeTree) elem; + } + } + + public void visitTypeApply(JCTypeApply tree) { + try { + printExpr(tree.clazz); + print("<"); + printExprs(tree.arguments); + print(">"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitTypeParameter(JCTypeParameter tree) { + try { + print(tree.name); + if (tree.bounds.nonEmpty()) { + print(" extends "); + printExprs(tree.bounds, " & "); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + public void visitWildcard(JCWildcard tree) { + try { + print(tree.kind); + + if (tree.getKind() != Tree.Kind.UNBOUNDED_WILDCARD) + printExpr(tree.inner); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitTypeBoundKind(TypeBoundKind tree) { + try { + print(String.valueOf(tree.kind)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitErroneous(JCErroneous tree) { + try { + print("(ERROR)"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitLetExpr(LetExpr tree) { + try { + print("(let " + tree.defs + " in " + tree.expr + ")"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitModifiers(JCModifiers mods) { + try { + printAnnotations(mods.annotations); + printFlags(mods.flags); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitAnnotation(JCAnnotation tree) { + try { + print("@"); + printExpr(tree.annotationType); + print("("); + printExprs(tree.args); + print(")"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void visitTree(JCTree tree) { + try { + print("(UNKNOWN: " + tree + ")"); + println(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java new file mode 100644 index 00000000..2da0d9f4 --- /dev/null +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -0,0 +1,199 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * 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 java.io.BufferedReader; +import java.io.FileReader; +import java.io.StringWriter; +import java.nio.CharBuffer; + +import com.sun.source.tree.Tree; +import com.sun.source.tree.Tree.Kind; +import com.sun.source.util.SimpleTreeVisitor; +import com.sun.source.util.TreeScanner; +import com.sun.tools.javac.main.JavaCompiler; +import com.sun.tools.javac.main.OptionName; +import com.sun.tools.javac.parser.Scanner; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Options; + +public class PrettyPrinter { + + private final Context context = new Context(); + private final JavaCompiler compiler; + + public static void main(String[] args) throws Exception { + if (args.length == 0) { +// System.out.println("Usage: java %s ..."); + args = new String[] {"tests/foo/WithComments.java"}; + } + PrettyPrinter prettyPrinter = new PrettyPrinter(); + for (String fileName : args) { + prettyPrinter.print(fileName); + } + } + + public PrettyPrinter() { + Options.instance(context).put(OptionName.ENCODING, "utf-8"); + PrettyDocCommentScanner.Factory.preRegister(context); + compiler = new JavaCompiler(context) { + @Override + protected boolean keepComments() { + return true; + } + }; + compiler.genEndPos = true; + } + + public static class Comments { +// private static Key commentsKey = new Key(); + + private List comments = List.nil(); + + void add(int pos, String content) { + comments = comments.append(new Comment(pos, content)); + } + } + + private void print(String fileName) throws Exception { + + Comments comments = new Comments(); + context.put(Comments.class, comments); + + @SuppressWarnings("deprecation") + final JCCompilationUnit cu = compiler.parse(fileName); + + StringWriter writer = new StringWriter(); + cu.accept(new PrettyCommentsPrinter(writer, comments.comments, cu)); + System.out.printf("####### Original source of %s #######\n", fileName); + BufferedReader reader = new BufferedReader(new FileReader(fileName)); + String line = null; + while ((line = reader.readLine()) != null) { + System.out.println(line); + } + reader.close(); + + System.out.printf("####### Generated source of %s #######\n", fileName); + System.out.println(writer); + + printNodes(fileName, cu); + System.out.printf("####### Comments of %s #######\n", fileName); + for (Comment comment : comments.comments) { + System.out.println(comment.summary()); + } + System.out.printf("####### End of %s #######\n\n", fileName); + } + + private void printNodes(String fileName, final JCCompilationUnit cu) { + System.out.printf("####### Nodes of %s #######\n", fileName); + cu.accept(new TreeScanner(){ + @Override + public Void scan(Tree node, Void p) { + if (node == null) { + return null; + } + node.accept(new SimpleTreeVisitor(){ + @Override + protected Void defaultAction(Tree node, Void p) { + if (node == null) { + return null; + } + JCTree tree = (JCTree)node; + Kind kind = tree.getKind(); + System.out.print(kind.toString() + " " + tree.pos + " - " + tree.getEndPosition(cu.endPositions)); + switch (kind) { + case IDENTIFIER: + case PRIMITIVE_TYPE: + case MODIFIERS: + System.out.print("[" + tree.toString() + "]"); + break; + } + System.out.println(); + return null; + } + }, null); + return super.scan(node, p); + } + }, null); + } + + public static class PrettyDocCommentScanner extends Scanner { + + private final Comments comments; + + /** A factory for creating scanners. */ + public static class Factory extends Scanner.Factory { + + private final Context context; + + public static void preRegister(final Context context) { + context.put(scannerFactoryKey, new Context.Factory() { + public Factory make() { + return new Factory(context); + } + }); + } + + /** Create a new scanner factory. */ + protected Factory(Context context) { + super(context); + this.context = context; + } + + @Override + public Scanner newScanner(CharSequence input) { + if (input instanceof CharBuffer) { + return new PrettyDocCommentScanner(this, (CharBuffer)input, context.get(Comments.class)); + } + else { + char[] array = input.toString().toCharArray(); + return newScanner(array, array.length); + } + } + + @Override + public Scanner newScanner(char[] input, int inputLength) { + return new PrettyDocCommentScanner(this, input, inputLength, context.get(Comments.class)); + } + } + + + public PrettyDocCommentScanner(PrettyPrinter.PrettyDocCommentScanner.Factory factory, CharBuffer charBuffer, Comments comments) { + super(factory, charBuffer); + this.comments = comments; + } + + + public PrettyDocCommentScanner(PrettyPrinter.PrettyDocCommentScanner.Factory factory, char[] input, int inputLength, Comments comments) { + super(factory, input, inputLength); + this.comments = comments; + } + + @Override + protected void processComment(CommentStyle style) { + comments.add(pos(), new String(getRawCharacters(pos(), endPos()))); + } + } +} -- cgit From 4c73407dc7f68fffd7d3166f6e01118d331d3a68 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Nov 2009 17:34:05 +0100 Subject: Solved or suppressed warnings --- src/delombok/lombok/delombok/PrettyCommentsPrinter.java | 1 + src/delombok/lombok/delombok/PrettyPrinter.java | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index 68e503a7..aa42f2b5 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -107,6 +107,7 @@ import com.sun.tools.javac.util.Name; * This code and its internal interfaces are subject to change or * deletion without notice. */ +@SuppressWarnings("all") // Mainly sun code that has other warning settings public class PrettyCommentsPrinter extends JCTree.Visitor { private static final Method GET_TAG_METHOD; diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index 2da0d9f4..caea38c9 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -115,12 +115,13 @@ public class PrettyPrinter { return null; } node.accept(new SimpleTreeVisitor(){ + @SuppressWarnings("incomplete-switch") @Override - protected Void defaultAction(Tree node, Void p) { - if (node == null) { + protected Void defaultAction(Tree treeNode, Void r) { + if (treeNode == null) { return null; } - JCTree tree = (JCTree)node; + JCTree tree = (JCTree)treeNode; Kind kind = tree.getKind(); System.out.print(kind.toString() + " " + tree.pos + " - " + tree.getEndPosition(cu.endPositions)); switch (kind) { @@ -167,10 +168,8 @@ public class PrettyPrinter { if (input instanceof CharBuffer) { return new PrettyDocCommentScanner(this, (CharBuffer)input, context.get(Comments.class)); } - else { - char[] array = input.toString().toCharArray(); - return newScanner(array, array.length); - } + char[] array = input.toString().toCharArray(); + return newScanner(array, array.length); } @Override -- cgit From 6cd3b8a8ca4809efd2001473f31c881c9f2381ea Mon Sep 17 00:00:00 2001 From: Roel Spilker Date: Thu, 26 Nov 2009 01:45:55 +0100 Subject: Major restructuring+adding tests --- .classpath | 2 + deps/junit-4.7.jar | Bin 0 -> 232354 bytes src/delombok/lombok/delombok/Comment.java | 4 +- .../lombok/delombok/CommentCollectingScanner.java | 85 +++++++++ .../lombok/delombok/CommentPreservingParser.java | 77 ++++++++ .../lombok/delombok/PrettyCommentsPrinter.java | 6 +- src/delombok/lombok/delombok/PrettyPrinter.java | 198 --------------------- test/delombok/resource/after/WithComments.java | 5 + test/delombok/resource/before/WithComments.java | 4 + .../src/lombok/delombok/TestSourceFiles.java | 97 ++++++++++ 10 files changed, 274 insertions(+), 204 deletions(-) create mode 100644 deps/junit-4.7.jar create mode 100644 src/delombok/lombok/delombok/CommentCollectingScanner.java create mode 100644 src/delombok/lombok/delombok/CommentPreservingParser.java delete mode 100644 src/delombok/lombok/delombok/PrettyPrinter.java create mode 100644 test/delombok/resource/after/WithComments.java create mode 100644 test/delombok/resource/before/WithComments.java create mode 100644 test/delombok/src/lombok/delombok/TestSourceFiles.java (limited to 'src') diff --git a/.classpath b/.classpath index 8da629d1..3390740d 100644 --- a/.classpath +++ b/.classpath @@ -5,12 +5,14 @@ + + diff --git a/deps/junit-4.7.jar b/deps/junit-4.7.jar new file mode 100644 index 00000000..700ad695 Binary files /dev/null and b/deps/junit-4.7.jar differ diff --git a/src/delombok/lombok/delombok/Comment.java b/src/delombok/lombok/delombok/Comment.java index 6f6910b4..c264733f 100644 --- a/src/delombok/lombok/delombok/Comment.java +++ b/src/delombok/lombok/delombok/Comment.java @@ -21,11 +21,11 @@ */ package lombok.delombok; -class Comment { +public final class Comment { final int pos; final String content; - Comment(int pos, String content) { + public Comment(int pos, String content) { this.pos = pos; this.content = content; } diff --git a/src/delombok/lombok/delombok/CommentCollectingScanner.java b/src/delombok/lombok/delombok/CommentCollectingScanner.java new file mode 100644 index 00000000..6f593c7f --- /dev/null +++ b/src/delombok/lombok/delombok/CommentCollectingScanner.java @@ -0,0 +1,85 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * 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 java.nio.CharBuffer; + +import lombok.delombok.CommentPreservingParser.Comments; + +import com.sun.tools.javac.parser.Scanner; +import com.sun.tools.javac.util.Context; + +public class CommentCollectingScanner extends Scanner { + + private final Comments comments; + + /** A factory for creating scanners. */ + public static class Factory extends Scanner.Factory { + + private final Context context; + + public static void preRegister(final Context context) { + context.put(scannerFactoryKey, new Context.Factory() { + public CommentCollectingScanner.Factory make() { + return new Factory(context); + } + }); + } + + /** Create a new scanner factory. */ + protected Factory(Context context) { + super(context); + this.context = context; + } + + @Override + public Scanner newScanner(CharSequence input) { + if (input instanceof CharBuffer) { + return new CommentCollectingScanner(this, (CharBuffer)input, context.get(Comments.class)); + } + char[] array = input.toString().toCharArray(); + return newScanner(array, array.length); + } + + @Override + public Scanner newScanner(char[] input, int inputLength) { + return new CommentCollectingScanner(this, input, inputLength, context.get(Comments.class)); + } + } + + + public CommentCollectingScanner(CommentCollectingScanner.Factory factory, CharBuffer charBuffer, Comments comments) { + super(factory, charBuffer); + this.comments = comments; + } + + + public CommentCollectingScanner(CommentCollectingScanner.Factory factory, char[] input, int inputLength, Comments comments) { + super(factory, input, inputLength); + this.comments = comments; + } + + @Override + protected void processComment(CommentStyle style) { + comments.add(pos(), new String(getRawCharacters(pos(), endPos()))); + } +} \ No newline at end of file diff --git a/src/delombok/lombok/delombok/CommentPreservingParser.java b/src/delombok/lombok/delombok/CommentPreservingParser.java new file mode 100644 index 00000000..c85124b5 --- /dev/null +++ b/src/delombok/lombok/delombok/CommentPreservingParser.java @@ -0,0 +1,77 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * 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 java.io.IOException; +import java.io.Writer; + +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 CommentPreservingParser { + private final JavaCompiler compiler; + private final Context context; + + public CommentPreservingParser(Context context) { + this.context = context; + CommentCollectingScanner.Factory.preRegister(context); + compiler = new JavaCompiler(context) { + @Override + protected boolean keepComments() { + return true; + } + }; + compiler.genEndPos = true; + } + + public ParseResult parseFile(String fileName) throws IOException { + Comments comments = new Comments(); + context.put(Comments.class, comments); + @SuppressWarnings("deprecation") + JCCompilationUnit cu = compiler.parse(fileName); + return new ParseResult(comments.comments, cu); + } + + static class Comments { + List comments = List.nil(); + + void add(int pos, String content) { + comments = comments.append(new Comment(pos, content)); + } + } + + public static class ParseResult { + private final List comments; + private final JCCompilationUnit compilationUnit; + + private ParseResult(List comments, JCCompilationUnit compilationUnit) { + this.comments = comments; + this.compilationUnit = compilationUnit; + } + + public void print(Writer out) { + compilationUnit.accept(new PrettyCommentsPrinter(out, compilationUnit, comments)); + } + } +} \ No newline at end of file diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index aa42f2b5..c6b58a31 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -112,17 +112,16 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { private static final Method GET_TAG_METHOD; private static final Field TAG_FIELD; + static { Method m = null; Field f = null; try { m = JCTree.class.getDeclaredMethod("getTag"); - System.out.println("Using getTag method"); } catch (NoSuchMethodException e) { try { f = JCTree.class.getDeclaredField("tag"); - System.out.println("Using tag field"); } catch (NoSuchFieldException e1) { e1.printStackTrace(); @@ -152,12 +151,11 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { } } - private List comments; private final JCCompilationUnit cu; private boolean newLine = true; - public PrettyCommentsPrinter(Writer out, List comments, JCCompilationUnit cu) { + public PrettyCommentsPrinter(Writer out, JCCompilationUnit cu, List comments) { this.out = out; this.comments = comments; this.cu = cu; diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java deleted file mode 100644 index caea38c9..00000000 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. - * - * 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 java.io.BufferedReader; -import java.io.FileReader; -import java.io.StringWriter; -import java.nio.CharBuffer; - -import com.sun.source.tree.Tree; -import com.sun.source.tree.Tree.Kind; -import com.sun.source.util.SimpleTreeVisitor; -import com.sun.source.util.TreeScanner; -import com.sun.tools.javac.main.JavaCompiler; -import com.sun.tools.javac.main.OptionName; -import com.sun.tools.javac.parser.Scanner; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Options; - -public class PrettyPrinter { - - private final Context context = new Context(); - private final JavaCompiler compiler; - - public static void main(String[] args) throws Exception { - if (args.length == 0) { -// System.out.println("Usage: java %s ..."); - args = new String[] {"tests/foo/WithComments.java"}; - } - PrettyPrinter prettyPrinter = new PrettyPrinter(); - for (String fileName : args) { - prettyPrinter.print(fileName); - } - } - - public PrettyPrinter() { - Options.instance(context).put(OptionName.ENCODING, "utf-8"); - PrettyDocCommentScanner.Factory.preRegister(context); - compiler = new JavaCompiler(context) { - @Override - protected boolean keepComments() { - return true; - } - }; - compiler.genEndPos = true; - } - - public static class Comments { -// private static Key commentsKey = new Key(); - - private List comments = List.nil(); - - void add(int pos, String content) { - comments = comments.append(new Comment(pos, content)); - } - } - - private void print(String fileName) throws Exception { - - Comments comments = new Comments(); - context.put(Comments.class, comments); - - @SuppressWarnings("deprecation") - final JCCompilationUnit cu = compiler.parse(fileName); - - StringWriter writer = new StringWriter(); - cu.accept(new PrettyCommentsPrinter(writer, comments.comments, cu)); - System.out.printf("####### Original source of %s #######\n", fileName); - BufferedReader reader = new BufferedReader(new FileReader(fileName)); - String line = null; - while ((line = reader.readLine()) != null) { - System.out.println(line); - } - reader.close(); - - System.out.printf("####### Generated source of %s #######\n", fileName); - System.out.println(writer); - - printNodes(fileName, cu); - System.out.printf("####### Comments of %s #######\n", fileName); - for (Comment comment : comments.comments) { - System.out.println(comment.summary()); - } - System.out.printf("####### End of %s #######\n\n", fileName); - } - - private void printNodes(String fileName, final JCCompilationUnit cu) { - System.out.printf("####### Nodes of %s #######\n", fileName); - cu.accept(new TreeScanner(){ - @Override - public Void scan(Tree node, Void p) { - if (node == null) { - return null; - } - node.accept(new SimpleTreeVisitor(){ - @SuppressWarnings("incomplete-switch") - @Override - protected Void defaultAction(Tree treeNode, Void r) { - if (treeNode == null) { - return null; - } - JCTree tree = (JCTree)treeNode; - Kind kind = tree.getKind(); - System.out.print(kind.toString() + " " + tree.pos + " - " + tree.getEndPosition(cu.endPositions)); - switch (kind) { - case IDENTIFIER: - case PRIMITIVE_TYPE: - case MODIFIERS: - System.out.print("[" + tree.toString() + "]"); - break; - } - System.out.println(); - return null; - } - }, null); - return super.scan(node, p); - } - }, null); - } - - public static class PrettyDocCommentScanner extends Scanner { - - private final Comments comments; - - /** A factory for creating scanners. */ - public static class Factory extends Scanner.Factory { - - private final Context context; - - public static void preRegister(final Context context) { - context.put(scannerFactoryKey, new Context.Factory() { - public Factory make() { - return new Factory(context); - } - }); - } - - /** Create a new scanner factory. */ - protected Factory(Context context) { - super(context); - this.context = context; - } - - @Override - public Scanner newScanner(CharSequence input) { - if (input instanceof CharBuffer) { - return new PrettyDocCommentScanner(this, (CharBuffer)input, context.get(Comments.class)); - } - char[] array = input.toString().toCharArray(); - return newScanner(array, array.length); - } - - @Override - public Scanner newScanner(char[] input, int inputLength) { - return new PrettyDocCommentScanner(this, input, inputLength, context.get(Comments.class)); - } - } - - - public PrettyDocCommentScanner(PrettyPrinter.PrettyDocCommentScanner.Factory factory, CharBuffer charBuffer, Comments comments) { - super(factory, charBuffer); - this.comments = comments; - } - - - public PrettyDocCommentScanner(PrettyPrinter.PrettyDocCommentScanner.Factory factory, char[] input, int inputLength, Comments comments) { - super(factory, input, inputLength); - this.comments = comments; - } - - @Override - protected void processComment(CommentStyle style) { - comments.add(pos(), new String(getRawCharacters(pos(), endPos()))); - } - } -} diff --git a/test/delombok/resource/after/WithComments.java b/test/delombok/resource/after/WithComments.java new file mode 100644 index 00000000..0f9ddb9f --- /dev/null +++ b/test/delombok/resource/after/WithComments.java @@ -0,0 +1,5 @@ +// Cool Comments + +public class WithComments { + // Also inside the body +} \ No newline at end of file diff --git a/test/delombok/resource/before/WithComments.java b/test/delombok/resource/before/WithComments.java new file mode 100644 index 00000000..22d044b3 --- /dev/null +++ b/test/delombok/resource/before/WithComments.java @@ -0,0 +1,4 @@ +// Cool Comments +public class WithComments { + // Also inside the body +} diff --git a/test/delombok/src/lombok/delombok/TestSourceFiles.java b/test/delombok/src/lombok/delombok/TestSourceFiles.java new file mode 100644 index 00000000..90c9b543 --- /dev/null +++ b/test/delombok/src/lombok/delombok/TestSourceFiles.java @@ -0,0 +1,97 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * 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 java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.StringWriter; + +import lombok.delombok.CommentPreservingParser.ParseResult; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +import com.sun.tools.javac.main.OptionName; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Options; + +public class TestSourceFiles { + + private static CommentPreservingParser parser; + + private static final File BEFORE_FOLDER = new File("test/delombok/resource/before"); + private static final File AFTER_FOLDER = new File("test/delombok/resource/after"); + + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + @BeforeClass + public static void init() { + Context c = new Context(); + Options.instance(c).put(OptionName.ENCODING, "utf-8"); + parser = new CommentPreservingParser(c); + } + + @Test + public void testSources() throws Exception { + File[] listFiles = BEFORE_FOLDER.listFiles(); + for (File file : listFiles) { + ParseResult parseResult = parser.parseFile(file.toString()); + StringWriter writer = new StringWriter(); + parseResult.print(writer); + compare(file.getName(), readAfter(file), writer.toString()); + } + } + + private void compare(String name, String expectedFile, String actualFile) { + String[] expectedLines = expectedFile.split("(\\r?\\n)"); + String[] actualLines = actualFile.split("(\\r?\\n)"); + int size = Math.min(expectedLines.length, actualLines.length); + for (int i = 0; i < size; i++) { + String expected = expectedLines[i]; + String actual = actualLines[i]; + if (!expected.equals(actual)) { + fail(String.format("Difference in line %s(%d):\n`%s`\n`%s`\n", name, i, expected, actual)); + } + } + if (expectedLines.length > actualLines.length) { + fail(String.format("Missing line %s(%d): %s\n", name, size, expectedLines[size])); + } + if (expectedLines.length < actualLines.length) { + fail(String.format("Extra line %s(%d): %s\n", name, size, actualLines[size])); + } + } + + private String readAfter(File file) throws IOException { + BufferedReader reader = new BufferedReader(new FileReader(new File(AFTER_FOLDER, file.getName()))); + StringBuilder result = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + result.append(line); + result.append(LINE_SEPARATOR); + } + reader.close(); + return result.toString(); + } +} -- cgit From f22021ca7808af2cd0ba03b7c34b8fd3758ff44b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 26 Nov 2009 17:12:41 +0100 Subject: Minor refactoring + added testcase for for-loop --- .../lombok/delombok/CommentPreservingParser.java | 30 ++++++++++++++++------ .../lombok/delombok/PrettyCommentsPrinter.java | 10 +++----- test/delombok/resource/after/ForLoop.java | 13 ++++++++++ test/delombok/resource/after/WithComments.java | 2 +- test/delombok/resource/before/ForLoop.java | 12 +++++++++ .../src/lombok/delombok/TestSourceFiles.java | 11 +++----- 6 files changed, 54 insertions(+), 24 deletions(-) create mode 100644 test/delombok/resource/after/ForLoop.java create mode 100644 test/delombok/resource/before/ForLoop.java (limited to 'src') diff --git a/src/delombok/lombok/delombok/CommentPreservingParser.java b/src/delombok/lombok/delombok/CommentPreservingParser.java index c85124b5..19219d93 100644 --- a/src/delombok/lombok/delombok/CommentPreservingParser.java +++ b/src/delombok/lombok/delombok/CommentPreservingParser.java @@ -25,29 +25,43 @@ import java.io.IOException; import java.io.Writer; 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.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Options; public class CommentPreservingParser { - private final JavaCompiler compiler; - private final Context context; - public CommentPreservingParser(Context context) { - this.context = context; + private final String encoding; + + public CommentPreservingParser() { + this("utf-8"); + } + + public CommentPreservingParser(String encoding) { + this.encoding = encoding; + } + + public ParseResult parseFile(String fileName) throws IOException { + Context context = new Context(); + + Options.instance(context).put(OptionName.ENCODING, encoding); + CommentCollectingScanner.Factory.preRegister(context); - compiler = new JavaCompiler(context) { + + JavaCompiler compiler = new JavaCompiler(context) { @Override protected boolean keepComments() { return true; } }; compiler.genEndPos = true; - } - - public ParseResult parseFile(String fileName) throws IOException { + Comments comments = new Comments(); context.put(Comments.class, comments); + + comments.comments = List.nil(); @SuppressWarnings("deprecation") JCCompilationUnit cu = compiler.parse(fileName); return new ParseResult(comments.comments, cu); diff --git a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java index c6b58a31..2fb62e53 100644 --- a/src/delombok/lombok/delombok/PrettyCommentsPrinter.java +++ b/src/delombok/lombok/delombok/PrettyCommentsPrinter.java @@ -184,10 +184,6 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { */ Writer out; - /** Indentation width (can be reassigned from outside). - */ - public int width = 4; - /** The current left margin. */ int lmargin = 0; @@ -205,19 +201,19 @@ public class PrettyCommentsPrinter extends JCTree.Visitor { */ void align() throws IOException { newLine = false; - for (int i = 0; i < lmargin; i++) out.write(" "); + for (int i = 0; i < lmargin; i++) out.write("\t"); } /** Increase left margin by indentation width. */ void indent() { - lmargin = lmargin + width; + lmargin++; } /** Decrease left margin by indentation width. */ void undent() { - lmargin = lmargin - width; + lmargin--; } /** Enter a new precedence level. Emit a `(' if new precedence level diff --git a/test/delombok/resource/after/ForLoop.java b/test/delombok/resource/after/ForLoop.java new file mode 100644 index 00000000..609549b7 --- /dev/null +++ b/test/delombok/resource/after/ForLoop.java @@ -0,0 +1,13 @@ + +public class ForLoop { + + public static void main(String[] args) { + // before loop + for (int i = 0; i < 10; i++) { + // start of block + System.out.println(i); + // end of block + } + // after loop + } +} diff --git a/test/delombok/resource/after/WithComments.java b/test/delombok/resource/after/WithComments.java index 0f9ddb9f..59cc97c4 100644 --- a/test/delombok/resource/after/WithComments.java +++ b/test/delombok/resource/after/WithComments.java @@ -1,5 +1,5 @@ // Cool Comments public class WithComments { - // Also inside the body + // Also inside the body } \ No newline at end of file diff --git a/test/delombok/resource/before/ForLoop.java b/test/delombok/resource/before/ForLoop.java new file mode 100644 index 00000000..2bed7f9b --- /dev/null +++ b/test/delombok/resource/before/ForLoop.java @@ -0,0 +1,12 @@ +public class ForLoop { + + public static void main(String[] args) { + // before loop + for (int i = 0; i < 10; i++) { + // start of block + System.out.println(i); + // end of block + } + // after loop + } +} diff --git a/test/delombok/src/lombok/delombok/TestSourceFiles.java b/test/delombok/src/lombok/delombok/TestSourceFiles.java index 90c9b543..374eeb8b 100644 --- a/test/delombok/src/lombok/delombok/TestSourceFiles.java +++ b/test/delombok/src/lombok/delombok/TestSourceFiles.java @@ -21,6 +21,8 @@ */ package lombok.delombok; +import static org.junit.Assert.fail; + import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -31,11 +33,6 @@ import lombok.delombok.CommentPreservingParser.ParseResult; import org.junit.BeforeClass; import org.junit.Test; -import static org.junit.Assert.*; - -import com.sun.tools.javac.main.OptionName; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Options; public class TestSourceFiles { @@ -48,9 +45,7 @@ public class TestSourceFiles { @BeforeClass public static void init() { - Context c = new Context(); - Options.instance(c).put(OptionName.ENCODING, "utf-8"); - parser = new CommentPreservingParser(c); + parser = new CommentPreservingParser(); } @Test -- cgit From e5d248c3ccf64211fd8a301f584bde82dd426601 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Fri, 27 Nov 2009 00:38:58 +0100 Subject: delombok now calls lombok. wahey! --- src/core/lombok/javac/JavacAST.java | 5 +- src/core/lombok/javac/JavacTransformer.java | 98 ++++++++++++++++++++++ src/core/lombok/javac/apt/Processor.java | 67 +-------------- .../lombok/delombok/CommentPreservingParser.java | 32 ++++++- .../src/lombok/delombok/TestLombokFiles.java | 95 +++++++++++++++++++++ .../src/lombok/delombok/TestSourceFiles.java | 21 +++-- .../resource/after/CommentsInterspersed.java | 26 ++++++ .../resource/before/CommentsInterspersed.java | 14 ++++ 8 files changed, 285 insertions(+), 73 deletions(-) create mode 100644 src/core/lombok/javac/JavacTransformer.java create mode 100644 test/delombok/src/lombok/delombok/TestLombokFiles.java create mode 100644 test/lombok/resource/after/CommentsInterspersed.java create mode 100644 test/lombok/resource/before/CommentsInterspersed.java (limited to 'src') diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index f2c83fb8..77c63cfe 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -32,7 +32,6 @@ import javax.tools.JavaFileObject; import lombok.core.AST; -import com.sun.source.util.Trees; import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeMaker; @@ -66,13 +65,11 @@ public class JavacAST extends AST { /** * Creates a new JavacAST of the provided Compilation Unit. * - * @param trees The trees instance to use to inspect the compilation unit. Generate via: - * {@code Trees.getInstance(env)} * @param messager A Messager for warning and error reporting. * @param context A Context object for interfacing with the compiler. * @param top The compilation unit, which serves as the top level node in the tree to be built. */ - public JavacAST(Trees trees, Messager messager, Context context, JCCompilationUnit top) { + public JavacAST(Messager messager, Context context, JCCompilationUnit top) { super(top.sourcefile == null ? null : top.sourcefile.toString()); setTop(buildCompilationUnit(top)); this.context = context; diff --git a/src/core/lombok/javac/JavacTransformer.java b/src/core/lombok/javac/JavacTransformer.java new file mode 100644 index 00000000..d004414d --- /dev/null +++ b/src/core/lombok/javac/JavacTransformer.java @@ -0,0 +1,98 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * 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.javac; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.processing.Messager; + +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.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.util.Context; + +public class JavacTransformer { + private final HandlerLibrary handlers; + private final Messager messager; + + public JavacTransformer(Messager messager) { + this.messager = messager; + this.handlers = HandlerLibrary.load(messager); + } + + public void transform(Context context, Iterable compilationUnits) { + List asts = new ArrayList(); + + for (JCCompilationUnit unit : compilationUnits) asts.add(new JavacAST(messager, context, unit)); + + handlers.skipPrintAST(); + for (JavacAST ast : asts) { + ast.traverse(new AnnotationVisitor()); + handlers.callASTVisitors(ast); + } + + handlers.skipAllButPrintAST(); + for (JavacAST ast : asts) { + ast.traverse(new AnnotationVisitor()); + } + } + + private class AnnotationVisitor extends JavacASTAdapter { + @Override public void visitAnnotationOnType(JCClassDecl type, JavacNode annotationNode, JCAnnotation annotation) { + if (annotationNode.isHandled()) return; + JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); + boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); + if (handled) annotationNode.setHandled(); + } + + @Override public void visitAnnotationOnField(JCVariableDecl field, JavacNode annotationNode, JCAnnotation annotation) { + if (annotationNode.isHandled()) return; + JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); + boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); + if (handled) annotationNode.setHandled(); + } + + @Override public void visitAnnotationOnMethod(JCMethodDecl method, JavacNode annotationNode, JCAnnotation annotation) { + if (annotationNode.isHandled()) return; + JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); + boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); + if (handled) annotationNode.setHandled(); + } + + @Override public void visitAnnotationOnMethodArgument(JCVariableDecl argument, JCMethodDecl method, JavacNode annotationNode, JCAnnotation annotation) { + if (annotationNode.isHandled()) return; + JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); + boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); + if (handled) annotationNode.setHandled(); + } + + @Override public void visitAnnotationOnLocal(JCVariableDecl local, JavacNode annotationNode, JCAnnotation annotation) { + if (annotationNode.isHandled()) return; + JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); + boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); + if (handled) annotationNode.setHandled(); + } + } +} diff --git a/src/core/lombok/javac/apt/Processor.java b/src/core/lombok/javac/apt/Processor.java index 9c851762..b779a680 100644 --- a/src/core/lombok/javac/apt/Processor.java +++ b/src/core/lombok/javac/apt/Processor.java @@ -21,9 +21,7 @@ */ package lombok.javac.apt; -import java.util.ArrayList; import java.util.IdentityHashMap; -import java.util.List; import java.util.Set; import javax.annotation.processing.AbstractProcessor; @@ -36,19 +34,12 @@ import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic.Kind; -import lombok.javac.HandlerLibrary; -import lombok.javac.JavacAST; -import lombok.javac.JavacASTAdapter; -import lombok.javac.JavacNode; +import lombok.javac.JavacTransformer; import com.sun.source.util.TreePath; import com.sun.source.util.Trees; import com.sun.tools.javac.processing.JavacProcessingEnvironment; -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.JCMethodDecl; -import com.sun.tools.javac.tree.JCTree.JCVariableDecl; /** @@ -66,7 +57,7 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; public class Processor extends AbstractProcessor { private ProcessingEnvironment rawProcessingEnv; private JavacProcessingEnvironment processingEnv; - private HandlerLibrary handlers; + private JavacTransformer transformer; private Trees trees; private String errorToShow; @@ -86,7 +77,7 @@ public class Processor extends AbstractProcessor { this.errorToShow = null; } else { this.processingEnv = (JavacProcessingEnvironment) procEnv; - handlers = HandlerLibrary.load(procEnv.getMessager()); + transformer = new JavacTransformer(procEnv.getMessager()); trees = Trees.instance(procEnv); this.errorToShow = null; } @@ -111,61 +102,11 @@ public class Processor extends AbstractProcessor { if (unit != null) units.put(unit, null); } - List asts = new ArrayList(); + transformer.transform(processingEnv.getContext(), units.keySet()); - for (JCCompilationUnit unit : units.keySet()) asts.add( - new JavacAST(trees, processingEnv.getMessager(), processingEnv.getContext(), unit)); - - handlers.skipPrintAST(); - for (JavacAST ast : asts) { - ast.traverse(new AnnotationVisitor()); - handlers.callASTVisitors(ast); - } - - handlers.skipAllButPrintAST(); - for (JavacAST ast : asts) { - ast.traverse(new AnnotationVisitor()); - } return false; } - private class AnnotationVisitor extends JavacASTAdapter { - @Override public void visitAnnotationOnType(JCClassDecl type, JavacNode annotationNode, JCAnnotation annotation) { - if (annotationNode.isHandled()) return; - JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); - boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); - } - - @Override public void visitAnnotationOnField(JCVariableDecl field, JavacNode annotationNode, JCAnnotation annotation) { - if (annotationNode.isHandled()) return; - JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); - boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); - } - - @Override public void visitAnnotationOnMethod(JCMethodDecl method, JavacNode annotationNode, JCAnnotation annotation) { - if (annotationNode.isHandled()) return; - JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); - boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); - } - - @Override public void visitAnnotationOnMethodArgument(JCVariableDecl argument, JCMethodDecl method, JavacNode annotationNode, JCAnnotation annotation) { - if (annotationNode.isHandled()) return; - JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); - boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); - } - - @Override public void visitAnnotationOnLocal(JCVariableDecl local, JavacNode annotationNode, JCAnnotation annotation) { - if (annotationNode.isHandled()) return; - JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); - boolean handled = handlers.handleAnnotation(top, annotationNode, annotation); - if (handled) annotationNode.setHandled(); - } - } - private JCCompilationUnit toUnit(Element element) { TreePath path = trees == null ? null : trees.getPath(element); if (path == null) return null; diff --git a/src/delombok/lombok/delombok/CommentPreservingParser.java b/src/delombok/lombok/delombok/CommentPreservingParser.java index 19219d93..51df5ed1 100644 --- a/src/delombok/lombok/delombok/CommentPreservingParser.java +++ b/src/delombok/lombok/delombok/CommentPreservingParser.java @@ -23,6 +23,15 @@ package lombok.delombok; import java.io.IOException; import java.io.Writer; +import java.util.Collections; + +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.Diagnostic.Kind; + +import lombok.javac.JavacTransformer; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.main.OptionName; @@ -64,9 +73,30 @@ public class CommentPreservingParser { comments.comments = List.nil(); @SuppressWarnings("deprecation") JCCompilationUnit cu = compiler.parse(fileName); + + new JavacTransformer(messager).transform(context, Collections.singleton(cu)); + return new ParseResult(comments.comments, cu); } - + + private static final Messager messager = new Messager() { + @Override public void printMessage(Kind kind, CharSequence msg) { + System.out.printf("M: %s: %s\n", kind, msg); + } + + @Override public void printMessage(Kind kind, CharSequence msg, Element e) { + System.out.printf("E: %s: %s\n", kind, msg); + } + + @Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a) { + System.out.printf("A: %s: %s\n", kind, msg); + } + + @Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v) { + System.out.printf("V: %s: %s\n", kind, msg); + } + }; + static class Comments { List comments = List.nil(); diff --git a/test/delombok/src/lombok/delombok/TestLombokFiles.java b/test/delombok/src/lombok/delombok/TestLombokFiles.java new file mode 100644 index 00000000..10782830 --- /dev/null +++ b/test/delombok/src/lombok/delombok/TestLombokFiles.java @@ -0,0 +1,95 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * 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 static org.junit.Assert.fail; +import static lombok.delombok.TestSourceFiles.removeBlanks; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.StringWriter; + +import lombok.delombok.CommentPreservingParser.ParseResult; + +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestLombokFiles { + private static CommentPreservingParser parser; + + private static final File BEFORE_FOLDER = new File("test/lombok/resource/before"); + private static final File AFTER_FOLDER = new File("test/lombok/resource/after"); + + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + @BeforeClass + public static void init() { + parser = new CommentPreservingParser(); + } + + @Test + public void testSources() throws Exception { + File[] listFiles = BEFORE_FOLDER.listFiles(); + for (File file : listFiles) { + ParseResult parseResult = parser.parseFile(file.toString()); + StringWriter writer = new StringWriter(); + parseResult.print(writer); + System.out.println(writer); + compare(file.getName(), readAfter(file), writer.toString()); + } + } + + private void compare(String name, String expectedFile, String actualFile) { + String[] expectedLines = expectedFile.split("(\\r?\\n)"); + String[] actualLines = actualFile.split("(\\r?\\n)"); + expectedLines = removeBlanks(expectedLines); + actualLines = removeBlanks(actualLines); + int size = Math.min(expectedLines.length, actualLines.length); + for (int i = 0; i < size; i++) { + String expected = expectedLines[i]; + String actual = actualLines[i]; + if (!expected.equals(actual)) { + fail(String.format("Difference in line %s(%d):\n`%s`\n`%s`\n", name, i, expected, actual)); + } + } + if (expectedLines.length > actualLines.length) { + fail(String.format("Missing line %s(%d): %s\n", name, size, expectedLines[size])); + } + if (expectedLines.length < actualLines.length) { + fail(String.format("Extra line %s(%d): %s\n", name, size, actualLines[size])); + } + } + + private String readAfter(File file) throws IOException { + BufferedReader reader = new BufferedReader(new FileReader(new File(AFTER_FOLDER, file.getName()))); + StringBuilder result = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + result.append(line); + result.append(LINE_SEPARATOR); + } + reader.close(); + return result.toString(); + } +} diff --git a/test/delombok/src/lombok/delombok/TestSourceFiles.java b/test/delombok/src/lombok/delombok/TestSourceFiles.java index 374eeb8b..b662651d 100644 --- a/test/delombok/src/lombok/delombok/TestSourceFiles.java +++ b/test/delombok/src/lombok/delombok/TestSourceFiles.java @@ -28,6 +28,8 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; import lombok.delombok.CommentPreservingParser.ParseResult; @@ -35,14 +37,13 @@ import org.junit.BeforeClass; import org.junit.Test; public class TestSourceFiles { - private static CommentPreservingParser parser; private static final File BEFORE_FOLDER = new File("test/delombok/resource/before"); private static final File AFTER_FOLDER = new File("test/delombok/resource/after"); - - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); - + + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + @BeforeClass public static void init() { parser = new CommentPreservingParser(); @@ -59,9 +60,19 @@ public class TestSourceFiles { } } + static String[] removeBlanks(String[] in) { + List out = new ArrayList(); + for (String s : in) { + if (!s.trim().isEmpty()) out.add(s); + } + return out.toArray(new String[0]); + } + private void compare(String name, String expectedFile, String actualFile) { String[] expectedLines = expectedFile.split("(\\r?\\n)"); String[] actualLines = actualFile.split("(\\r?\\n)"); + expectedLines = removeBlanks(expectedLines); + actualLines = removeBlanks(actualLines); int size = Math.min(expectedLines.length, actualLines.length); for (int i = 0; i < size; i++) { String expected = expectedLines[i]; @@ -77,7 +88,7 @@ public class TestSourceFiles { fail(String.format("Extra line %s(%d): %s\n", name, size, actualLines[size])); } } - + private String readAfter(File file) throws IOException { BufferedReader reader = new BufferedReader(new FileReader(new File(AFTER_FOLDER, file.getName()))); StringBuilder result = new StringBuilder(); diff --git a/test/lombok/resource/after/CommentsInterspersed.java b/test/lombok/resource/after/CommentsInterspersed.java new file mode 100644 index 00000000..ec5374c0 --- /dev/null +++ b/test/lombok/resource/after/CommentsInterspersed.java @@ -0,0 +1,26 @@ +import lombok.Getter; + +/*bla */ +public class CommentsInterspersed { + /** javadoc for field */ + private int x; + + /* bla2 */ + @Getter() + private String test = "foo"; + //$NON-NLS-1$ + + /** Javadoc on method */ + public native void gwtTest(); + /*-{ + javascript; + }-*/ + + public CommentsInterspersed() { + } + + public String getTest() { + return this.test; + } +} +//haha! diff --git a/test/lombok/resource/before/CommentsInterspersed.java b/test/lombok/resource/before/CommentsInterspersed.java new file mode 100644 index 00000000..2a32d309 --- /dev/null +++ b/test/lombok/resource/before/CommentsInterspersed.java @@ -0,0 +1,14 @@ +import lombok.Getter; + +public /*bla */ class CommentsInterspersed { + /** javadoc for field */ + private int x; + + private /* bla2 */ @Getter String test = "foo"; //$NON-NLS-1$ + + /** Javadoc on method */ + public native void gwtTest(); /*-{ + javascript; + }-*/ +} //haha! + -- cgit From 86ac271a45e1152272f44fcd81f0c90914853013 Mon Sep 17 00:00:00 2001 From: Roel Spilker Date: Fri, 27 Nov 2009 02:38:55 +0100 Subject: We encountered a strange NPE here. Can't reproduce, nevertheless added null-checks --- src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java b/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java index 5d54692e..1430ca8c 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java @@ -26,6 +26,7 @@ public class PatchFixes { public static void setIsGeneratedFlag(org.eclipse.jdt.core.dom.ASTNode domNode, org.eclipse.jdt.internal.compiler.ast.ASTNode internalNode) throws Exception { + if (internalNode == null || domNode == null) return; boolean isGenerated = internalNode.getClass().getField("$generatedBy").get(internalNode) != null; if (isGenerated) { domNode.getClass().getField("$isGenerated").set(domNode, true); -- cgit From e54c3f36e3122dfe34a119178cfcca2dcdbad998 Mon Sep 17 00:00:00 2001 From: Roel Spilker Date: Fri, 27 Nov 2009 03:10:03 +0100 Subject: Added change tracking so that 1 AST instance can tell you if any processor changed anything. --- src/core/lombok/core/AST.java | 13 +++++++++++++ src/core/lombok/core/LombokNode.java | 6 ++++++ src/core/lombok/eclipse/EclipseAST.java | 3 +++ src/core/lombok/javac/JavacAST.java | 1 + 4 files changed, 23 insertions(+) (limited to 'src') diff --git a/src/core/lombok/core/AST.java b/src/core/lombok/core/AST.java index 6d786d1e..e769ce34 100644 --- a/src/core/lombok/core/AST.java +++ b/src/core/lombok/core/AST.java @@ -54,11 +54,24 @@ public abstract class AST, L extends LombokNode, private final String fileName; Map identityDetector = new IdentityHashMap(); private Map nodeMap = new IdentityHashMap(); + private boolean changed = false; protected AST(String fileName) { this.fileName = fileName == null ? "(unknown).java" : fileName; } + protected void setChanged() { + this.changed = true; + } + + protected void clearChanged() { + this.changed = false; + } + + public boolean isChanged() { + return changed; + } + /** Set the node object that wraps the internal Compilation Unit node. */ protected void setTop(L top) { this.top = top; diff --git a/src/core/lombok/core/LombokNode.java b/src/core/lombok/core/LombokNode.java index c8ee4c00..95c5a0cb 100644 --- a/src/core/lombok/core/LombokNode.java +++ b/src/core/lombok/core/LombokNode.java @@ -126,6 +126,7 @@ public abstract class LombokNode, L extends LombokNode, L extends LombokNode, L extends LombokNode, L extends LombokNode, L extends LombokNode { this.compilationUnitDeclaration = ast; setTop(buildCompilationUnit(ast)); this.completeParse = isComplete(ast); + clearChanged(); } /** {@inheritDoc} */ @@ -201,12 +202,14 @@ public class EclipseAST extends AST { public void reparse() { propagateProblems(); if (completeParse) return; + boolean changed = isChanged(); boolean newCompleteParse = isComplete(compilationUnitDeclaration); if (!newCompleteParse) return; top().rebuild(); this.completeParse = true; + if (!changed) clearChanged(); } private static boolean isComplete(CompilationUnitDeclaration unit) { diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index 77c63cfe..93e3f3dc 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -78,6 +78,7 @@ public class JavacAST extends AST { this.nameTable = Name.Table.instance(context); this.treeMaker = TreeMaker.instance(context); this.symtab = Symtab.instance(context); + clearChanged(); } public Context getContext() { -- cgit From 391db3dcecdd0d94eb76b656e655346891b02bb4 Mon Sep 17 00:00:00 2001 From: Roel Spilker Date: Fri, 27 Nov 2009 04:18:28 +0100 Subject: 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. --- .classpath | 2 +- src/core/lombok/javac/JavacTransformer.java | 7 ++- src/core/lombok/javac/handlers/HandleCleanup.java | 2 + src/core/lombok/javac/handlers/HandleData.java | 1 + .../javac/handlers/HandleEqualsAndHashCode.java | 1 + src/core/lombok/javac/handlers/HandleGetter.java | 2 + src/core/lombok/javac/handlers/HandleSetter.java | 2 + .../lombok/javac/handlers/HandleSneakyThrows.java | 2 + .../lombok/javac/handlers/HandleSynchronized.java | 3 ++ src/core/lombok/javac/handlers/HandleToString.java | 2 + .../lombok/javac/handlers/JavacHandlerUtil.java | 51 ++++++++++++++++++++++ src/delombok/lombok/delombok/Comment.java | 12 ++++- .../lombok/delombok/CommentCollectingScanner.java | 16 ++++++- .../lombok/delombok/CommentPreservingParser.java | 29 ++++++++---- .../lombok/delombok/PrettyCommentsPrinter.java | 37 +++++++++++++--- .../src/lombok/delombok/TestLombokFiles.java | 6 ++- .../src/lombok/delombok/TestSourceFiles.java | 7 ++- .../resource/after/CommentsInterspersed.java | 20 +++------ .../resource/before/CommentsInterspersed.java | 2 +- 19 files changed, 169 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/.classpath b/.classpath index 3390740d..0d702795 100644 --- a/.classpath +++ b/.classpath @@ -14,7 +14,7 @@ - + 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 compilationUnits) { + public boolean transform(Context context, Iterable compilationUnits) { List asts = new ArrayList(); 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 { @Override public boolean handle(AnnotationValues 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 { @Override public boolean handle(AnnotationValues 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 annotation, JCAnnotation ast, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, EqualsAndHashCode.class); EqualsAndHashCode ann = annotation.getInstance(); List excludes = List.from(ann.exclude()); List 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 { } @Override public boolean handle(AnnotationValues 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 { } @Override public boolean handle(AnnotationValues 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 { @Override public boolean handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, SneakyThrows.class); Collection exceptionNames = annotation.getRawExpressions("value"); List 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 private static final String STATIC_LOCK_NAME = "$LOCK"; @Override public boolean handle(AnnotationValues 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 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 { } @Override public boolean handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { + markAnnotationAsProcessed(annotationNode, ToString.class); + ToString ann = annotation.getInstance(); List excludes = List.from(ann.exclude()); List 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; @@ -57,6 +60,54 @@ public class JavacHandlerUtil { return TransformationsUtil.PRIMITIVE_TYPE_NAME_PATTERN.matcher(typeName).matches(); } + /** + * 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 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 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 filterList(List annotations, JCTree jcTree) { + List 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 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 comments; private final JCCompilationUnit compilationUnit; + private final boolean changed; - private ParseResult(List comments, JCCompilationUnit compilationUnit) { + private ParseResult(List 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 */ diff --git a/test/delombok/src/lombok/delombok/TestLombokFiles.java b/test/delombok/src/lombok/delombok/TestLombokFiles.java index 10782830..f04a0a34 100644 --- a/test/delombok/src/lombok/delombok/TestLombokFiles.java +++ b/test/delombok/src/lombok/delombok/TestLombokFiles.java @@ -52,10 +52,9 @@ public class TestLombokFiles { public void testSources() throws Exception { File[] listFiles = BEFORE_FOLDER.listFiles(); for (File file : listFiles) { - ParseResult parseResult = parser.parseFile(file.toString()); + ParseResult parseResult = parser.parse(file.toString(), true); StringWriter writer = new StringWriter(); parseResult.print(writer); - System.out.println(writer); compare(file.getName(), readAfter(file), writer.toString()); } } @@ -63,6 +62,9 @@ public class TestLombokFiles { private void compare(String name, String expectedFile, String actualFile) { String[] expectedLines = expectedFile.split("(\\r?\\n)"); String[] actualLines = actualFile.split("(\\r?\\n)"); + if (actualLines[0].startsWith("// Generated by delombok at ")) { + actualLines[0] = ""; + } expectedLines = removeBlanks(expectedLines); actualLines = removeBlanks(actualLines); int size = Math.min(expectedLines.length, actualLines.length); diff --git a/test/delombok/src/lombok/delombok/TestSourceFiles.java b/test/delombok/src/lombok/delombok/TestSourceFiles.java index b662651d..91ace773 100644 --- a/test/delombok/src/lombok/delombok/TestSourceFiles.java +++ b/test/delombok/src/lombok/delombok/TestSourceFiles.java @@ -53,7 +53,7 @@ public class TestSourceFiles { public void testSources() throws Exception { File[] listFiles = BEFORE_FOLDER.listFiles(); for (File file : listFiles) { - ParseResult parseResult = parser.parseFile(file.toString()); + ParseResult parseResult = parser.parse(file.toString(), true); StringWriter writer = new StringWriter(); parseResult.print(writer); compare(file.getName(), readAfter(file), writer.toString()); @@ -71,6 +71,9 @@ public class TestSourceFiles { private void compare(String name, String expectedFile, String actualFile) { String[] expectedLines = expectedFile.split("(\\r?\\n)"); String[] actualLines = actualFile.split("(\\r?\\n)"); + if (actualLines[0].startsWith("// Generated by delombok at ")) { + actualLines[0] = ""; + } expectedLines = removeBlanks(expectedLines); actualLines = removeBlanks(actualLines); int size = Math.min(expectedLines.length, actualLines.length); @@ -78,7 +81,7 @@ public class TestSourceFiles { String expected = expectedLines[i]; String actual = actualLines[i]; if (!expected.equals(actual)) { - fail(String.format("Difference in line %s(%d):\n`%s`\n`%s`\n", name, i, expected, actual)); + fail(String.format("Difference in line %s(%d):\nExpected `%s`\nGot `%s`\n", name, i, expected, actual)); } } if (expectedLines.length > actualLines.length) { diff --git a/test/lombok/resource/after/CommentsInterspersed.java b/test/lombok/resource/after/CommentsInterspersed.java index ec5374c0..f3841606 100644 --- a/test/lombok/resource/after/CommentsInterspersed.java +++ b/test/lombok/resource/after/CommentsInterspersed.java @@ -1,26 +1,20 @@ -import lombok.Getter; - +/* cmt */ +/* cmt2 */ +/* cmt3 */ /*bla */ public class CommentsInterspersed { /** javadoc for field */ private int x; /* bla2 */ - @Getter() - private String test = "foo"; - //$NON-NLS-1$ + private String test = "foo"; //$NON-NLS-1$ /** Javadoc on method */ - public native void gwtTest(); - /*-{ + public native void gwtTest(); /*-{ javascript; }-*/ - public CommentsInterspersed() { - } - public String getTest() { - return this.test; + return test; } -} -//haha! +} //haha! diff --git a/test/lombok/resource/before/CommentsInterspersed.java b/test/lombok/resource/before/CommentsInterspersed.java index 2a32d309..455c680d 100644 --- a/test/lombok/resource/before/CommentsInterspersed.java +++ b/test/lombok/resource/before/CommentsInterspersed.java @@ -1,4 +1,4 @@ -import lombok.Getter; +import /* cmt */ lombok./* cmt2 */Getter /* cmt3 */ ; public /*bla */ class CommentsInterspersed { /** javadoc for field */ -- cgit From 4316e77e1eb6654eec18d04780a6da78c22fb644 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Fri, 27 Nov 2009 07:18:48 +0100 Subject: Added a class that is easier to use than the parser itself for delombok, as well as code to process entire directories at a time. Also removed duplication from the testcases. --- .classpath | 1 + src/delombok/lombok/delombok/Delombok.java | 155 +++++++++++++++++++++ test/core/src/lombok/TestViaDelombok.java | 97 +++++++++++++ .../src/lombok/delombok/TestLombokFiles.java | 67 +-------- .../src/lombok/delombok/TestSourceFiles.java | 76 +--------- 5 files changed, 261 insertions(+), 135 deletions(-) create mode 100644 src/delombok/lombok/delombok/Delombok.java create mode 100644 test/core/src/lombok/TestViaDelombok.java (limited to 'src') diff --git a/.classpath b/.classpath index 0d702795..a33a68d9 100644 --- a/.classpath +++ b/.classpath @@ -6,6 +6,7 @@ + diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java new file mode 100644 index 00000000..c6f9ecf9 --- /dev/null +++ b/src/delombok/lombok/delombok/Delombok.java @@ -0,0 +1,155 @@ +package lombok.delombok; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintStream; +import java.io.Writer; +import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; + +import lombok.delombok.CommentPreservingParser.ParseResult; + +public class Delombok { + private Charset charset = Charset.defaultCharset(); + private CommentPreservingParser parser = new CommentPreservingParser(); + private PrintStream feedback = System.err; + private boolean verbose; + private boolean force = false; + + /** If null, output to standard out. */ + private File output = null; + + public void setCharset(String charsetName) throws UnsupportedCharsetException { + charset = Charset.forName(charsetName); + } + + public void setForceProcess(boolean force) { + this.force = force; + } + + public void setFeedback(PrintStream feedback) { + this.feedback = feedback; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + public void setOutput(File dir) { + if (dir.isFile()) throw new IllegalArgumentException( + "DELOMBOK: delombok will only write to a directory. " + + "If you want to delombok a single file, use -p to output to standard output, then redirect this to a file:\n" + + "delombok MyJavaFile.java -p >MyJavaFileDelombok.java"); + output = dir; + } + + public void setOutputToStandardOut() { + this.output = null; + } + + public void delombok(File base) throws IOException { + delombok0(base, "", 0); + } + + private void delombok0(File base, String suffix, int loop) throws IOException { + File dir = suffix.isEmpty() ? base : new File(base, suffix); + String name = suffix + File.separator + dir.getName(); + + if (dir.isDirectory()) { + if (loop >= 100) { + feedback.printf("Over 100 subdirectories? I'm guessing there's a loop in your directory structure. Skipping: %s\n", suffix); + } else { + dir.mkdir(); + delombok0(base, name, loop + 1); + } + } else if (dir.isFile()) { + String extension = getExtension(dir); + if (extension.equals(".java")) delombok(base, name); + else if (extension.equals(".class")) skipClass(name); + else copy(base, name); + } else { + feedback.printf("Skipping %s because it is a special file type.\n", canonical(dir)); + } + } + + private void skipClass(String fileName) { + if (verbose) feedback.printf("Skipping class file: %s\n", fileName); + } + + private void copy(File base, String fileName) throws IOException { + if (output == null) { + feedback.printf("Skipping resource file: %s\n", fileName); + return; + } + if (verbose) feedback.printf("Copying resource file: %s\n", fileName); + byte[] b = new byte[65536]; + FileInputStream in = new FileInputStream(new File(base, fileName)); + try { + FileOutputStream out = new FileOutputStream(new File(output, fileName)); + try { + while (true) { + int r = in.read(b); + if (r == -1) break; + out.write(b, 0, r); + } + } finally { + out.close(); + } + } finally { + in.close(); + } + } + + public void delombok(String file, Writer writer) throws IOException { + ParseResult result = parser.parse(file, force); + + result.print(writer); + } + + public void delombok(File base, String fileName) throws IOException { + if (output != null && canonical(base).equals(canonical(output))) throw new IOException( + "DELOMBOK: Output file and input file refer to the same filesystem location. Specify a separate path for output."); + + ParseResult result = parser.parse(new File(base, fileName).getAbsolutePath(), force); + + if (verbose) feedback.printf("File: %s [%s]\n", fileName, result.isChanged() ? "delombok-ed" : "unchanged"); + + Writer rawWriter = output == null ? createStandardOutWriter() : createFileWriter(output, fileName); + BufferedWriter writer = new BufferedWriter(rawWriter); + + try { + result.print(writer); + } finally { + writer.close(); + } + } + + private static String canonical(File dir) { + try { + return dir.getCanonicalPath(); + } catch (Exception e) { + return dir.getAbsolutePath(); + } + } + + private static String getExtension(File dir) { + String name = dir.getName(); + int idx = name.lastIndexOf('.'); + return idx == -1 ? "" : name.substring(idx+1); + } + + private Writer createFileWriter(File base, String fileName) throws IOException { + File outFile = new File(base, fileName); + outFile.getParentFile().mkdirs(); + FileOutputStream out = new FileOutputStream(outFile); + return new OutputStreamWriter(out, charset); + } + + private Writer createStandardOutWriter() { + return new OutputStreamWriter(System.out, charset); + } +} diff --git a/test/core/src/lombok/TestViaDelombok.java b/test/core/src/lombok/TestViaDelombok.java new file mode 100644 index 00000000..e8070723 --- /dev/null +++ b/test/core/src/lombok/TestViaDelombok.java @@ -0,0 +1,97 @@ +/* + * Copyright © 2009 Reinier Zwitserloot and Roel Spilker. + * + * 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; + +import static org.junit.Assert.fail; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +import lombok.delombok.Delombok; + +public class TestViaDelombok { + private static Delombok delombok = new Delombok(); + + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + public static void runComparison(File beforeDir, File afterDir) throws IOException { + File[] listFiles = beforeDir.listFiles(); + + for (File file : listFiles) { + delombok.setVerbose(false); + delombok.setForceProcess(true); + delombok.setCharset("UTF-8"); + StringWriter writer = new StringWriter(); + delombok.delombok(file.getAbsolutePath(), writer); + compare(file.getName(), readAfter(afterDir, file), writer.toString()); + } + } + + private static void compare(String name, String expectedFile, String actualFile) { + String[] expectedLines = expectedFile.split("(\\r?\\n)"); + String[] actualLines = actualFile.split("(\\r?\\n)"); + if (actualLines[0].startsWith("// Generated by delombok at ")) { + actualLines[0] = ""; + } + expectedLines = removeBlanks(expectedLines); + actualLines = removeBlanks(actualLines); + int size = Math.min(expectedLines.length, actualLines.length); + for (int i = 0; i < size; i++) { + String expected = expectedLines[i]; + String actual = actualLines[i]; + if (!expected.equals(actual)) { + fail(String.format("Difference in line %s(%d):\n`%s`\n`%s`\n", name, i, expected, actual)); + } + } + if (expectedLines.length > actualLines.length) { + fail(String.format("Missing line %s(%d): %s\n", name, size, expectedLines[size])); + } + if (expectedLines.length < actualLines.length) { + fail(String.format("Extra line %s(%d): %s\n", name, size, actualLines[size])); + } + } + + private static String readAfter(File afterDir, File file) throws IOException { + BufferedReader reader = new BufferedReader(new FileReader(new File(afterDir, file.getName()))); + StringBuilder result = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + result.append(line); + result.append(LINE_SEPARATOR); + } + reader.close(); + return result.toString(); + } + + private static String[] removeBlanks(String[] in) { + List out = new ArrayList(); + for (String s : in) { + if (!s.trim().isEmpty()) out.add(s); + } + return out.toArray(new String[0]); + } +} diff --git a/test/delombok/src/lombok/delombok/TestLombokFiles.java b/test/delombok/src/lombok/delombok/TestLombokFiles.java index f04a0a34..1d93a4b2 100644 --- a/test/delombok/src/lombok/delombok/TestLombokFiles.java +++ b/test/delombok/src/lombok/delombok/TestLombokFiles.java @@ -21,77 +21,18 @@ */ package lombok.delombok; -import static org.junit.Assert.fail; -import static lombok.delombok.TestSourceFiles.removeBlanks; - -import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.StringWriter; -import lombok.delombok.CommentPreservingParser.ParseResult; +import lombok.TestViaDelombok; -import org.junit.BeforeClass; import org.junit.Test; public class TestLombokFiles { - private static CommentPreservingParser parser; - - private static final File BEFORE_FOLDER = new File("test/lombok/resource/before"); - private static final File AFTER_FOLDER = new File("test/lombok/resource/after"); - - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); - - @BeforeClass - public static void init() { - parser = new CommentPreservingParser(); - } + private static final File BEFORE_DIR = new File("test/lombok/resource/before"); + private static final File AFTER_DIR = new File("test/lombok/resource/after"); @Test public void testSources() throws Exception { - File[] listFiles = BEFORE_FOLDER.listFiles(); - for (File file : listFiles) { - ParseResult parseResult = parser.parse(file.toString(), true); - StringWriter writer = new StringWriter(); - parseResult.print(writer); - compare(file.getName(), readAfter(file), writer.toString()); - } - } - - private void compare(String name, String expectedFile, String actualFile) { - String[] expectedLines = expectedFile.split("(\\r?\\n)"); - String[] actualLines = actualFile.split("(\\r?\\n)"); - if (actualLines[0].startsWith("// Generated by delombok at ")) { - actualLines[0] = ""; - } - expectedLines = removeBlanks(expectedLines); - actualLines = removeBlanks(actualLines); - int size = Math.min(expectedLines.length, actualLines.length); - for (int i = 0; i < size; i++) { - String expected = expectedLines[i]; - String actual = actualLines[i]; - if (!expected.equals(actual)) { - fail(String.format("Difference in line %s(%d):\n`%s`\n`%s`\n", name, i, expected, actual)); - } - } - if (expectedLines.length > actualLines.length) { - fail(String.format("Missing line %s(%d): %s\n", name, size, expectedLines[size])); - } - if (expectedLines.length < actualLines.length) { - fail(String.format("Extra line %s(%d): %s\n", name, size, actualLines[size])); - } - } - - private String readAfter(File file) throws IOException { - BufferedReader reader = new BufferedReader(new FileReader(new File(AFTER_FOLDER, file.getName()))); - StringBuilder result = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - result.append(line); - result.append(LINE_SEPARATOR); - } - reader.close(); - return result.toString(); + TestViaDelombok.runComparison(BEFORE_DIR, AFTER_DIR); } } diff --git a/test/delombok/src/lombok/delombok/TestSourceFiles.java b/test/delombok/src/lombok/delombok/TestSourceFiles.java index 91ace773..a5df5197 100644 --- a/test/delombok/src/lombok/delombok/TestSourceFiles.java +++ b/test/delombok/src/lombok/delombok/TestSourceFiles.java @@ -21,86 +21,18 @@ */ package lombok.delombok; -import static org.junit.Assert.fail; - -import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.List; -import lombok.delombok.CommentPreservingParser.ParseResult; +import lombok.TestViaDelombok; -import org.junit.BeforeClass; import org.junit.Test; public class TestSourceFiles { - private static CommentPreservingParser parser; - - private static final File BEFORE_FOLDER = new File("test/delombok/resource/before"); - private static final File AFTER_FOLDER = new File("test/delombok/resource/after"); - - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); - - @BeforeClass - public static void init() { - parser = new CommentPreservingParser(); - } + private static final File BEFORE_DIR = new File("test/delombok/resource/before"); + private static final File AFTER_DIR = new File("test/delombok/resource/after"); @Test public void testSources() throws Exception { - File[] listFiles = BEFORE_FOLDER.listFiles(); - for (File file : listFiles) { - ParseResult parseResult = parser.parse(file.toString(), true); - StringWriter writer = new StringWriter(); - parseResult.print(writer); - compare(file.getName(), readAfter(file), writer.toString()); - } - } - - static String[] removeBlanks(String[] in) { - List out = new ArrayList(); - for (String s : in) { - if (!s.trim().isEmpty()) out.add(s); - } - return out.toArray(new String[0]); - } - - private void compare(String name, String expectedFile, String actualFile) { - String[] expectedLines = expectedFile.split("(\\r?\\n)"); - String[] actualLines = actualFile.split("(\\r?\\n)"); - if (actualLines[0].startsWith("// Generated by delombok at ")) { - actualLines[0] = ""; - } - expectedLines = removeBlanks(expectedLines); - actualLines = removeBlanks(actualLines); - int size = Math.min(expectedLines.length, actualLines.length); - for (int i = 0; i < size; i++) { - String expected = expectedLines[i]; - String actual = actualLines[i]; - if (!expected.equals(actual)) { - fail(String.format("Difference in line %s(%d):\nExpected `%s`\nGot `%s`\n", name, i, expected, actual)); - } - } - if (expectedLines.length > actualLines.length) { - fail(String.format("Missing line %s(%d): %s\n", name, size, expectedLines[size])); - } - if (expectedLines.length < actualLines.length) { - fail(String.format("Extra line %s(%d): %s\n", name, size, actualLines[size])); - } - } - - private String readAfter(File file) throws IOException { - BufferedReader reader = new BufferedReader(new FileReader(new File(AFTER_FOLDER, file.getName()))); - StringBuilder result = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - result.append(line); - result.append(LINE_SEPARATOR); - } - reader.close(); - return result.toString(); + TestViaDelombok.runComparison(BEFORE_DIR, AFTER_DIR); } } -- cgit From 9ac004b385f5fdc1a113a7b6fc38098c86e8ac8a Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Fri, 27 Nov 2009 07:19:38 +0100 Subject: Fixed whitespace to project standards. --- .../lombok/delombok/CommentCollectingScanner.java | 60 ++++++++++------------ .../lombok/delombok/CommentPreservingParser.java | 10 ++-- 2 files changed, 35 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/delombok/lombok/delombok/CommentCollectingScanner.java b/src/delombok/lombok/delombok/CommentCollectingScanner.java index c38aef24..361d975c 100644 --- a/src/delombok/lombok/delombok/CommentCollectingScanner.java +++ b/src/delombok/lombok/delombok/CommentCollectingScanner.java @@ -29,55 +29,52 @@ import com.sun.tools.javac.parser.Scanner; import com.sun.tools.javac.util.Context; public class CommentCollectingScanner extends Scanner { - - private final Comments comments; + private final Comments comments; /** A factory for creating scanners. */ - public static class Factory extends Scanner.Factory { - - private final Context context; - + public static class Factory extends Scanner.Factory { + private final Context context; + public static void preRegister(final Context context) { - context.put(scannerFactoryKey, new Context.Factory() { + context.put(scannerFactoryKey, new Context.Factory() { public CommentCollectingScanner.Factory make() { - return new Factory(context); + return new Factory(context); } - }); + }); } - + /** Create a new scanner factory. */ protected Factory(Context context) { - super(context); + super(context); this.context = context; } - - @Override - public Scanner newScanner(CharSequence input) { - if (input instanceof CharBuffer) { - return new CommentCollectingScanner(this, (CharBuffer)input, context.get(Comments.class)); - } - char[] array = input.toString().toCharArray(); - return newScanner(array, array.length); - } + + @Override + public Scanner newScanner(CharSequence input) { + if (input instanceof CharBuffer) { + return new CommentCollectingScanner(this, (CharBuffer)input, context.get(Comments.class)); + } + char[] array = input.toString().toCharArray(); + return newScanner(array, array.length); + } + + @Override + public Scanner newScanner(char[] input, int inputLength) { + return new CommentCollectingScanner(this, input, inputLength, context.get(Comments.class)); + } + } - @Override - public Scanner newScanner(char[] input, int inputLength) { - return new CommentCollectingScanner(this, input, inputLength, context.get(Comments.class)); - } - } - public CommentCollectingScanner(CommentCollectingScanner.Factory factory, CharBuffer charBuffer, Comments comments) { super(factory, charBuffer); this.comments = comments; } - - + public CommentCollectingScanner(CommentCollectingScanner.Factory factory, char[] input, int inputLength, Comments comments) { super(factory, input, inputLength); this.comments = comments; } - + @Override protected void processComment(CommentStyle style) { int prevEndPos = prevEndPos(); @@ -86,8 +83,7 @@ public class CommentCollectingScanner extends Scanner { 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') { @@ -96,4 +92,4 @@ public class CommentCollectingScanner extends Scanner { } 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 9fd8778c..d353a9a6 100644 --- a/src/delombok/lombok/delombok/CommentPreservingParser.java +++ b/src/delombok/lombok/delombok/CommentPreservingParser.java @@ -43,9 +43,8 @@ import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Options; public class CommentPreservingParser { - private final String encoding; - + public CommentPreservingParser() { this("utf-8"); } @@ -73,6 +72,7 @@ public class CommentPreservingParser { context.put(Comments.class, comments); comments.comments = List.nil(); + @SuppressWarnings("deprecation") JCCompilationUnit cu = compiler.parse(fileName); @@ -130,5 +130,9 @@ public class CommentPreservingParser { out.write("// Generated by delombok at " + new Date() + "\n"); compilationUnit.accept(new PrettyCommentsPrinter(out, compilationUnit, comments)); } + + public boolean isChanged() { + return changed; + } } -} \ No newline at end of file +} -- cgit From 2b61c2534b22f07a13d8cb4c97c2ad323c6c4597 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Fri, 27 Nov 2009 09:49:48 +0100 Subject: Delombok now works from the command line as: java -jar lombok.jar delombok (args) --- .../lombok/delombok/CommentPreservingParser.java | 9 +- src/delombok/lombok/delombok/Delombok.java | 132 +++++++++++++++++++-- src/installer/lombok/installer/Installer.java | 7 ++ 3 files changed, 136 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/delombok/lombok/delombok/CommentPreservingParser.java b/src/delombok/lombok/delombok/CommentPreservingParser.java index d353a9a6..c776a224 100644 --- a/src/delombok/lombok/delombok/CommentPreservingParser.java +++ b/src/delombok/lombok/delombok/CommentPreservingParser.java @@ -82,19 +82,19 @@ public class CommentPreservingParser { private static final Messager messager = new Messager() { @Override public void printMessage(Kind kind, CharSequence msg) { - System.out.printf("M: %s: %s\n", kind, msg); + System.out.printf("%s: %s\n", kind, msg); } @Override public void printMessage(Kind kind, CharSequence msg, Element e) { - System.out.printf("E: %s: %s\n", kind, msg); + System.out.printf("%s: %s\n", kind, msg); } @Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a) { - System.out.printf("A: %s: %s\n", kind, msg); + System.out.printf("%s: %s\n", kind, msg); } @Override public void printMessage(Kind kind, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v) { - System.out.printf("V: %s: %s\n", kind, msg); + System.out.printf("%s: %s\n", kind, msg); } }; @@ -122,7 +122,6 @@ public class CommentPreservingParser { JavaFileObject sourceFile = compilationUnit.getSourceFile(); if (sourceFile != null) { out.write(sourceFile.getCharContent(true).toString()); - System.out.println(out.toString()); return; } } diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index c6f9ecf9..e05f4982 100644 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -5,14 +5,26 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.Writer; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; +import java.util.ArrayList; +import java.util.List; import lombok.delombok.CommentPreservingParser.ParseResult; +import com.zwitserloot.cmdreader.CmdReader; +import com.zwitserloot.cmdreader.Description; +import com.zwitserloot.cmdreader.Excludes; +import com.zwitserloot.cmdreader.InvalidCommandLineException; +import com.zwitserloot.cmdreader.Mandatory; +import com.zwitserloot.cmdreader.Parameterized; +import com.zwitserloot.cmdreader.Sequential; +import com.zwitserloot.cmdreader.Shorthand; + public class Delombok { private Charset charset = Charset.defaultCharset(); private CommentPreservingParser parser = new CommentPreservingParser(); @@ -23,6 +35,107 @@ public class Delombok { /** If null, output to standard out. */ private File output = null; + private static class CmdArgs { + @Shorthand("v") + @Description("Print the name of each file as it is being delombok-ed.") + @Excludes("quiet") + private boolean verbose; + + @Shorthand("q") + @Description("No warnings or errors will be emitted to standard error") + @Excludes("verbose") + private boolean quiet; + + @Shorthand("e") + @Description("Sets the encoding of your source files. Defaults to the system default charset. Example: \"UTF-8\"") + @Parameterized + private String encoding; + + @Shorthand("p") + @Description("Print delombok-ed code to standard output instead of saving it in target directory") + private boolean print; + + @Shorthand("d") + @Description("Directory to save delomboked files to") + @Mandatory(onlyIfNot="print") + @Parameterized + private String target; + + @Description("Files to delombok. Provide either a file, or a directory. If you use a directory, all files in it (recursive) are delombok-ed") + @Sequential + @Parameterized + private List input = new ArrayList(); + + private boolean help; + } + + public static void main(String[] rawArgs) { + CmdReader reader = CmdReader.of(CmdArgs.class); + CmdArgs args; + try { + args = reader.make(rawArgs); + } catch (InvalidCommandLineException e) { + System.err.println("ERROR: " + e.getMessage()); + System.err.println(reader.generateCommandLineHelp("delombok")); + System.exit(1); + return; + } + + if (args.help || args.input.isEmpty()) { + if (args.input.isEmpty()) System.err.println("ERROR: no files or directories to delombok specified."); + System.err.println(reader.generateCommandLineHelp("delombok")); + System.exit(args.input.isEmpty() ? 1 : 0); + return; + } + + Delombok delombok = new Delombok(); + + if (args.quiet) delombok.setFeedback(new PrintStream(new OutputStream() { + @Override public void write(int b) throws IOException { + //dummy - do nothing. + } + })); + + if (args.encoding != null) { + try { + delombok.setCharset(args.encoding); + } catch (UnsupportedCharsetException e) { + System.err.println("ERROR: Not a known charset: " + args.encoding); + System.exit(1); + return; + } + } + + if (args.verbose) delombok.setVerbose(true); + if (args.print) delombok.setOutputToStandardOut(); + else delombok.setOutput(new File(args.target)); + + for (String in : args.input) { + try { + File f = new File(in); + if (f.isFile()) { + delombok.delombok(f.getParentFile(), f.getName()); + } else if (f.isDirectory()) { + delombok.delombok(f); + } else if (!f.exists()) { + if (!args.quiet) System.err.println("WARNING: does not exist - skipping: " + f); + } else { + if (!args.quiet) System.err.println("WARNING: not a standard file or directory - skipping: " + f); + } + } catch (Exception e) { + if (!args.quiet) { + String msg = e.getMessage(); + if (msg != null && msg.startsWith("DELOMBOK: ")) System.err.println(msg.substring("DELOMBOK: ".length())); + else { + e.printStackTrace(); + } + System.exit(1); + return; + } + } + } + } + public void setCharset(String charsetName) throws UnsupportedCharsetException { charset = Charset.forName(charsetName); } @@ -40,7 +153,7 @@ public class Delombok { } public void setOutput(File dir) { - if (dir.isFile()) throw new IllegalArgumentException( + if (dir.isFile() || (!dir.isDirectory() && dir.getName().endsWith(".java"))) throw new IllegalArgumentException( "DELOMBOK: delombok will only write to a directory. " + "If you want to delombok a single file, use -p to output to standard output, then redirect this to a file:\n" + "delombok MyJavaFile.java -p >MyJavaFileDelombok.java"); @@ -57,20 +170,23 @@ public class Delombok { private void delombok0(File base, String suffix, int loop) throws IOException { File dir = suffix.isEmpty() ? base : new File(base, suffix); - String name = suffix + File.separator + dir.getName(); + String name = suffix; if (dir.isDirectory()) { if (loop >= 100) { feedback.printf("Over 100 subdirectories? I'm guessing there's a loop in your directory structure. Skipping: %s\n", suffix); } else { - dir.mkdir(); - delombok0(base, name, loop + 1); + for (File f : dir.listFiles()) { + delombok0(base, suffix + (suffix.isEmpty() ? "" : File.separator) + f.getName(), loop + 1); + } } } else if (dir.isFile()) { String extension = getExtension(dir); - if (extension.equals(".java")) delombok(base, name); - else if (extension.equals(".class")) skipClass(name); + if (extension.equals("java")) delombok(base, name); + else if (extension.equals("class")) skipClass(name); else copy(base, name); + } else if (!dir.exists()) { + feedback.printf("Skipping %s because it does not exist.\n", canonical(dir)); } else { feedback.printf("Skipping %s because it is a special file type.\n", canonical(dir)); } @@ -87,7 +203,9 @@ public class Delombok { } if (verbose) feedback.printf("Copying resource file: %s\n", fileName); byte[] b = new byte[65536]; - FileInputStream in = new FileInputStream(new File(base, fileName)); + File outFile = new File(base, fileName); + outFile.getParentFile().mkdirs(); + FileInputStream in = new FileInputStream(outFile); try { FileOutputStream out = new FileOutputStream(new File(output, fileName)); try { diff --git a/src/installer/lombok/installer/Installer.java b/src/installer/lombok/installer/Installer.java index e1da5d31..a823dd69 100644 --- a/src/installer/lombok/installer/Installer.java +++ b/src/installer/lombok/installer/Installer.java @@ -64,6 +64,7 @@ import javax.swing.UIManager; import javax.swing.filechooser.FileFilter; import lombok.core.Version; +import lombok.delombok.Delombok; import lombok.installer.EclipseFinder.OS; import lombok.installer.EclipseLocation.InstallException; import lombok.installer.EclipseLocation.NotAnEclipseException; @@ -95,6 +96,12 @@ public class Installer { private JButton installButton; public static void main(String[] args) { + if (args.length > 0 && args[0].equals("delombok")) { + String[] newArgs = new String[args.length-1]; + System.arraycopy(args, 1, newArgs, 0, newArgs.length); + Delombok.main(newArgs); + return; + } if (args.length > 0 && (args[0].equals("install") || args[0].equals("uninstall"))) { boolean uninstall = args[0].equals("uninstall"); if (args.length < 3 || !args[1].equals("eclipse")) { -- cgit