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