1 /* 2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javac.tree; 27 28 import java.io.*; 29 30 import com.sun.source.tree.MemberReferenceTree.ReferenceMode; 31 import com.sun.tools.javac.code.*; 32 import com.sun.tools.javac.tree.JCTree.*; 33 import com.sun.tools.javac.util.*; 34 import com.sun.tools.javac.util.List; 35 import static com.sun.tools.javac.code.Flags.*; 36 import static com.sun.tools.javac.code.Flags.ANNOTATION; 37 import static com.sun.tools.javac.tree.JCTree.Tag.*; 38 39 /** Prints out a tree as an indented Java source program. 40 * 41 * <p><b>This is NOT part of any supported API. 42 * If you write code that depends on this, you do so at your own risk. 43 * This code and its internal interfaces are subject to change or 44 * deletion without notice.</b> 45 */ 46 public class Pretty extends JCTree.Visitor { 47 Pretty(Writer out, boolean sourceOutput)48 public Pretty(Writer out, boolean sourceOutput) { 49 this.out = out; 50 this.sourceOutput = sourceOutput; 51 } 52 53 /** Set when we are producing source output. If we're not 54 * producing source output, we can sometimes give more detail in 55 * the output even though that detail would not be valid java 56 * source. 57 */ 58 private final boolean sourceOutput; 59 60 /** The output stream on which trees are printed. 61 */ 62 Writer out; 63 64 /** Indentation width (can be reassigned from outside). 65 */ 66 public int width = 4; 67 68 /** The current left margin. 69 */ 70 int lmargin = 0; 71 72 /** The enclosing class name. 73 */ 74 Name enclClassName; 75 76 /** A table mapping trees to their documentation comments 77 * (can be null) 78 */ 79 DocCommentTable docComments = null; 80 81 /** 82 * A string sequence to be used when Pretty output should be constrained 83 * to fit into a given size 84 */ 85 private final static String trimSequence = "[...]"; 86 87 /** 88 * Max number of chars to be generated when output should fit into a single line 89 */ 90 private final static int PREFERRED_LENGTH = 20; 91 92 /** Align code to be indented to left margin. 93 */ align()94 void align() throws IOException { 95 for (int i = 0; i < lmargin; i++) out.write(" "); 96 } 97 98 /** Increase left margin by indentation width. 99 */ indent()100 void indent() { 101 lmargin = lmargin + width; 102 } 103 104 /** Decrease left margin by indentation width. 105 */ undent()106 void undent() { 107 lmargin = lmargin - width; 108 } 109 110 /** Enter a new precedence level. Emit a `(' if new precedence level 111 * is less than precedence level so far. 112 * @param contextPrec The precedence level in force so far. 113 * @param ownPrec The new precedence level. 114 */ open(int contextPrec, int ownPrec)115 void open(int contextPrec, int ownPrec) throws IOException { 116 if (ownPrec < contextPrec) out.write("("); 117 } 118 119 /** Leave precedence level. Emit a `(' if inner precedence level 120 * is less than precedence level we revert to. 121 * @param contextPrec The precedence level we revert to. 122 * @param ownPrec The inner precedence level. 123 */ close(int contextPrec, int ownPrec)124 void close(int contextPrec, int ownPrec) throws IOException { 125 if (ownPrec < contextPrec) out.write(")"); 126 } 127 128 /** Print string, replacing all non-ascii character with unicode escapes. 129 */ print(Object s)130 public void print(Object s) throws IOException { 131 out.write(Convert.escapeUnicode(s.toString())); 132 } 133 134 /** Print new line. 135 */ println()136 public void println() throws IOException { 137 out.write(lineSep); 138 } 139 toSimpleString(JCTree tree)140 public static String toSimpleString(JCTree tree) { 141 return toSimpleString(tree, PREFERRED_LENGTH); 142 } 143 toSimpleString(JCTree tree, int maxLength)144 public static String toSimpleString(JCTree tree, int maxLength) { 145 StringWriter s = new StringWriter(); 146 try { 147 new Pretty(s, false).printExpr(tree); 148 } 149 catch (IOException e) { 150 // should never happen, because StringWriter is defined 151 // never to throw any IOExceptions 152 throw new AssertionError(e); 153 } 154 //we need to (i) replace all line terminators with a space and (ii) remove 155 //occurrences of 'missing' in the Pretty output (generated when types are missing) 156 String res = s.toString().trim().replaceAll("\\s+", " ").replaceAll("/\\*missing\\*/", ""); 157 if (res.length() < maxLength) { 158 return res; 159 } else { 160 int head = (maxLength - trimSequence.length()) * 2 / 3; 161 int tail = maxLength - trimSequence.length() - head; 162 return res.substring(0, head) + trimSequence + res.substring(res.length() - tail); 163 } 164 } 165 166 String lineSep = System.getProperty("line.separator"); 167 168 /************************************************************************** 169 * Traversal methods 170 *************************************************************************/ 171 172 /** Exception to propogate IOException through visitXXX methods */ 173 private static class UncheckedIOException extends Error { 174 static final long serialVersionUID = -4032692679158424751L; UncheckedIOException(IOException e)175 UncheckedIOException(IOException e) { 176 super(e.getMessage(), e); 177 } 178 } 179 180 /** Visitor argument: the current precedence level. 181 */ 182 int prec; 183 184 /** Visitor method: print expression tree. 185 * @param prec The current precedence level. 186 */ printExpr(JCTree tree, int prec)187 public void printExpr(JCTree tree, int prec) throws IOException { 188 int prevPrec = this.prec; 189 try { 190 this.prec = prec; 191 if (tree == null) print("/*missing*/"); 192 else { 193 tree.accept(this); 194 } 195 } catch (UncheckedIOException ex) { 196 IOException e = new IOException(ex.getMessage()); 197 e.initCause(ex); 198 throw e; 199 } finally { 200 this.prec = prevPrec; 201 } 202 } 203 204 /** Derived visitor method: print expression tree at minimum precedence level 205 * for expression. 206 */ printExpr(JCTree tree)207 public void printExpr(JCTree tree) throws IOException { 208 printExpr(tree, TreeInfo.noPrec); 209 } 210 211 /** Derived visitor method: print statement tree. 212 */ printStat(JCTree tree)213 public void printStat(JCTree tree) throws IOException { 214 printExpr(tree, TreeInfo.notExpression); 215 } 216 217 /** Derived visitor method: print list of expression trees, separated by given string. 218 * @param sep the separator string 219 */ printExprs(List<T> trees, String sep)220 public <T extends JCTree> void printExprs(List<T> trees, String sep) throws IOException { 221 if (trees.nonEmpty()) { 222 printExpr(trees.head); 223 for (List<T> l = trees.tail; l.nonEmpty(); l = l.tail) { 224 print(sep); 225 printExpr(l.head); 226 } 227 } 228 } 229 230 /** Derived visitor method: print list of expression trees, separated by commas. 231 */ printExprs(List<T> trees)232 public <T extends JCTree> void printExprs(List<T> trees) throws IOException { 233 printExprs(trees, ", "); 234 } 235 236 /** Derived visitor method: print list of statements, each on a separate line. 237 */ printStats(List<? extends JCTree> trees)238 public void printStats(List<? extends JCTree> trees) throws IOException { 239 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) { 240 align(); 241 printStat(l.head); 242 println(); 243 } 244 } 245 246 /** Print a set of modifiers. 247 */ printFlags(long flags)248 public void printFlags(long flags) throws IOException { 249 if ((flags & SYNTHETIC) != 0) print("/*synthetic*/ "); 250 print(TreeInfo.flagNames(flags)); 251 if ((flags & ExtendedStandardFlags) != 0) print(" "); 252 if ((flags & ANNOTATION) != 0) print("@"); 253 } 254 printAnnotations(List<JCAnnotation> trees)255 public void printAnnotations(List<JCAnnotation> trees) throws IOException { 256 for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) { 257 printStat(l.head); 258 println(); 259 align(); 260 } 261 } 262 printTypeAnnotations(List<JCAnnotation> trees)263 public void printTypeAnnotations(List<JCAnnotation> trees) throws IOException { 264 for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) { 265 printExpr(l.head); 266 print(" "); 267 } 268 } 269 270 /** Print documentation comment, if it exists 271 * @param tree The tree for which a documentation comment should be printed. 272 */ printDocComment(JCTree tree)273 public void printDocComment(JCTree tree) throws IOException { 274 if (docComments != null) { 275 String dc = docComments.getCommentText(tree); 276 if (dc != null) { 277 print("/**"); println(); 278 int pos = 0; 279 int endpos = lineEndPos(dc, pos); 280 while (pos < dc.length()) { 281 align(); 282 print(" *"); 283 if (pos < dc.length() && dc.charAt(pos) > ' ') print(" "); 284 print(dc.substring(pos, endpos)); println(); 285 pos = endpos + 1; 286 endpos = lineEndPos(dc, pos); 287 } 288 align(); print(" */"); println(); 289 align(); 290 } 291 } 292 } 293 //where lineEndPos(String s, int start)294 static int lineEndPos(String s, int start) { 295 int pos = s.indexOf('\n', start); 296 if (pos < 0) pos = s.length(); 297 return pos; 298 } 299 300 /** If type parameter list is non-empty, print it enclosed in 301 * {@literal "<...>"} brackets. 302 */ printTypeParameters(List<JCTypeParameter> trees)303 public void printTypeParameters(List<JCTypeParameter> trees) throws IOException { 304 if (trees.nonEmpty()) { 305 print("<"); 306 printExprs(trees); 307 print(">"); 308 } 309 } 310 311 /** Print a block. 312 */ printBlock(List<? extends JCTree> stats)313 public void printBlock(List<? extends JCTree> stats) throws IOException { 314 print("{"); 315 println(); 316 indent(); 317 printStats(stats); 318 undent(); 319 align(); 320 print("}"); 321 } 322 323 /** Print a block. 324 */ printEnumBody(List<JCTree> stats)325 public void printEnumBody(List<JCTree> stats) throws IOException { 326 print("{"); 327 println(); 328 indent(); 329 boolean first = true; 330 for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) { 331 if (isEnumerator(l.head)) { 332 if (!first) { 333 print(","); 334 println(); 335 } 336 align(); 337 printStat(l.head); 338 first = false; 339 } 340 } 341 print(";"); 342 println(); 343 for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) { 344 if (!isEnumerator(l.head)) { 345 align(); 346 printStat(l.head); 347 println(); 348 } 349 } 350 undent(); 351 align(); 352 print("}"); 353 } 354 355 /** Is the given tree an enumerator definition? */ isEnumerator(JCTree t)356 boolean isEnumerator(JCTree t) { 357 return t.hasTag(VARDEF) && (((JCVariableDecl) t).mods.flags & ENUM) != 0; 358 } 359 360 /** Print unit consisting of package clause and import statements in toplevel, 361 * followed by class definition. if class definition == null, 362 * print all definitions in toplevel. 363 * @param tree The toplevel tree 364 * @param cdef The class definition, which is assumed to be part of the 365 * toplevel tree. 366 */ printUnit(JCCompilationUnit tree, JCClassDecl cdef)367 public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException { 368 docComments = tree.docComments; 369 printDocComment(tree); 370 if (tree.pid != null) { 371 print("package "); 372 printExpr(tree.pid); 373 print(";"); 374 println(); 375 } 376 boolean firstImport = true; 377 for (List<JCTree> l = tree.defs; 378 l.nonEmpty() && (cdef == null || l.head.hasTag(IMPORT)); 379 l = l.tail) { 380 if (l.head.hasTag(IMPORT)) { 381 JCImport imp = (JCImport)l.head; 382 Name name = TreeInfo.name(imp.qualid); 383 if (name == name.table.names.asterisk || 384 cdef == null || 385 isUsed(TreeInfo.symbol(imp.qualid), cdef)) { 386 if (firstImport) { 387 firstImport = false; 388 println(); 389 } 390 printStat(imp); 391 } 392 } else { 393 printStat(l.head); 394 } 395 } 396 if (cdef != null) { 397 printStat(cdef); 398 println(); 399 } 400 } 401 // where isUsed(final Symbol t, JCTree cdef)402 boolean isUsed(final Symbol t, JCTree cdef) { 403 class UsedVisitor extends TreeScanner { 404 public void scan(JCTree tree) { 405 if (tree!=null && !result) tree.accept(this); 406 } 407 boolean result = false; 408 public void visitIdent(JCIdent tree) { 409 if (tree.sym == t) result = true; 410 } 411 } 412 UsedVisitor v = new UsedVisitor(); 413 v.scan(cdef); 414 return v.result; 415 } 416 417 /************************************************************************** 418 * Visitor methods 419 *************************************************************************/ 420 visitTopLevel(JCCompilationUnit tree)421 public void visitTopLevel(JCCompilationUnit tree) { 422 try { 423 printUnit(tree, null); 424 } catch (IOException e) { 425 throw new UncheckedIOException(e); 426 } 427 } 428 visitImport(JCImport tree)429 public void visitImport(JCImport tree) { 430 try { 431 print("import "); 432 if (tree.staticImport) print("static "); 433 printExpr(tree.qualid); 434 print(";"); 435 println(); 436 } catch (IOException e) { 437 throw new UncheckedIOException(e); 438 } 439 } 440 visitClassDef(JCClassDecl tree)441 public void visitClassDef(JCClassDecl tree) { 442 try { 443 println(); align(); 444 printDocComment(tree); 445 printAnnotations(tree.mods.annotations); 446 printFlags(tree.mods.flags & ~INTERFACE); 447 Name enclClassNamePrev = enclClassName; 448 enclClassName = tree.name; 449 if ((tree.mods.flags & INTERFACE) != 0) { 450 print("interface " + tree.name); 451 printTypeParameters(tree.typarams); 452 if (tree.implementing.nonEmpty()) { 453 print(" extends "); 454 printExprs(tree.implementing); 455 } 456 } else { 457 if ((tree.mods.flags & ENUM) != 0) 458 print("enum " + tree.name); 459 else 460 print("class " + tree.name); 461 printTypeParameters(tree.typarams); 462 if (tree.extending != null) { 463 print(" extends "); 464 printExpr(tree.extending); 465 } 466 if (tree.implementing.nonEmpty()) { 467 print(" implements "); 468 printExprs(tree.implementing); 469 } 470 } 471 print(" "); 472 if ((tree.mods.flags & ENUM) != 0) { 473 printEnumBody(tree.defs); 474 } else { 475 printBlock(tree.defs); 476 } 477 enclClassName = enclClassNamePrev; 478 } catch (IOException e) { 479 throw new UncheckedIOException(e); 480 } 481 } 482 visitMethodDef(JCMethodDecl tree)483 public void visitMethodDef(JCMethodDecl tree) { 484 try { 485 // when producing source output, omit anonymous constructors 486 if (tree.name == tree.name.table.names.init && 487 enclClassName == null && 488 sourceOutput) return; 489 println(); align(); 490 printDocComment(tree); 491 printExpr(tree.mods); 492 printTypeParameters(tree.typarams); 493 if (tree.name == tree.name.table.names.init) { 494 print(enclClassName != null ? enclClassName : tree.name); 495 } else { 496 printExpr(tree.restype); 497 print(" " + tree.name); 498 } 499 print("("); 500 if (tree.recvparam!=null) { 501 printExpr(tree.recvparam); 502 if (tree.params.size() > 0) { 503 print(", "); 504 } 505 } 506 printExprs(tree.params); 507 print(")"); 508 if (tree.thrown.nonEmpty()) { 509 print(" throws "); 510 printExprs(tree.thrown); 511 } 512 if (tree.defaultValue != null) { 513 print(" default "); 514 printExpr(tree.defaultValue); 515 } 516 if (tree.body != null) { 517 print(" "); 518 printStat(tree.body); 519 } else { 520 print(";"); 521 } 522 } catch (IOException e) { 523 throw new UncheckedIOException(e); 524 } 525 } 526 visitVarDef(JCVariableDecl tree)527 public void visitVarDef(JCVariableDecl tree) { 528 try { 529 if (docComments != null && docComments.hasComment(tree)) { 530 println(); align(); 531 } 532 printDocComment(tree); 533 if ((tree.mods.flags & ENUM) != 0) { 534 print("/*public static final*/ "); 535 print(tree.name); 536 if (tree.init != null) { 537 if (sourceOutput && tree.init.hasTag(NEWCLASS)) { 538 print(" /*enum*/ "); 539 JCNewClass init = (JCNewClass) tree.init; 540 if (init.args != null && init.args.nonEmpty()) { 541 print("("); 542 print(init.args); 543 print(")"); 544 } 545 if (init.def != null && init.def.defs != null) { 546 print(" "); 547 printBlock(init.def.defs); 548 } 549 return; 550 } 551 print(" /* = "); 552 printExpr(tree.init); 553 print(" */"); 554 } 555 } else { 556 printExpr(tree.mods); 557 if ((tree.mods.flags & VARARGS) != 0) { 558 JCTree vartype = tree.vartype; 559 List<JCAnnotation> tas = null; 560 if (vartype instanceof JCAnnotatedType) { 561 tas = ((JCAnnotatedType)vartype).annotations; 562 vartype = ((JCAnnotatedType)vartype).underlyingType; 563 } 564 printExpr(((JCArrayTypeTree) vartype).elemtype); 565 if (tas != null) { 566 print(' '); 567 printTypeAnnotations(tas); 568 } 569 print("... " + tree.name); 570 } else { 571 printExpr(tree.vartype); 572 print(" " + tree.name); 573 } 574 if (tree.init != null) { 575 print(" = "); 576 printExpr(tree.init); 577 } 578 if (prec == TreeInfo.notExpression) print(";"); 579 } 580 } catch (IOException e) { 581 throw new UncheckedIOException(e); 582 } 583 } 584 visitSkip(JCSkip tree)585 public void visitSkip(JCSkip tree) { 586 try { 587 print(";"); 588 } catch (IOException e) { 589 throw new UncheckedIOException(e); 590 } 591 } 592 visitBlock(JCBlock tree)593 public void visitBlock(JCBlock tree) { 594 try { 595 printFlags(tree.flags); 596 printBlock(tree.stats); 597 } catch (IOException e) { 598 throw new UncheckedIOException(e); 599 } 600 } 601 visitDoLoop(JCDoWhileLoop tree)602 public void visitDoLoop(JCDoWhileLoop tree) { 603 try { 604 print("do "); 605 printStat(tree.body); 606 align(); 607 print(" while "); 608 if (tree.cond.hasTag(PARENS)) { 609 printExpr(tree.cond); 610 } else { 611 print("("); 612 printExpr(tree.cond); 613 print(")"); 614 } 615 print(";"); 616 } catch (IOException e) { 617 throw new UncheckedIOException(e); 618 } 619 } 620 visitWhileLoop(JCWhileLoop tree)621 public void visitWhileLoop(JCWhileLoop tree) { 622 try { 623 print("while "); 624 if (tree.cond.hasTag(PARENS)) { 625 printExpr(tree.cond); 626 } else { 627 print("("); 628 printExpr(tree.cond); 629 print(")"); 630 } 631 print(" "); 632 printStat(tree.body); 633 } catch (IOException e) { 634 throw new UncheckedIOException(e); 635 } 636 } 637 visitForLoop(JCForLoop tree)638 public void visitForLoop(JCForLoop tree) { 639 try { 640 print("for ("); 641 if (tree.init.nonEmpty()) { 642 if (tree.init.head.hasTag(VARDEF)) { 643 printExpr(tree.init.head); 644 for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) { 645 JCVariableDecl vdef = (JCVariableDecl)l.head; 646 print(", " + vdef.name + " = "); 647 printExpr(vdef.init); 648 } 649 } else { 650 printExprs(tree.init); 651 } 652 } 653 print("; "); 654 if (tree.cond != null) printExpr(tree.cond); 655 print("; "); 656 printExprs(tree.step); 657 print(") "); 658 printStat(tree.body); 659 } catch (IOException e) { 660 throw new UncheckedIOException(e); 661 } 662 } 663 visitForeachLoop(JCEnhancedForLoop tree)664 public void visitForeachLoop(JCEnhancedForLoop tree) { 665 try { 666 print("for ("); 667 printExpr(tree.var); 668 print(" : "); 669 printExpr(tree.expr); 670 print(") "); 671 printStat(tree.body); 672 } catch (IOException e) { 673 throw new UncheckedIOException(e); 674 } 675 } 676 visitLabelled(JCLabeledStatement tree)677 public void visitLabelled(JCLabeledStatement tree) { 678 try { 679 print(tree.label + ": "); 680 printStat(tree.body); 681 } catch (IOException e) { 682 throw new UncheckedIOException(e); 683 } 684 } 685 visitSwitch(JCSwitch tree)686 public void visitSwitch(JCSwitch tree) { 687 try { 688 print("switch "); 689 if (tree.selector.hasTag(PARENS)) { 690 printExpr(tree.selector); 691 } else { 692 print("("); 693 printExpr(tree.selector); 694 print(")"); 695 } 696 print(" {"); 697 println(); 698 printStats(tree.cases); 699 align(); 700 print("}"); 701 } catch (IOException e) { 702 throw new UncheckedIOException(e); 703 } 704 } 705 visitCase(JCCase tree)706 public void visitCase(JCCase tree) { 707 try { 708 if (tree.pat == null) { 709 print("default"); 710 } else { 711 print("case "); 712 printExpr(tree.pat); 713 } 714 print(": "); 715 println(); 716 indent(); 717 printStats(tree.stats); 718 undent(); 719 align(); 720 } catch (IOException e) { 721 throw new UncheckedIOException(e); 722 } 723 } 724 visitSynchronized(JCSynchronized tree)725 public void visitSynchronized(JCSynchronized tree) { 726 try { 727 print("synchronized "); 728 if (tree.lock.hasTag(PARENS)) { 729 printExpr(tree.lock); 730 } else { 731 print("("); 732 printExpr(tree.lock); 733 print(")"); 734 } 735 print(" "); 736 printStat(tree.body); 737 } catch (IOException e) { 738 throw new UncheckedIOException(e); 739 } 740 } 741 visitTry(JCTry tree)742 public void visitTry(JCTry tree) { 743 try { 744 print("try "); 745 if (tree.resources.nonEmpty()) { 746 print("("); 747 boolean first = true; 748 for (JCTree var : tree.resources) { 749 if (!first) { 750 println(); 751 indent(); 752 } 753 printStat(var); 754 first = false; 755 } 756 print(") "); 757 } 758 printStat(tree.body); 759 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 760 printStat(l.head); 761 } 762 if (tree.finalizer != null) { 763 print(" finally "); 764 printStat(tree.finalizer); 765 } 766 } catch (IOException e) { 767 throw new UncheckedIOException(e); 768 } 769 } 770 visitCatch(JCCatch tree)771 public void visitCatch(JCCatch tree) { 772 try { 773 print(" catch ("); 774 printExpr(tree.param); 775 print(") "); 776 printStat(tree.body); 777 } catch (IOException e) { 778 throw new UncheckedIOException(e); 779 } 780 } 781 visitConditional(JCConditional tree)782 public void visitConditional(JCConditional tree) { 783 try { 784 open(prec, TreeInfo.condPrec); 785 printExpr(tree.cond, TreeInfo.condPrec + 1); 786 print(" ? "); 787 printExpr(tree.truepart); 788 print(" : "); 789 printExpr(tree.falsepart, TreeInfo.condPrec); 790 close(prec, TreeInfo.condPrec); 791 } catch (IOException e) { 792 throw new UncheckedIOException(e); 793 } 794 } 795 visitIf(JCIf tree)796 public void visitIf(JCIf tree) { 797 try { 798 print("if "); 799 if (tree.cond.hasTag(PARENS)) { 800 printExpr(tree.cond); 801 } else { 802 print("("); 803 printExpr(tree.cond); 804 print(")"); 805 } 806 print(" "); 807 printStat(tree.thenpart); 808 if (tree.elsepart != null) { 809 print(" else "); 810 printStat(tree.elsepart); 811 } 812 } catch (IOException e) { 813 throw new UncheckedIOException(e); 814 } 815 } 816 visitExec(JCExpressionStatement tree)817 public void visitExec(JCExpressionStatement tree) { 818 try { 819 printExpr(tree.expr); 820 if (prec == TreeInfo.notExpression) print(";"); 821 } catch (IOException e) { 822 throw new UncheckedIOException(e); 823 } 824 } 825 visitBreak(JCBreak tree)826 public void visitBreak(JCBreak tree) { 827 try { 828 print("break"); 829 if (tree.label != null) print(" " + tree.label); 830 print(";"); 831 } catch (IOException e) { 832 throw new UncheckedIOException(e); 833 } 834 } 835 visitContinue(JCContinue tree)836 public void visitContinue(JCContinue tree) { 837 try { 838 print("continue"); 839 if (tree.label != null) print(" " + tree.label); 840 print(";"); 841 } catch (IOException e) { 842 throw new UncheckedIOException(e); 843 } 844 } 845 visitReturn(JCReturn tree)846 public void visitReturn(JCReturn tree) { 847 try { 848 print("return"); 849 if (tree.expr != null) { 850 print(" "); 851 printExpr(tree.expr); 852 } 853 print(";"); 854 } catch (IOException e) { 855 throw new UncheckedIOException(e); 856 } 857 } 858 visitThrow(JCThrow tree)859 public void visitThrow(JCThrow tree) { 860 try { 861 print("throw "); 862 printExpr(tree.expr); 863 print(";"); 864 } catch (IOException e) { 865 throw new UncheckedIOException(e); 866 } 867 } 868 visitAssert(JCAssert tree)869 public void visitAssert(JCAssert tree) { 870 try { 871 print("assert "); 872 printExpr(tree.cond); 873 if (tree.detail != null) { 874 print(" : "); 875 printExpr(tree.detail); 876 } 877 print(";"); 878 } catch (IOException e) { 879 throw new UncheckedIOException(e); 880 } 881 } 882 visitApply(JCMethodInvocation tree)883 public void visitApply(JCMethodInvocation tree) { 884 try { 885 if (!tree.typeargs.isEmpty()) { 886 if (tree.meth.hasTag(SELECT)) { 887 JCFieldAccess left = (JCFieldAccess)tree.meth; 888 printExpr(left.selected); 889 print(".<"); 890 printExprs(tree.typeargs); 891 print(">" + left.name); 892 } else { 893 print("<"); 894 printExprs(tree.typeargs); 895 print(">"); 896 printExpr(tree.meth); 897 } 898 } else { 899 printExpr(tree.meth); 900 } 901 print("("); 902 printExprs(tree.args); 903 print(")"); 904 } catch (IOException e) { 905 throw new UncheckedIOException(e); 906 } 907 } 908 visitNewClass(JCNewClass tree)909 public void visitNewClass(JCNewClass tree) { 910 try { 911 if (tree.encl != null) { 912 printExpr(tree.encl); 913 print("."); 914 } 915 print("new "); 916 if (!tree.typeargs.isEmpty()) { 917 print("<"); 918 printExprs(tree.typeargs); 919 print(">"); 920 } 921 if (tree.def != null && tree.def.mods.annotations.nonEmpty()) { 922 printTypeAnnotations(tree.def.mods.annotations); 923 } 924 printExpr(tree.clazz); 925 print("("); 926 printExprs(tree.args); 927 print(")"); 928 if (tree.def != null) { 929 Name enclClassNamePrev = enclClassName; 930 enclClassName = 931 tree.def.name != null ? tree.def.name : 932 tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.names.empty 933 ? tree.type.tsym.name : null; 934 if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/"); 935 printBlock(tree.def.defs); 936 enclClassName = enclClassNamePrev; 937 } 938 } catch (IOException e) { 939 throw new UncheckedIOException(e); 940 } 941 } 942 visitNewArray(JCNewArray tree)943 public void visitNewArray(JCNewArray tree) { 944 try { 945 if (tree.elemtype != null) { 946 print("new "); 947 JCTree elem = tree.elemtype; 948 printBaseElementType(elem); 949 950 if (!tree.annotations.isEmpty()) { 951 print(' '); 952 printTypeAnnotations(tree.annotations); 953 } 954 if (tree.elems != null) { 955 print("[]"); 956 } 957 958 int i = 0; 959 List<List<JCAnnotation>> da = tree.dimAnnotations; 960 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) { 961 if (da.size() > i && !da.get(i).isEmpty()) { 962 print(' '); 963 printTypeAnnotations(da.get(i)); 964 } 965 print("["); 966 i++; 967 printExpr(l.head); 968 print("]"); 969 } 970 printBrackets(elem); 971 } 972 if (tree.elems != null) { 973 print("{"); 974 printExprs(tree.elems); 975 print("}"); 976 } 977 } catch (IOException e) { 978 throw new UncheckedIOException(e); 979 } 980 } 981 visitLambda(JCLambda tree)982 public void visitLambda(JCLambda tree) { 983 try { 984 print("("); 985 if (tree.paramKind == JCLambda.ParameterKind.EXPLICIT) { 986 printExprs(tree.params); 987 } else { 988 String sep = ""; 989 for (JCVariableDecl param : tree.params) { 990 print(sep); 991 print(param.name); 992 sep = ","; 993 } 994 } 995 print(")->"); 996 printExpr(tree.body); 997 } catch (IOException e) { 998 throw new UncheckedIOException(e); 999 } 1000 } 1001 visitParens(JCParens tree)1002 public void visitParens(JCParens tree) { 1003 try { 1004 print("("); 1005 printExpr(tree.expr); 1006 print(")"); 1007 } catch (IOException e) { 1008 throw new UncheckedIOException(e); 1009 } 1010 } 1011 visitAssign(JCAssign tree)1012 public void visitAssign(JCAssign tree) { 1013 try { 1014 open(prec, TreeInfo.assignPrec); 1015 printExpr(tree.lhs, TreeInfo.assignPrec + 1); 1016 print(" = "); 1017 printExpr(tree.rhs, TreeInfo.assignPrec); 1018 close(prec, TreeInfo.assignPrec); 1019 } catch (IOException e) { 1020 throw new UncheckedIOException(e); 1021 } 1022 } 1023 operatorName(JCTree.Tag tag)1024 public String operatorName(JCTree.Tag tag) { 1025 switch(tag) { 1026 case POS: return "+"; 1027 case NEG: return "-"; 1028 case NOT: return "!"; 1029 case COMPL: return "~"; 1030 case PREINC: return "++"; 1031 case PREDEC: return "--"; 1032 case POSTINC: return "++"; 1033 case POSTDEC: return "--"; 1034 case NULLCHK: return "<*nullchk*>"; 1035 case OR: return "||"; 1036 case AND: return "&&"; 1037 case EQ: return "=="; 1038 case NE: return "!="; 1039 case LT: return "<"; 1040 case GT: return ">"; 1041 case LE: return "<="; 1042 case GE: return ">="; 1043 case BITOR: return "|"; 1044 case BITXOR: return "^"; 1045 case BITAND: return "&"; 1046 case SL: return "<<"; 1047 case SR: return ">>"; 1048 case USR: return ">>>"; 1049 case PLUS: return "+"; 1050 case MINUS: return "-"; 1051 case MUL: return "*"; 1052 case DIV: return "/"; 1053 case MOD: return "%"; 1054 default: throw new Error(); 1055 } 1056 } 1057 visitAssignop(JCAssignOp tree)1058 public void visitAssignop(JCAssignOp tree) { 1059 try { 1060 open(prec, TreeInfo.assignopPrec); 1061 printExpr(tree.lhs, TreeInfo.assignopPrec + 1); 1062 print(" " + operatorName(tree.getTag().noAssignOp()) + "= "); 1063 printExpr(tree.rhs, TreeInfo.assignopPrec); 1064 close(prec, TreeInfo.assignopPrec); 1065 } catch (IOException e) { 1066 throw new UncheckedIOException(e); 1067 } 1068 } 1069 visitUnary(JCUnary tree)1070 public void visitUnary(JCUnary tree) { 1071 try { 1072 int ownprec = TreeInfo.opPrec(tree.getTag()); 1073 String opname = operatorName(tree.getTag()); 1074 open(prec, ownprec); 1075 if (!tree.getTag().isPostUnaryOp()) { 1076 print(opname); 1077 printExpr(tree.arg, ownprec); 1078 } else { 1079 printExpr(tree.arg, ownprec); 1080 print(opname); 1081 } 1082 close(prec, ownprec); 1083 } catch (IOException e) { 1084 throw new UncheckedIOException(e); 1085 } 1086 } 1087 visitBinary(JCBinary tree)1088 public void visitBinary(JCBinary tree) { 1089 try { 1090 int ownprec = TreeInfo.opPrec(tree.getTag()); 1091 String opname = operatorName(tree.getTag()); 1092 open(prec, ownprec); 1093 printExpr(tree.lhs, ownprec); 1094 print(" " + opname + " "); 1095 printExpr(tree.rhs, ownprec + 1); 1096 close(prec, ownprec); 1097 } catch (IOException e) { 1098 throw new UncheckedIOException(e); 1099 } 1100 } 1101 visitTypeCast(JCTypeCast tree)1102 public void visitTypeCast(JCTypeCast tree) { 1103 try { 1104 open(prec, TreeInfo.prefixPrec); 1105 print("("); 1106 printExpr(tree.clazz); 1107 print(")"); 1108 printExpr(tree.expr, TreeInfo.prefixPrec); 1109 close(prec, TreeInfo.prefixPrec); 1110 } catch (IOException e) { 1111 throw new UncheckedIOException(e); 1112 } 1113 } 1114 visitTypeTest(JCInstanceOf tree)1115 public void visitTypeTest(JCInstanceOf tree) { 1116 try { 1117 open(prec, TreeInfo.ordPrec); 1118 printExpr(tree.expr, TreeInfo.ordPrec); 1119 print(" instanceof "); 1120 printExpr(tree.clazz, TreeInfo.ordPrec + 1); 1121 close(prec, TreeInfo.ordPrec); 1122 } catch (IOException e) { 1123 throw new UncheckedIOException(e); 1124 } 1125 } 1126 visitIndexed(JCArrayAccess tree)1127 public void visitIndexed(JCArrayAccess tree) { 1128 try { 1129 printExpr(tree.indexed, TreeInfo.postfixPrec); 1130 print("["); 1131 printExpr(tree.index); 1132 print("]"); 1133 } catch (IOException e) { 1134 throw new UncheckedIOException(e); 1135 } 1136 } 1137 visitSelect(JCFieldAccess tree)1138 public void visitSelect(JCFieldAccess tree) { 1139 try { 1140 printExpr(tree.selected, TreeInfo.postfixPrec); 1141 print("." + tree.name); 1142 } catch (IOException e) { 1143 throw new UncheckedIOException(e); 1144 } 1145 } 1146 visitReference(JCMemberReference tree)1147 public void visitReference(JCMemberReference tree) { 1148 try { 1149 printExpr(tree.expr); 1150 print("::"); 1151 if (tree.typeargs != null) { 1152 print("<"); 1153 printExprs(tree.typeargs); 1154 print(">"); 1155 } 1156 print(tree.getMode() == ReferenceMode.INVOKE ? tree.name : "new"); 1157 } catch (IOException e) { 1158 throw new UncheckedIOException(e); 1159 } 1160 } 1161 visitIdent(JCIdent tree)1162 public void visitIdent(JCIdent tree) { 1163 try { 1164 print(tree.name); 1165 } catch (IOException e) { 1166 throw new UncheckedIOException(e); 1167 } 1168 } 1169 visitLiteral(JCLiteral tree)1170 public void visitLiteral(JCLiteral tree) { 1171 try { 1172 switch (tree.typetag) { 1173 case INT: 1174 print(tree.value.toString()); 1175 break; 1176 case LONG: 1177 print(tree.value + "L"); 1178 break; 1179 case FLOAT: 1180 print(tree.value + "F"); 1181 break; 1182 case DOUBLE: 1183 print(tree.value.toString()); 1184 break; 1185 case CHAR: 1186 print("\'" + 1187 Convert.quote( 1188 String.valueOf((char)((Number)tree.value).intValue())) + 1189 "\'"); 1190 break; 1191 case BOOLEAN: 1192 print(((Number)tree.value).intValue() == 1 ? "true" : "false"); 1193 break; 1194 case BOT: 1195 print("null"); 1196 break; 1197 default: 1198 print("\"" + Convert.quote(tree.value.toString()) + "\""); 1199 break; 1200 } 1201 } catch (IOException e) { 1202 throw new UncheckedIOException(e); 1203 } 1204 } 1205 visitTypeIdent(JCPrimitiveTypeTree tree)1206 public void visitTypeIdent(JCPrimitiveTypeTree tree) { 1207 try { 1208 switch(tree.typetag) { 1209 case BYTE: 1210 print("byte"); 1211 break; 1212 case CHAR: 1213 print("char"); 1214 break; 1215 case SHORT: 1216 print("short"); 1217 break; 1218 case INT: 1219 print("int"); 1220 break; 1221 case LONG: 1222 print("long"); 1223 break; 1224 case FLOAT: 1225 print("float"); 1226 break; 1227 case DOUBLE: 1228 print("double"); 1229 break; 1230 case BOOLEAN: 1231 print("boolean"); 1232 break; 1233 case VOID: 1234 print("void"); 1235 break; 1236 default: 1237 print("error"); 1238 break; 1239 } 1240 } catch (IOException e) { 1241 throw new UncheckedIOException(e); 1242 } 1243 } 1244 visitTypeArray(JCArrayTypeTree tree)1245 public void visitTypeArray(JCArrayTypeTree tree) { 1246 try { 1247 printBaseElementType(tree); 1248 printBrackets(tree); 1249 } catch (IOException e) { 1250 throw new UncheckedIOException(e); 1251 } 1252 } 1253 1254 // Prints the inner element type of a nested array printBaseElementType(JCTree tree)1255 private void printBaseElementType(JCTree tree) throws IOException { 1256 printExpr(TreeInfo.innermostType(tree)); 1257 } 1258 1259 // prints the brackets of a nested array in reverse order 1260 // tree is either JCArrayTypeTree or JCAnnotatedTypeTree printBrackets(JCTree tree)1261 private void printBrackets(JCTree tree) throws IOException { 1262 JCTree elem = tree; 1263 while (true) { 1264 if (elem.hasTag(ANNOTATED_TYPE)) { 1265 JCAnnotatedType atype = (JCAnnotatedType) elem; 1266 elem = atype.underlyingType; 1267 if (elem.hasTag(TYPEARRAY)) { 1268 print(' '); 1269 printTypeAnnotations(atype.annotations); 1270 } 1271 } 1272 if (elem.hasTag(TYPEARRAY)) { 1273 print("[]"); 1274 elem = ((JCArrayTypeTree)elem).elemtype; 1275 } else { 1276 break; 1277 } 1278 } 1279 } 1280 visitTypeApply(JCTypeApply tree)1281 public void visitTypeApply(JCTypeApply tree) { 1282 try { 1283 printExpr(tree.clazz); 1284 print("<"); 1285 printExprs(tree.arguments); 1286 print(">"); 1287 } catch (IOException e) { 1288 throw new UncheckedIOException(e); 1289 } 1290 } 1291 visitTypeUnion(JCTypeUnion tree)1292 public void visitTypeUnion(JCTypeUnion tree) { 1293 try { 1294 printExprs(tree.alternatives, " | "); 1295 } catch (IOException e) { 1296 throw new UncheckedIOException(e); 1297 } 1298 } 1299 visitTypeIntersection(JCTypeIntersection tree)1300 public void visitTypeIntersection(JCTypeIntersection tree) { 1301 try { 1302 printExprs(tree.bounds, " & "); 1303 } catch (IOException e) { 1304 throw new UncheckedIOException(e); 1305 } 1306 } 1307 visitTypeParameter(JCTypeParameter tree)1308 public void visitTypeParameter(JCTypeParameter tree) { 1309 try { 1310 if (tree.annotations.nonEmpty()) { 1311 this.printTypeAnnotations(tree.annotations); 1312 } 1313 print(tree.name); 1314 if (tree.bounds.nonEmpty()) { 1315 print(" extends "); 1316 printExprs(tree.bounds, " & "); 1317 } 1318 } catch (IOException e) { 1319 throw new UncheckedIOException(e); 1320 } 1321 } 1322 1323 @Override visitWildcard(JCWildcard tree)1324 public void visitWildcard(JCWildcard tree) { 1325 try { 1326 print(tree.kind); 1327 if (tree.kind.kind != BoundKind.UNBOUND) 1328 printExpr(tree.inner); 1329 } catch (IOException e) { 1330 throw new UncheckedIOException(e); 1331 } 1332 } 1333 1334 @Override visitTypeBoundKind(TypeBoundKind tree)1335 public void visitTypeBoundKind(TypeBoundKind tree) { 1336 try { 1337 print(String.valueOf(tree.kind)); 1338 } catch (IOException e) { 1339 throw new UncheckedIOException(e); 1340 } 1341 } 1342 visitErroneous(JCErroneous tree)1343 public void visitErroneous(JCErroneous tree) { 1344 try { 1345 print("(ERROR)"); 1346 } catch (IOException e) { 1347 throw new UncheckedIOException(e); 1348 } 1349 } 1350 visitLetExpr(LetExpr tree)1351 public void visitLetExpr(LetExpr tree) { 1352 try { 1353 print("(let " + tree.defs + " in " + tree.expr + ")"); 1354 } catch (IOException e) { 1355 throw new UncheckedIOException(e); 1356 } 1357 } 1358 visitModifiers(JCModifiers mods)1359 public void visitModifiers(JCModifiers mods) { 1360 try { 1361 printAnnotations(mods.annotations); 1362 printFlags(mods.flags); 1363 } catch (IOException e) { 1364 throw new UncheckedIOException(e); 1365 } 1366 } 1367 visitAnnotation(JCAnnotation tree)1368 public void visitAnnotation(JCAnnotation tree) { 1369 try { 1370 print("@"); 1371 printExpr(tree.annotationType); 1372 print("("); 1373 printExprs(tree.args); 1374 print(")"); 1375 } catch (IOException e) { 1376 throw new UncheckedIOException(e); 1377 } 1378 } 1379 visitAnnotatedType(JCAnnotatedType tree)1380 public void visitAnnotatedType(JCAnnotatedType tree) { 1381 try { 1382 if (tree.underlyingType.hasTag(SELECT)) { 1383 JCFieldAccess access = (JCFieldAccess) tree.underlyingType; 1384 printExpr(access.selected, TreeInfo.postfixPrec); 1385 print("."); 1386 printTypeAnnotations(tree.annotations); 1387 print(access.name); 1388 } else if (tree.underlyingType.hasTag(TYPEARRAY)) { 1389 printBaseElementType(tree); 1390 printBrackets(tree); 1391 } else { 1392 printTypeAnnotations(tree.annotations); 1393 printExpr(tree.underlyingType); 1394 } 1395 } catch (IOException e) { 1396 throw new UncheckedIOException(e); 1397 } 1398 } 1399 visitTree(JCTree tree)1400 public void visitTree(JCTree tree) { 1401 try { 1402 print("(UNKNOWN: " + tree + ")"); 1403 println(); 1404 } catch (IOException e) { 1405 throw new UncheckedIOException(e); 1406 } 1407 } 1408 1409 } 1410