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 printStat(tree.body); 695 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 696 printStat(l.head); 697 } 698 if (tree.finalizer != null) { 699 print(" finally "); 700 printStat(tree.finalizer); 701 } 702 } catch (IOException e) { 703 throw new UncheckedIOException(e); 704 } 705 } 706 707 public void visitCatch(JCCatch tree) { 708 try { 709 print(" catch ("); 710 printExpr(tree.param); 711 print(") "); 712 printStat(tree.body); 713 } catch (IOException e) { 714 throw new UncheckedIOException(e); 715 } 716 } 717 718 public void visitConditional(JCConditional tree) { 719 try { 720 open(prec, TreeInfo.condPrec); 721 printExpr(tree.cond, TreeInfo.condPrec); 722 print(" ? "); 723 printExpr(tree.truepart, TreeInfo.condPrec); 724 print(" : "); 725 printExpr(tree.falsepart, TreeInfo.condPrec); 726 close(prec, TreeInfo.condPrec); 727 } catch (IOException e) { 728 throw new UncheckedIOException(e); 729 } 730 } 731 732 public void visitIf(JCIf tree) { 733 try { 734 print("if "); 735 if (tree.cond.getTag() == JCTree.PARENS) { 736 printExpr(tree.cond); 737 } else { 738 print("("); 739 printExpr(tree.cond); 740 print(")"); 741 } 742 print(" "); 743 printStat(tree.thenpart); 744 if (tree.elsepart != null) { 745 print(" else "); 746 printStat(tree.elsepart); 747 } 748 } catch (IOException e) { 749 throw new UncheckedIOException(e); 750 } 751 } 752 753 public void visitExec(JCExpressionStatement tree) { 754 try { 755 printExpr(tree.expr); 756 if (prec == TreeInfo.notExpression) print(";"); 757 } catch (IOException e) { 758 throw new UncheckedIOException(e); 759 } 760 } 761 762 public void visitBreak(JCBreak tree) { 763 try { 764 print("break"); 765 if (tree.label != null) print(" " + tree.label); 766 print(";"); 767 } catch (IOException e) { 768 throw new UncheckedIOException(e); 769 } 770 } 771 772 public void visitContinue(JCContinue tree) { 773 try { 774 print("continue"); 775 if (tree.label != null) print(" " + tree.label); 776 print(";"); 777 } catch (IOException e) { 778 throw new UncheckedIOException(e); 779 } 780 } 781 782 public void visitReturn(JCReturn tree) { 783 try { 784 print("return"); 785 if (tree.expr != null) { 786 print(" "); 787 printExpr(tree.expr); 788 } 789 print(";"); 790 } catch (IOException e) { 791 throw new UncheckedIOException(e); 792 } 793 } 794 795 public void visitThrow(JCThrow tree) { 796 try { 797 print("throw "); 798 printExpr(tree.expr); 799 print(";"); 800 } catch (IOException e) { 801 throw new UncheckedIOException(e); 802 } 803 } 804 805 public void visitAssert(JCAssert tree) { 806 try { 807 print("assert "); 808 printExpr(tree.cond); 809 if (tree.detail != null) { 810 print(" : "); 811 printExpr(tree.detail); 812 } 813 print(";"); 814 } catch (IOException e) { 815 throw new UncheckedIOException(e); 816 } 817 } 818 819 public void visitApply(JCMethodInvocation tree) { 820 try { 821 if (!tree.typeargs.isEmpty()) { 822 if (tree.meth.getTag() == JCTree.SELECT) { 823 JCFieldAccess left = (JCFieldAccess)tree.meth; 824 printExpr(left.selected); 825 print(".<"); 826 printExprs(tree.typeargs); 827 print(">" + left.name); 828 } else { 829 print("<"); 830 printExprs(tree.typeargs); 831 print(">"); 832 printExpr(tree.meth); 833 } 834 } else { 835 printExpr(tree.meth); 836 } 837 print("("); 838 printExprs(tree.args); 839 print(")"); 840 } catch (IOException e) { 841 throw new UncheckedIOException(e); 842 } 843 } 844 845 public void visitNewClass(JCNewClass tree) { 846 try { 847 if (tree.encl != null) { 848 printExpr(tree.encl); 849 print("."); 850 } 851 print("new "); 852 if (!tree.typeargs.isEmpty()) { 853 print("<"); 854 printExprs(tree.typeargs); 855 print(">"); 856 } 857 printExpr(tree.clazz); 858 print("("); 859 printExprs(tree.args); 860 print(")"); 861 if (tree.def != null) { 862 Name enclClassNamePrev = enclClassName; 863 enclClassName = 864 tree.def.name != null ? tree.def.name : 865 tree.type != null && tree.type.tsym.name != tree.type.tsym.name.table.names.empty 866 ? tree.type.tsym.name : null; 867 if ((tree.def.mods.flags & Flags.ENUM) != 0) print("/*enum*/"); 868 printBlock(tree.def.defs); 869 enclClassName = enclClassNamePrev; 870 } 871 } catch (IOException e) { 872 throw new UncheckedIOException(e); 873 } 874 } 875 876 public void visitNewArray(JCNewArray tree) { 877 try { 878 if (tree.elemtype != null) { 879 print("new "); 880 printTypeAnnotations(tree.annotations); 881 JCTree elem = tree.elemtype; 882 printBaseElementType(elem); 883 boolean isElemAnnoType = elem instanceof JCAnnotatedType; 884 int i = 0; 885 List<List<JCTypeAnnotation>> da = tree.dimAnnotations; 886 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) { 887 if (da.size() > i) { 888 printTypeAnnotations(da.get(i)); 889 } 890 print("["); 891 i++; 892 printExpr(l.head); 893 print("]"); 894 } 895 if (tree.elems != null) { 896 if (isElemAnnoType) { 897 printTypeAnnotations(((JCAnnotatedType)tree.elemtype).annotations); 898 } 899 print("[]"); 900 } 901 if (isElemAnnoType) 902 elem = ((JCAnnotatedType)elem).underlyingType; 903 if (elem instanceof JCArrayTypeTree) 904 printBrackets((JCArrayTypeTree) elem); 905 } 906 if (tree.elems != null) { 907 print("{"); 908 printExprs(tree.elems); 909 print("}"); 910 } 911 } catch (IOException e) { 912 throw new UncheckedIOException(e); 913 } 914 } 915 916 public void visitParens(JCParens tree) { 917 try { 918 print("("); 919 printExpr(tree.expr); 920 print(")"); 921 } catch (IOException e) { 922 throw new UncheckedIOException(e); 923 } 924 } 925 926 public void visitAssign(JCAssign tree) { 927 try { 928 open(prec, TreeInfo.assignPrec); 929 printExpr(tree.lhs, TreeInfo.assignPrec + 1); 930 print(" = "); 931 printExpr(tree.rhs, TreeInfo.assignPrec); 932 close(prec, TreeInfo.assignPrec); 933 } catch (IOException e) { 934 throw new UncheckedIOException(e); 935 } 936 } 937 938 public String operatorName(int tag) { 939 switch(tag) { 940 case JCTree.POS: return "+"; 941 case JCTree.NEG: return "-"; 942 case JCTree.NOT: return "!"; 943 case JCTree.COMPL: return "~"; 944 case JCTree.PREINC: return "++"; 945 case JCTree.PREDEC: return "--"; 946 case JCTree.POSTINC: return "++"; 947 case JCTree.POSTDEC: return "--"; 948 case JCTree.NULLCHK: return "<*nullchk*>"; 949 case JCTree.OR: return "||"; 950 case JCTree.AND: return "&&"; 951 case JCTree.EQ: return "=="; 952 case JCTree.NE: return "!="; 953 case JCTree.LT: return "<"; 954 case JCTree.GT: return ">"; 955 case JCTree.LE: return "<="; 956 case JCTree.GE: return ">="; 957 case JCTree.BITOR: return "|"; 958 case JCTree.BITXOR: return "^"; 959 case JCTree.BITAND: return "&"; 960 case JCTree.SL: return "<<"; 961 case JCTree.SR: return ">>"; 962 case JCTree.USR: return ">>>"; 963 case JCTree.PLUS: return "+"; 964 case JCTree.MINUS: return "-"; 965 case JCTree.MUL: return "*"; 966 case JCTree.DIV: return "/"; 967 case JCTree.MOD: return "%"; 968 default: throw new Error(); 969 } 970 } 971 972 public void visitAssignop(JCAssignOp tree) { 973 try { 974 open(prec, TreeInfo.assignopPrec); 975 printExpr(tree.lhs, TreeInfo.assignopPrec + 1); 976 print(" " + operatorName(tree.getTag() - JCTree.ASGOffset) + "= "); 977 printExpr(tree.rhs, TreeInfo.assignopPrec); 978 close(prec, TreeInfo.assignopPrec); 979 } catch (IOException e) { 980 throw new UncheckedIOException(e); 981 } 982 } 983 984 public void visitUnary(JCUnary tree) { 985 try { 986 int ownprec = TreeInfo.opPrec(tree.getTag()); 987 String opname = operatorName(tree.getTag()); 988 open(prec, ownprec); 989 if (tree.getTag() <= JCTree.PREDEC) { 990 print(opname); 991 printExpr(tree.arg, ownprec); 992 } else { 993 printExpr(tree.arg, ownprec); 994 print(opname); 995 } 996 close(prec, ownprec); 997 } catch (IOException e) { 998 throw new UncheckedIOException(e); 999 } 1000 } 1001 1002 public void visitBinary(JCBinary tree) { 1003 try { 1004 int ownprec = TreeInfo.opPrec(tree.getTag()); 1005 String opname = operatorName(tree.getTag()); 1006 open(prec, ownprec); 1007 printExpr(tree.lhs, ownprec); 1008 print(" " + opname + " "); 1009 printExpr(tree.rhs, ownprec + 1); 1010 close(prec, ownprec); 1011 } catch (IOException e) { 1012 throw new UncheckedIOException(e); 1013 } 1014 } 1015 1016 public void visitTypeCast(JCTypeCast tree) { 1017 try { 1018 open(prec, TreeInfo.prefixPrec); 1019 print("("); 1020 printExpr(tree.clazz); 1021 print(")"); 1022 printExpr(tree.expr, TreeInfo.prefixPrec); 1023 close(prec, TreeInfo.prefixPrec); 1024 } catch (IOException e) { 1025 throw new UncheckedIOException(e); 1026 } 1027 } 1028 1029 public void visitTypeTest(JCInstanceOf tree) { 1030 try { 1031 open(prec, TreeInfo.ordPrec); 1032 printExpr(tree.expr, TreeInfo.ordPrec); 1033 print(" instanceof "); 1034 printExpr(tree.clazz, TreeInfo.ordPrec + 1); 1035 close(prec, TreeInfo.ordPrec); 1036 } catch (IOException e) { 1037 throw new UncheckedIOException(e); 1038 } 1039 } 1040 1041 public void visitIndexed(JCArrayAccess tree) { 1042 try { 1043 printExpr(tree.indexed, TreeInfo.postfixPrec); 1044 print("["); 1045 printExpr(tree.index); 1046 print("]"); 1047 } catch (IOException e) { 1048 throw new UncheckedIOException(e); 1049 } 1050 } 1051 1052 public void visitSelect(JCFieldAccess tree) { 1053 try { 1054 printExpr(tree.selected, TreeInfo.postfixPrec); 1055 print("." + tree.name); 1056 } catch (IOException e) { 1057 throw new UncheckedIOException(e); 1058 } 1059 } 1060 1061 public void visitIdent(JCIdent tree) { 1062 try { 1063 print(tree.name); 1064 } catch (IOException e) { 1065 throw new UncheckedIOException(e); 1066 } 1067 } 1068 1069 public void visitLiteral(JCLiteral tree) { 1070 try { 1071 switch (tree.typetag) { 1072 case TypeTags.INT: 1073 print(tree.value.toString()); 1074 break; 1075 case TypeTags.LONG: 1076 print(tree.value + "L"); 1077 break; 1078 case TypeTags.FLOAT: 1079 print(tree.value + "F"); 1080 break; 1081 case TypeTags.DOUBLE: 1082 print(tree.value.toString()); 1083 break; 1084 case TypeTags.CHAR: 1085 print("\'" + 1086 Convert.quote( 1087 String.valueOf((char)((Number)tree.value).intValue())) + 1088 "\'"); 1089 break; 1090 case TypeTags.BOOLEAN: 1091 print(((Number)tree.value).intValue() == 1 ? "true" : "false"); 1092 break; 1093 case TypeTags.BOT: 1094 print("null"); 1095 break; 1096 default: 1097 print("\"" + Convert.quote(tree.value.toString()) + "\""); 1098 break; 1099 } 1100 } catch (IOException e) { 1101 throw new UncheckedIOException(e); 1102 } 1103 } 1104 1105 public void visitTypeIdent(JCPrimitiveTypeTree tree) { 1106 try { 1107 switch(tree.typetag) { 1108 case TypeTags.BYTE: 1109 print("byte"); 1110 break; 1111 case TypeTags.CHAR: 1112 print("char"); 1113 break; 1114 case TypeTags.SHORT: 1115 print("short"); 1116 break; 1117 case TypeTags.INT: 1118 print("int"); 1119 break; 1120 case TypeTags.LONG: 1121 print("long"); 1122 break; 1123 case TypeTags.FLOAT: 1124 print("float"); 1125 break; 1126 case TypeTags.DOUBLE: 1127 print("double"); 1128 break; 1129 case TypeTags.BOOLEAN: 1130 print("boolean"); 1131 break; 1132 case TypeTags.VOID: 1133 print("void"); 1134 break; 1135 default: 1136 print("error"); 1137 break; 1138 } 1139 } catch (IOException e) { 1140 throw new UncheckedIOException(e); 1141 } 1142 } 1143 1144 public void visitTypeArray(JCArrayTypeTree tree) { 1145 try { 1146 printBaseElementType(tree); 1147 printBrackets(tree); 1148 } catch (IOException e) { 1149 throw new UncheckedIOException(e); 1150 } 1151 } 1152 1153 // Prints the inner element type of a nested array 1154 private void printBaseElementType(JCTree tree) throws IOException { 1155 printExpr(TreeInfo.innermostType(tree)); 1156 } 1157 1158 // prints the brackets of a nested array in reverse order 1159 private void printBrackets(JCArrayTypeTree tree) throws IOException { 1160 JCTree elem; 1161 while (true) { 1162 elem = tree.elemtype; 1163 if (elem.getTag() == JCTree.ANNOTATED_TYPE) { 1164 JCAnnotatedType atype = (JCAnnotatedType) elem; 1165 printTypeAnnotations(atype.annotations); 1166 elem = atype.underlyingType; 1167 } 1168 print("[]"); 1169 if (elem.getTag() != JCTree.TYPEARRAY) break; 1170 tree = (JCArrayTypeTree) elem; 1171 } 1172 } 1173 1174 public void visitTypeApply(JCTypeApply tree) { 1175 try { 1176 printExpr(tree.clazz); 1177 print("<"); 1178 printExprs(tree.arguments); 1179 print(">"); 1180 } catch (IOException e) { 1181 throw new UncheckedIOException(e); 1182 } 1183 } 1184 1185 public void visitTypeDisjoint(JCTypeDisjoint tree) { 1186 try { 1187 printExprs(tree.components, " | "); 1188 } catch (IOException e) { 1189 throw new UncheckedIOException(e); 1190 } 1191 } 1192 1193 public void visitTypeParameter(JCTypeParameter tree) { 1194 try { 1195 print(tree.name); 1196 if (tree.bounds.nonEmpty()) { 1197 print(" extends "); 1198 printExprs(tree.bounds, " & "); 1199 } 1200 } catch (IOException e) { 1201 throw new UncheckedIOException(e); 1202 } 1203 } 1204 1205 @Override 1206 public void visitWildcard(JCWildcard tree) { 1207 try { 1208 print(tree.kind); 1209 if (tree.kind.kind != BoundKind.UNBOUND) 1210 printExpr(tree.inner); 1211 } catch (IOException e) { 1212 throw new UncheckedIOException(e); 1213 } 1214 } 1215 1216 @Override 1217 public void visitTypeBoundKind(TypeBoundKind tree) { 1218 try { 1219 print(String.valueOf(tree.kind)); 1220 } catch (IOException e) { 1221 throw new UncheckedIOException(e); 1222 } 1223 } 1224 1225 public void visitErroneous(JCErroneous tree) { 1226 try { 1227 print("(ERROR)"); 1228 } catch (IOException e) { 1229 throw new UncheckedIOException(e); 1230 } 1231 } 1232 1233 public void visitLetExpr(LetExpr tree) { 1234 try { 1235 print("(let " + tree.defs + " in " + tree.expr + ")"); 1236 } catch (IOException e) { 1237 throw new UncheckedIOException(e); 1238 } 1239 } 1240 1241 public void visitModifiers(JCModifiers mods) { 1242 try { 1243 printAnnotations(mods.annotations); 1244 printFlags(mods.flags); 1245 } catch (IOException e) { 1246 throw new UncheckedIOException(e); 1247 } 1248 } 1249 1250 public void visitAnnotation(JCAnnotation tree) { 1251 try { 1252 print("@"); 1253 printExpr(tree.annotationType); 1254 print("("); 1255 printExprs(tree.args); 1256 print(")"); 1257 } catch (IOException e) { 1258 throw new UncheckedIOException(e); 1259 } 1260 } 1261 1262 public void visitAnnotatedType(JCAnnotatedType tree) { 1263 try { 1264 printTypeAnnotations(tree.annotations); 1265 printExpr(tree.underlyingType); 1266 } catch (IOException e) { 1267 throw new UncheckedIOException(e); 1268 } 1269 } 1270 1271 public void visitTree(JCTree tree) { 1272 try { 1273 print("(UNKNOWN: " + tree + ")"); 1274 println(); 1275 } catch (IOException e) { 1276 throw new UncheckedIOException(e); 1277 } 1278 } 1279 1280 }