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