DocPretty.java revision 3831:209b0eab0e1f
1/* 2 * Copyright (c) 1999, 2016, 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 26package com.sun.tools.javac.tree; 27 28import java.io.IOException; 29import java.io.Writer; 30import java.util.List; 31 32import com.sun.source.doctree.*; 33import com.sun.source.doctree.AttributeTree.ValueKind; 34import com.sun.tools.javac.util.Convert; 35import com.sun.tools.javac.util.DefinedBy; 36import com.sun.tools.javac.util.DefinedBy.Api; 37 38/** 39 * Prints out a doc comment tree. 40 * 41 * <p><b>This is NOT part of any supported API. 42 * If you write code that depends on this, you do so at your own risk. 43 * This code and its internal interfaces are subject to change or 44 * deletion without notice.</b> 45 */ 46public class DocPretty implements DocTreeVisitor<Void,Void> { 47 48 /** 49 * The output stream on which trees are printed. 50 */ 51 final Writer out; 52 53 /** 54 * The left margin. 55 */ 56 int lmargin = 0; 57 58 public DocPretty(Writer out) { 59 this.out = out; 60 } 61 62 /** Visitor method: print expression tree. 63 */ 64 public void print(DocTree tree) throws IOException { 65 try { 66 if (tree == null) 67 print("/*missing*/"); 68 else { 69 tree.accept(this, null); 70 } 71 } catch (UncheckedIOException ex) { 72 throw new IOException(ex.getMessage(), ex); 73 } 74 } 75 76 /** 77 * Print string, replacing all non-ascii character with unicode escapes. 78 */ 79 protected void print(Object s) throws IOException { 80 out.write(Convert.escapeUnicode(s.toString())); 81 } 82 83 /** 84 * Print list. 85 */ 86 public void print(List<? extends DocTree> list) throws IOException { 87 for (DocTree t: list) { 88 print(t); 89 } 90 } 91 92 /** 93 * Print list., with separators 94 */ 95 protected void print(List<? extends DocTree> list, String sep) throws IOException { 96 if (list.isEmpty()) 97 return; 98 boolean first = true; 99 for (DocTree t: list) { 100 if (!first) 101 print(sep); 102 print(t); 103 first = false; 104 } 105 } 106 107 /** Print new line. 108 */ 109 protected void println() throws IOException { 110 out.write(lineSep); 111 } 112 113 protected void printTagName(DocTree node) throws IOException { 114 out.write("@"); 115 out.write(node.getKind().tagName); 116 } 117 118 final String lineSep = System.getProperty("line.separator"); 119 120 /************************************************************************** 121 * Traversal methods 122 *************************************************************************/ 123 124 /** Exception to propagate IOException through visitXXX methods */ 125 private static class UncheckedIOException extends Error { 126 static final long serialVersionUID = -4032692679158424751L; 127 UncheckedIOException(IOException e) { 128 super(e.getMessage(), e); 129 } 130 } 131 132 @Override @DefinedBy(Api.COMPILER_TREE) 133 public Void visitAttribute(AttributeTree node, Void p) { 134 try { 135 print(node.getName()); 136 String quote; 137 switch (node.getValueKind()) { 138 case EMPTY: 139 quote = null; 140 break; 141 case UNQUOTED: 142 quote = ""; 143 break; 144 case SINGLE: 145 quote = "'"; 146 break; 147 case DOUBLE: 148 quote = "\""; 149 break; 150 default: 151 throw new AssertionError(); 152 } 153 if (quote != null) { 154 print("=" + quote); 155 print(node.getValue()); 156 print(quote); 157 } 158 } catch (IOException e) { 159 throw new UncheckedIOException(e); 160 } 161 return null; 162 } 163 164 @Override @DefinedBy(Api.COMPILER_TREE) 165 public Void visitAuthor(AuthorTree node, Void p) { 166 try { 167 printTagName(node); 168 print(" "); 169 print(node.getName()); 170 } catch (IOException e) { 171 throw new UncheckedIOException(e); 172 } 173 return null; 174 } 175 176 @Override @DefinedBy(Api.COMPILER_TREE) 177 public Void visitComment(CommentTree node, Void p) { 178 try { 179 print(node.getBody()); 180 } catch (IOException e) { 181 throw new UncheckedIOException(e); 182 } 183 return null; 184 } 185 186 @Override @DefinedBy(Api.COMPILER_TREE) 187 public Void visitDeprecated(DeprecatedTree node, Void p) { 188 try { 189 printTagName(node); 190 if (!node.getBody().isEmpty()) { 191 print(" "); 192 print(node.getBody()); 193 } 194 } catch (IOException e) { 195 throw new UncheckedIOException(e); 196 } 197 return null; 198 } 199 200 @Override @DefinedBy(Api.COMPILER_TREE) 201 public Void visitDocComment(DocCommentTree node, Void p) { 202 try { 203 List<? extends DocTree> b = node.getFullBody(); 204 List<? extends DocTree> t = node.getBlockTags(); 205 print(b); 206 if (!b.isEmpty() && !t.isEmpty()) 207 print("\n"); 208 print(t, "\n"); 209 } catch (IOException e) { 210 throw new UncheckedIOException(e); 211 } 212 return null; 213 } 214 215 @Override @DefinedBy(Api.COMPILER_TREE) 216 public Void visitDocRoot(DocRootTree node, Void p) { 217 try { 218 print("{"); 219 printTagName(node); 220 print("}"); 221 } catch (IOException e) { 222 throw new UncheckedIOException(e); 223 } 224 return null; 225 } 226 227 @Override @DefinedBy(Api.COMPILER_TREE) 228 public Void visitEndElement(EndElementTree node, Void p) { 229 try { 230 print("</"); 231 print(node.getName()); 232 print(">"); 233 } catch (IOException e) { 234 throw new UncheckedIOException(e); 235 } 236 return null; 237 } 238 239 @Override @DefinedBy(Api.COMPILER_TREE) 240 public Void visitEntity(EntityTree node, Void p) { 241 try { 242 print("&"); 243 print(node.getName()); 244 print(";"); 245 } catch (IOException e) { 246 throw new UncheckedIOException(e); 247 } 248 return null; 249 } 250 251 @Override @DefinedBy(Api.COMPILER_TREE) 252 public Void visitErroneous(ErroneousTree node, Void p) { 253 try { 254 print(node.getBody()); 255 } catch (IOException e) { 256 throw new UncheckedIOException(e); 257 } 258 return null; 259 } 260 261 @Override @DefinedBy(Api.COMPILER_TREE) 262 public Void visitHidden(HiddenTree node, Void p) { 263 try { 264 printTagName(node); 265 if (!node.getBody().isEmpty()) { 266 print(" "); 267 print(node.getBody()); 268 } 269 } catch (IOException e) { 270 throw new UncheckedIOException(e); 271 } 272 return null; 273 } 274 275 @Override @DefinedBy(Api.COMPILER_TREE) 276 public Void visitIdentifier(IdentifierTree node, Void p) { 277 try { 278 print(node.getName()); 279 } catch (IOException e) { 280 throw new UncheckedIOException(e); 281 } 282 return null; 283 } 284 285 @Override @DefinedBy(Api.COMPILER_TREE) 286 public Void visitIndex(IndexTree node, Void p) { 287 try { 288 print("{"); 289 printTagName(node); 290 print(" "); 291 print(node.getSearchTerm()); 292 if (!node.getDescription().isEmpty()) { 293 print(" "); 294 print(node.getDescription()); 295 } 296 print("}"); 297 } catch (IOException e) { 298 throw new UncheckedIOException(e); 299 } 300 return null; 301 } 302 303 @Override @DefinedBy(Api.COMPILER_TREE) 304 public Void visitInheritDoc(InheritDocTree node, Void p) { 305 try { 306 print("{"); 307 printTagName(node); 308 print("}"); 309 } catch (IOException e) { 310 throw new UncheckedIOException(e); 311 } 312 return null; 313 } 314 315 @Override @DefinedBy(Api.COMPILER_TREE) 316 public Void visitLink(LinkTree node, Void p) { 317 try { 318 print("{"); 319 printTagName(node); 320 print(" "); 321 print(node.getReference()); 322 if (!node.getLabel().isEmpty()) { 323 print(" "); 324 print(node.getLabel()); 325 } 326 print("}"); 327 } catch (IOException e) { 328 throw new UncheckedIOException(e); 329 } 330 return null; 331 } 332 333 @Override @DefinedBy(Api.COMPILER_TREE) 334 public Void visitLiteral(LiteralTree node, Void p) { 335 try { 336 print("{"); 337 printTagName(node); 338 String body = node.getBody().getBody(); 339 if (!body.isEmpty() && !Character.isWhitespace(body.charAt(0))) { 340 print(" "); 341 } 342 print(node.getBody()); 343 print("}"); 344 } catch (IOException e) { 345 throw new UncheckedIOException(e); 346 } 347 return null; 348 } 349 350 @Override @DefinedBy(Api.COMPILER_TREE) 351 public Void visitParam(ParamTree node, Void p) { 352 try { 353 printTagName(node); 354 print(" "); 355 if (node.isTypeParameter()) print("<"); 356 print(node.getName()); 357 if (node.isTypeParameter()) print(">"); 358 if (!node.getDescription().isEmpty()) { 359 print(" "); 360 print(node.getDescription()); 361 } 362 } catch (IOException e) { 363 throw new UncheckedIOException(e); 364 } 365 return null; 366 } 367 368 @Override @DefinedBy(Api.COMPILER_TREE) 369 public Void visitProvides(ProvidesTree node, Void p) { 370 try { 371 printTagName(node); 372 print(" "); 373 print(node.getServiceType()); 374 if (!node.getDescription().isEmpty()) { 375 print(" "); 376 print(node.getDescription()); 377 } 378 } catch (IOException e) { 379 throw new UncheckedIOException(e); 380 } 381 return null; 382 } 383 384 @Override @DefinedBy(Api.COMPILER_TREE) 385 public Void visitReference(ReferenceTree node, Void p) { 386 try { 387 print(node.getSignature()); 388 } catch (IOException e) { 389 throw new UncheckedIOException(e); 390 } 391 return null; 392 } 393 394 @Override @DefinedBy(Api.COMPILER_TREE) 395 public Void visitReturn(ReturnTree node, Void p) { 396 try { 397 printTagName(node); 398 print(" "); 399 print(node.getDescription()); 400 } catch (IOException e) { 401 throw new UncheckedIOException(e); 402 } 403 return null; 404 } 405 406 @Override @DefinedBy(Api.COMPILER_TREE) 407 public Void visitSee(SeeTree node, Void p) { 408 try { 409 printTagName(node); 410 boolean first = true; 411 boolean needSep = true; 412 for (DocTree t: node.getReference()) { 413 if (needSep) print(" "); 414 needSep = (first && (t instanceof ReferenceTree)); 415 first = false; 416 print(t); 417 } 418 } catch (IOException e) { 419 throw new UncheckedIOException(e); 420 } 421 return null; 422 } 423 424 @Override @DefinedBy(Api.COMPILER_TREE) 425 public Void visitSerial(SerialTree node, Void p) { 426 try { 427 printTagName(node); 428 if (!node.getDescription().isEmpty()) { 429 print(" "); 430 print(node.getDescription()); 431 } 432 } catch (IOException e) { 433 throw new UncheckedIOException(e); 434 } 435 return null; 436 } 437 438 @Override @DefinedBy(Api.COMPILER_TREE) 439 public Void visitSerialData(SerialDataTree node, Void p) { 440 try { 441 printTagName(node); 442 if (!node.getDescription().isEmpty()) { 443 print(" "); 444 print(node.getDescription()); 445 } 446 } catch (IOException e) { 447 throw new UncheckedIOException(e); 448 } 449 return null; 450 } 451 452 @Override @DefinedBy(Api.COMPILER_TREE) 453 public Void visitSerialField(SerialFieldTree node, Void p) { 454 try { 455 printTagName(node); 456 print(" "); 457 print(node.getName()); 458 print(" "); 459 print(node.getType()); 460 if (!node.getDescription().isEmpty()) { 461 print(" "); 462 print(node.getDescription()); 463 } 464 } catch (IOException e) { 465 throw new UncheckedIOException(e); 466 } 467 return null; 468 } 469 470 @Override @DefinedBy(Api.COMPILER_TREE) 471 public Void visitSince(SinceTree node, Void p) { 472 try { 473 printTagName(node); 474 print(" "); 475 print(node.getBody()); 476 } catch (IOException e) { 477 throw new UncheckedIOException(e); 478 } 479 return null; 480 } 481 482 @Override @DefinedBy(Api.COMPILER_TREE) 483 public Void visitStartElement(StartElementTree node, Void p) { 484 try { 485 print("<"); 486 print(node.getName()); 487 List<? extends DocTree> attrs = node.getAttributes(); 488 if (!attrs.isEmpty()) { 489 print(" "); 490 print(attrs); 491 DocTree last = node.getAttributes().get(attrs.size() - 1); 492 if (node.isSelfClosing() && last instanceof AttributeTree 493 && ((AttributeTree) last).getValueKind() == ValueKind.UNQUOTED) 494 print(" "); 495 } 496 if (node.isSelfClosing()) 497 print("/"); 498 print(">"); 499 } catch (IOException e) { 500 throw new UncheckedIOException(e); 501 } 502 return null; 503 } 504 505 @Override @DefinedBy(Api.COMPILER_TREE) 506 public Void visitText(TextTree node, Void p) { 507 try { 508 print(node.getBody()); 509 } catch (IOException e) { 510 throw new UncheckedIOException(e); 511 } 512 return null; 513 } 514 515 @Override @DefinedBy(Api.COMPILER_TREE) 516 public Void visitThrows(ThrowsTree node, Void p) { 517 try { 518 printTagName(node); 519 print(" "); 520 print(node.getExceptionName()); 521 if (!node.getDescription().isEmpty()) { 522 print(" "); 523 print(node.getDescription()); 524 } 525 } catch (IOException e) { 526 throw new UncheckedIOException(e); 527 } 528 return null; 529 } 530 531 @Override @DefinedBy(Api.COMPILER_TREE) 532 public Void visitUnknownBlockTag(UnknownBlockTagTree node, Void p) { 533 try { 534 print("@"); 535 print(node.getTagName()); 536 print(" "); 537 print(node.getContent()); 538 } catch (IOException e) { 539 throw new UncheckedIOException(e); 540 } 541 return null; 542 } 543 544 @Override @DefinedBy(Api.COMPILER_TREE) 545 public Void visitUnknownInlineTag(UnknownInlineTagTree node, Void p) { 546 try { 547 print("{"); 548 print("@"); 549 print(node.getTagName()); 550 print(" "); 551 print(node.getContent()); 552 print("}"); 553 } catch (IOException e) { 554 throw new UncheckedIOException(e); 555 } 556 return null; 557 } 558 559 @Override @DefinedBy(Api.COMPILER_TREE) 560 public Void visitUses(UsesTree node, Void p) { 561 try { 562 printTagName(node); 563 print(" "); 564 print(node.getServiceType()); 565 if (!node.getDescription().isEmpty()) { 566 print(" "); 567 print(node.getDescription()); 568 } 569 } catch (IOException e) { 570 throw new UncheckedIOException(e); 571 } 572 return null; 573 } 574 575 @Override @DefinedBy(Api.COMPILER_TREE) 576 public Void visitValue(ValueTree node, Void p) { 577 try { 578 print("{"); 579 printTagName(node); 580 if (node.getReference() != null) { 581 print(" "); 582 print(node.getReference()); 583 } 584 print("}"); 585 } catch (IOException e) { 586 throw new UncheckedIOException(e); 587 } 588 return null; 589 } 590 591 @Override @DefinedBy(Api.COMPILER_TREE) 592 public Void visitVersion(VersionTree node, Void p) { 593 try { 594 printTagName(node); 595 print(" "); 596 print(node.getBody()); 597 } catch (IOException e) { 598 throw new UncheckedIOException(e); 599 } 600 return null; 601 } 602 603 @Override @DefinedBy(Api.COMPILER_TREE) 604 public Void visitOther(DocTree node, Void p) { 605 try { 606 print("(UNKNOWN: " + node + ")"); 607 println(); 608 } catch (IOException e) { 609 throw new UncheckedIOException(e); 610 } 611 return null; 612 } 613} 614