--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,1515 @@
+/*
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.tree;
+
+import java.io.*;
+
+import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
+import com.sun.source.tree.ModuleTree.ModuleKind;
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.List;
+import static com.sun.tools.javac.code.Flags.*;
+import static com.sun.tools.javac.code.Flags.ANNOTATION;
+import static com.sun.tools.javac.tree.JCTree.Tag.*;
+
+/** Prints out a tree as an indented Java source program.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * 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.</b>
+ */
+public class Pretty extends JCTree.Visitor {
+
+ public Pretty(Writer out, boolean sourceOutput) {
+ this.out = out;
+ this.sourceOutput = sourceOutput;
+ }
+
+ /** Set when we are producing source output. If we're not
+ * producing source output, we can sometimes give more detail in
+ * the output even though that detail would not be valid java
+ * source.
+ */
+ private final boolean sourceOutput;
+
+ /** 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 table mapping trees to their documentation comments
+ * (can be null)
+ */
+ DocCommentTable docComments = null;
+
+ /**
+ * A string sequence to be used when Pretty output should be constrained
+ * to fit into a given size
+ */
+ private final static String trimSequence = "[...]";
+
+ /**
+ * Max number of chars to be generated when output should fit into a single line
+ */
+ private final static int PREFERRED_LENGTH = 20;
+
+ /** Align code to be indented to left margin.
+ */
+ void align() throws IOException {
+ 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 {
+ out.write(Convert.escapeUnicode(s.toString()));
+ }
+
+ /** Print new line.
+ */
+ public void println() throws IOException {
+ out.write(lineSep);
+ }
+
+ public static String toSimpleString(JCTree tree) {
+ return toSimpleString(tree, PREFERRED_LENGTH);
+ }
+
+ public static String toSimpleString(JCTree tree, int maxLength) {
+ StringWriter s = new StringWriter();
+ try {
+ new Pretty(s, false).printExpr(tree);
+ }
+ catch (IOException e) {
+ // should never happen, because StringWriter is defined
+ // never to throw any IOExceptions
+ throw new AssertionError(e);
+ }
+ //we need to (i) replace all line terminators with a space and (ii) remove
+ //occurrences of 'missing' in the Pretty output (generated when types are missing)
+ String res = s.toString().trim().replaceAll("\\s+", " ").replaceAll("/\\*missing\\*/", "");
+ if (res.length() < maxLength) {
+ return res;
+ } else {
+ int head = (maxLength - trimSequence.length()) * 2 / 3;
+ int tail = maxLength - trimSequence.length() - head;
+ return res.substring(0, head) + trimSequence + res.substring(res.length() - tail);
+ }
+ }
+
+ 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 {
+ tree.accept(this);
+ }
+ } 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 <T extends JCTree> void printExprs(List<T> trees, String sep) throws IOException {
+ if (trees.nonEmpty()) {
+ printExpr(trees.head);
+ for (List<T> 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 <T extends JCTree> void printExprs(List<T> trees) throws IOException {
+ printExprs(trees, ", ");
+ }
+
+ /** Derived visitor method: print list of statements, each on a separate line.
+ */
+ public void printStats(List<? extends JCTree> trees) throws IOException {
+ for (List<? extends JCTree> 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 & ExtendedStandardFlags) != 0) print(" ");
+ if ((flags & ANNOTATION) != 0) print("@");
+ }
+
+ public void printAnnotations(List<JCAnnotation> trees) throws IOException {
+ for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) {
+ printStat(l.head);
+ println();
+ align();
+ }
+ }
+
+ public void printTypeAnnotations(List<JCAnnotation> trees) throws IOException {
+ for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) {
+ printExpr(l.head);
+ print(" ");
+ }
+ }
+
+ /** 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.getCommentText(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
+ * {@literal "<...>"} brackets.
+ */
+ public void printTypeParameters(List<JCTypeParameter> trees) throws IOException {
+ if (trees.nonEmpty()) {
+ print("<");
+ printExprs(trees);
+ print(">");
+ }
+ }
+
+ /** Print a block.
+ */
+ public void printBlock(List<? extends JCTree> stats) throws IOException {
+ print("{");
+ println();
+ indent();
+ printStats(stats);
+ undent();
+ align();
+ print("}");
+ }
+
+ /** Print a block.
+ */
+ public void printEnumBody(List<JCTree> stats) throws IOException {
+ print("{");
+ println();
+ indent();
+ boolean first = true;
+ for (List<JCTree> 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<JCTree> 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 t.hasTag(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);
+
+ boolean firstImport = true;
+ for (List<JCTree> l = tree.defs;
+ l.nonEmpty() &&
+ (cdef == null ||
+ l.head.hasTag(IMPORT) || l.head.hasTag(PACKAGEDEF));
+ l = l.tail) {
+ if (l.head.hasTag(IMPORT)) {
+ JCImport imp = (JCImport)l.head;
+ Name name = TreeInfo.name(imp.qualid);
+ if (name == name.table.names.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 visitPackageDef(JCPackageDecl tree) {
+ try {
+ printDocComment(tree);
+ printAnnotations(tree.annotations);
+ if (tree.pid != null) {
+ print("package ");
+ printExpr(tree.pid);
+ print(";");
+ println();
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ @Override
+ public void visitModuleDef(JCModuleDecl tree) {
+ try {
+ printDocComment(tree);
+ printAnnotations(tree.mods.annotations);
+ if (tree.getModuleType() == ModuleKind.OPEN) {
+ print("open ");
+ }
+ print("module ");
+ printExpr(tree.qualId);
+ if (tree.directives == null) {
+ print(";");
+ } else {
+ printBlock(tree.directives);
+ }
+ println();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ @Override
+ public void visitExports(JCExports tree) {
+ try {
+ print("exports ");
+ printExpr(tree.qualid);
+ if (tree.moduleNames != null) {
+ print(" to ");
+ printExprs(tree.moduleNames);
+ }
+ print(";");
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ @Override
+ public void visitOpens(JCOpens tree) {
+ try {
+ print("opens ");
+ printExpr(tree.qualid);
+ if (tree.moduleNames != null) {
+ print(" to ");
+ printExprs(tree.moduleNames);
+ }
+ print(";");
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ @Override
+ public void visitProvides(JCProvides tree) {
+ try {
+ print("provides ");
+ printExpr(tree.serviceName);
+ print(" with ");
+ printExprs(tree.implNames);
+ print(";");
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ @Override
+ public void visitRequires(JCRequires tree) {
+ try {
+ print("requires ");
+ if (tree.isStaticPhase)
+ print("static ");
+ if (tree.isTransitive)
+ print("transitive ");
+ printExpr(tree.moduleName);
+ print(";");
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ @Override
+ public void visitUses(JCUses tree) {
+ try {
+ print("uses ");
+ printExpr(tree.qualid);
+ print(";");
+ } 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 {
+ 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);
+ }
+ 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.names.init &&
+ enclClassName == null &&
+ sourceOutput) return;
+ println(); align();
+ printDocComment(tree);
+ printExpr(tree.mods);
+ printTypeParameters(tree.typarams);
+ if (tree.name == tree.name.table.names.init) {
+ print(enclClassName != null ? enclClassName : tree.name);
+ } else {
+ printExpr(tree.restype);
+ print(" " + tree.name);
+ }
+ print("(");
+ if (tree.recvparam!=null) {
+ printExpr(tree.recvparam);
+ if (tree.params.size() > 0) {
+ print(", ");
+ }
+ }
+ printExprs(tree.params);
+ print(")");
+ if (tree.thrown.nonEmpty()) {
+ print(" throws ");
+ printExprs(tree.thrown);
+ }
+ if (tree.defaultValue != null) {
+ print(" default ");
+ printExpr(tree.defaultValue);
+ }
+ 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.hasComment(tree)) {
+ println(); align();
+ }
+ printDocComment(tree);
+ if ((tree.mods.flags & ENUM) != 0) {
+ print("/*public static final*/ ");
+ print(tree.name);
+ if (tree.init != null) {
+ if (sourceOutput && tree.init.hasTag(NEWCLASS)) {
+ print(" /*enum*/ ");
+ JCNewClass init = (JCNewClass) tree.init;
+ if (init.args != null && init.args.nonEmpty()) {
+ print("(");
+ print(init.args);
+ print(")");
+ }
+ if (init.def != null && init.def.defs != null) {
+ print(" ");
+ printBlock(init.def.defs);
+ }
+ return;
+ }
+ print(" /* = ");
+ printExpr(tree.init);
+ print(" */");
+ }
+ } else {
+ printExpr(tree.mods);
+ if ((tree.mods.flags & VARARGS) != 0) {
+ JCTree vartype = tree.vartype;
+ List<JCAnnotation> tas = null;
+ if (vartype instanceof JCAnnotatedType) {
+ tas = ((JCAnnotatedType)vartype).annotations;
+ vartype = ((JCAnnotatedType)vartype).underlyingType;
+ }
+ printExpr(((JCArrayTypeTree) vartype).elemtype);
+ if (tas != null) {
+ print(' ');
+ printTypeAnnotations(tas);
+ }
+ 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 {
+ printFlags(tree.flags);
+ printBlock(tree.stats);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public void visitDoLoop(JCDoWhileLoop tree) {
+ try {
+ print("do ");
+ printStat(tree.body);
+ align();
+ print(" while ");
+ if (tree.cond.hasTag(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 (tree.cond.hasTag(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 (tree.init.head.hasTag(VARDEF)) {
+ printExpr(tree.init.head);
+ for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) {
+ JCVariableDecl vdef = (JCVariableDecl)l.head;
+ print(", " + vdef.name);
+ if (vdef.init != null) {
+ print(" = ");
+ 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 (tree.selector.hasTag(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 (tree.lock.hasTag(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 ");
+ if (tree.resources.nonEmpty()) {
+ print("(");
+ boolean first = true;
+ for (JCTree var : tree.resources) {
+ if (!first) {
+ println();
+ indent();
+ }
+ printStat(var);
+ first = false;
+ }
+ print(") ");
+ }
+ printStat(tree.body);
+ for (List<JCCatch> 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 + 1);
+ print(" ? ");
+ printExpr(tree.truepart);
+ 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 (tree.cond.hasTag(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 (tree.meth.hasTag(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(">");
+ }
+ if (tree.def != null && tree.def.mods.annotations.nonEmpty()) {
+ printTypeAnnotations(tree.def.mods.annotations);
+ }
+ 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.names.empty
+ ? tree.type.tsym.name : null;
+ if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/");
+ printBlock(tree.def.defs);
+ 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;
+ printBaseElementType(elem);
+
+ if (!tree.annotations.isEmpty()) {
+ print(' ');
+ printTypeAnnotations(tree.annotations);
+ }
+ if (tree.elems != null) {
+ print("[]");
+ }
+
+ int i = 0;
+ List<List<JCAnnotation>> da = tree.dimAnnotations;
+ for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
+ if (da.size() > i && !da.get(i).isEmpty()) {
+ print(' ');
+ printTypeAnnotations(da.get(i));
+ }
+ print("[");
+ i++;
+ printExpr(l.head);
+ print("]");
+ }
+ printBrackets(elem);
+ }
+ if (tree.elems != null) {
+ print("{");
+ printExprs(tree.elems);
+ print("}");
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public void visitLambda(JCLambda tree) {
+ try {
+ print("(");
+ if (tree.paramKind == JCLambda.ParameterKind.EXPLICIT) {
+ printExprs(tree.params);
+ } else {
+ String sep = "";
+ for (JCVariableDecl param : tree.params) {
+ print(sep);
+ print(param.name);
+ sep = ",";
+ }
+ }
+ print(")->");
+ printExpr(tree.body);
+ } 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(JCTree.Tag tag) {
+ switch(tag) {
+ case POS: return "+";
+ case NEG: return "-";
+ case NOT: return "!";
+ case COMPL: return "~";
+ case PREINC: return "++";
+ case PREDEC: return "--";
+ case POSTINC: return "++";
+ case POSTDEC: return "--";
+ case NULLCHK: return "<*nullchk*>";
+ case OR: return "||";
+ case AND: return "&&";
+ case EQ: return "==";
+ case NE: return "!=";
+ case LT: return "<";
+ case GT: return ">";
+ case LE: return "<=";
+ case GE: return ">=";
+ case BITOR: return "|";
+ case BITXOR: return "^";
+ case BITAND: return "&";
+ case SL: return "<<";
+ case SR: return ">>";
+ case USR: return ">>>";
+ case PLUS: return "+";
+ case MINUS: return "-";
+ case MUL: return "*";
+ case DIV: return "/";
+ case MOD: return "%";
+ default: throw new Error();
+ }
+ }
+
+ public void visitAssignop(JCAssignOp tree) {
+ try {
+ open(prec, TreeInfo.assignopPrec);
+ printExpr(tree.lhs, TreeInfo.assignopPrec + 1);
+ print(" " + operatorName(tree.getTag().noAssignOp()) + "= ");
+ 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(tree.getTag());
+ String opname = operatorName(tree.getTag());
+ open(prec, ownprec);
+ if (!tree.getTag().isPostUnaryOp()) {
+ 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(tree.getTag());
+ String opname = operatorName(tree.getTag());
+ 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 visitReference(JCMemberReference tree) {
+ try {
+ printExpr(tree.expr);
+ print("::");
+ if (tree.typeargs != null) {
+ print("<");
+ printExprs(tree.typeargs);
+ print(">");
+ }
+ print(tree.getMode() == ReferenceMode.INVOKE ? tree.name : "new");
+ } 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 INT:
+ print(tree.value.toString());
+ break;
+ case LONG:
+ print(tree.value + "L");
+ break;
+ case FLOAT:
+ print(tree.value + "F");
+ break;
+ case DOUBLE:
+ print(tree.value.toString());
+ break;
+ case CHAR:
+ print("\'" +
+ Convert.quote(
+ String.valueOf((char)((Number)tree.value).intValue())) +
+ "\'");
+ break;
+ case BOOLEAN:
+ print(((Number)tree.value).intValue() == 1 ? "true" : "false");
+ break;
+ case 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 BYTE:
+ print("byte");
+ break;
+ case CHAR:
+ print("char");
+ break;
+ case SHORT:
+ print("short");
+ break;
+ case INT:
+ print("int");
+ break;
+ case LONG:
+ print("long");
+ break;
+ case FLOAT:
+ print("float");
+ break;
+ case DOUBLE:
+ print("double");
+ break;
+ case BOOLEAN:
+ print("boolean");
+ break;
+ case 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(JCTree tree) throws IOException {
+ printExpr(TreeInfo.innermostType(tree));
+ }
+
+ // prints the brackets of a nested array in reverse order
+ // tree is either JCArrayTypeTree or JCAnnotatedTypeTree
+ private void printBrackets(JCTree tree) throws IOException {
+ JCTree elem = tree;
+ while (true) {
+ if (elem.hasTag(ANNOTATED_TYPE)) {
+ JCAnnotatedType atype = (JCAnnotatedType) elem;
+ elem = atype.underlyingType;
+ if (elem.hasTag(TYPEARRAY)) {
+ print(' ');
+ printTypeAnnotations(atype.annotations);
+ }
+ }
+ if (elem.hasTag(TYPEARRAY)) {
+ print("[]");
+ elem = ((JCArrayTypeTree)elem).elemtype;
+ } else {
+ break;
+ }
+ }
+ }
+
+ public void visitTypeApply(JCTypeApply tree) {
+ try {
+ printExpr(tree.clazz);
+ print("<");
+ printExprs(tree.arguments);
+ print(">");
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public void visitTypeUnion(JCTypeUnion tree) {
+ try {
+ printExprs(tree.alternatives, " | ");
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public void visitTypeIntersection(JCTypeIntersection tree) {
+ try {
+ printExprs(tree.bounds, " & ");
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public void visitTypeParameter(JCTypeParameter tree) {
+ try {
+ if (tree.annotations.nonEmpty()) {
+ this.printTypeAnnotations(tree.annotations);
+ }
+ 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.kind.kind != BoundKind.UNBOUND)
+ printExpr(tree.inner);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ @Override
+ 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 visitAnnotatedType(JCAnnotatedType tree) {
+ try {
+ if (tree.underlyingType.hasTag(SELECT)) {
+ JCFieldAccess access = (JCFieldAccess) tree.underlyingType;
+ printExpr(access.selected, TreeInfo.postfixPrec);
+ print(".");
+ printTypeAnnotations(tree.annotations);
+ print(access.name);
+ } else if (tree.underlyingType.hasTag(TYPEARRAY)) {
+ printBaseElementType(tree);
+ printBrackets(tree);
+ } else {
+ printTypeAnnotations(tree.annotations);
+ printExpr(tree.underlyingType);
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public void visitTree(JCTree tree) {
+ try {
+ print("(UNKNOWN: " + tree.getTag() + ")");
+ println();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+}