1 /* 2 * Copyright (c) 1997, 2019, 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 jdk.javadoc.internal.doclets.formats.html; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 import java.util.Set; 31 import java.util.TreeSet; 32 import java.util.stream.Collectors; 33 34 import javax.lang.model.element.Element; 35 import javax.lang.model.element.ExecutableElement; 36 import javax.lang.model.element.Modifier; 37 import javax.lang.model.element.TypeElement; 38 import javax.lang.model.element.TypeParameterElement; 39 import javax.lang.model.type.TypeMirror; 40 41 import com.sun.source.doctree.DocTree; 42 43 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; 44 import jdk.javadoc.internal.doclets.formats.html.markup.Entity; 45 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; 46 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; 47 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; 48 import jdk.javadoc.internal.doclets.formats.html.markup.Links; 49 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; 50 import jdk.javadoc.internal.doclets.formats.html.markup.Table; 51 import jdk.javadoc.internal.doclets.formats.html.markup.TableHeader; 52 import jdk.javadoc.internal.doclets.toolkit.Content; 53 import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; 54 import jdk.javadoc.internal.doclets.toolkit.Resources; 55 import jdk.javadoc.internal.doclets.toolkit.taglets.DeprecatedTaglet; 56 import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants; 57 import jdk.javadoc.internal.doclets.toolkit.util.Utils; 58 59 import static javax.lang.model.element.Modifier.ABSTRACT; 60 import static javax.lang.model.element.Modifier.NATIVE; 61 import static javax.lang.model.element.Modifier.PUBLIC; 62 import static javax.lang.model.element.Modifier.STRICTFP; 63 import static javax.lang.model.element.Modifier.SYNCHRONIZED; 64 65 /** 66 * The base class for member writers. 67 * 68 * <p><b>This is NOT part of any supported API. 69 * If you write code that depends on this, you do so at your own risk. 70 * This code and its internal interfaces are subject to change or 71 * deletion without notice.</b> 72 */ 73 public abstract class AbstractMemberWriter implements MemberSummaryWriter { 74 75 protected final HtmlConfiguration configuration; 76 protected final HtmlOptions options; 77 protected final Utils utils; 78 protected final SubWriterHolderWriter writer; 79 protected final Contents contents; 80 protected final Resources resources; 81 protected final Links links; 82 83 protected final TypeElement typeElement; 84 public final boolean nodepr; 85 86 protected boolean printedSummaryHeader = false; 87 88 public AbstractMemberWriter(SubWriterHolderWriter writer, TypeElement typeElement) { 89 this.configuration = writer.configuration; 90 this.options = configuration.getOptions(); 91 this.writer = writer; 92 this.nodepr = options.noDeprecated; 93 this.typeElement = typeElement; 94 this.utils = configuration.utils; 95 this.contents = configuration.contents; 96 this.resources = configuration.resources; 97 this.links = writer.links; 98 } 99 100 public AbstractMemberWriter(SubWriterHolderWriter writer) { 101 this(writer, null); 102 } 103 104 /*** abstracts ***/ 105 106 /** 107 * Add the summary label for the member. 108 * 109 * @param memberTree the content tree to which the label will be added 110 */ 111 public abstract void addSummaryLabel(Content memberTree); 112 113 /** 114 * Get the summary for the member summary table. 115 * 116 * @return a string for the table summary 117 */ 118 private String getTableSummaryX() { return null; } 119 120 /** 121 * Get the summary table header for the member. 122 * 123 * @param member the member to be documented 124 * @return the summary table header 125 */ 126 public abstract TableHeader getSummaryTableHeader(Element member); 127 128 private Table summaryTable; 129 130 private Table getSummaryTable() { 131 if (summaryTable == null) { 132 summaryTable = createSummaryTable(); 133 } 134 return summaryTable; 135 } 136 137 /** 138 * Create the summary table for this element. 139 * The table should be created and initialized if needed, and configured 140 * so that it is ready to add content with {@link Table#addRow(Content[])} 141 * and similar methods. 142 * 143 * @return the summary table 144 */ 145 protected abstract Table createSummaryTable(); 146 147 148 149 /** 150 * Add inherited summary label for the member. 151 * 152 * @param typeElement the TypeElement to which to link to 153 * @param inheritedTree the content tree to which the inherited summary label will be added 154 */ 155 public abstract void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree); 156 157 /** 158 * Add the summary type for the member. 159 * 160 * @param member the member to be documented 161 * @param tdSummaryType the content tree to which the type will be added 162 */ 163 protected abstract void addSummaryType(Element member, Content tdSummaryType); 164 165 /** 166 * Add the summary link for the member. 167 * 168 * @param typeElement the TypeElement to be documented 169 * @param member the member to be documented 170 * @param tdSummary the content tree to which the link will be added 171 */ 172 protected void addSummaryLink(TypeElement typeElement, Element member, Content tdSummary) { 173 addSummaryLink(LinkInfoImpl.Kind.MEMBER, typeElement, member, tdSummary); 174 } 175 176 /** 177 * Add the summary link for the member. 178 * 179 * @param context the id of the context where the link will be printed 180 * @param typeElement the TypeElement to be documented 181 * @param member the member to be documented 182 * @param tdSummary the content tree to which the summary link will be added 183 */ 184 protected abstract void addSummaryLink(LinkInfoImpl.Kind context, 185 TypeElement typeElement, Element member, Content tdSummary); 186 187 /** 188 * Add the inherited summary link for the member. 189 * 190 * @param typeElement the TypeElement to be documented 191 * @param member the member to be documented 192 * @param linksTree the content tree to which the inherited summary link will be added 193 */ 194 protected abstract void addInheritedSummaryLink(TypeElement typeElement, 195 Element member, Content linksTree); 196 197 /** 198 * Get the deprecated link. 199 * 200 * @param member the member being linked to 201 * @return a content tree representing the link 202 */ 203 protected abstract Content getDeprecatedLink(Element member); 204 205 protected CharSequence makeSpace(int len) { 206 if (len <= 0) { 207 return ""; 208 } 209 StringBuilder sb = new StringBuilder(len); 210 for (int i = 0; i < len; i++) { 211 sb.append(' '); 212 } 213 return sb; 214 } 215 216 /** 217 * Add the modifier and type for the member in the member summary. 218 * 219 * @param member the member to add the type for 220 * @param type the type to add 221 * @param tdSummaryType the content tree to which the modified and type will be added 222 */ 223 protected void addModifierAndType(Element member, TypeMirror type, 224 Content tdSummaryType) { 225 HtmlTree code = new HtmlTree(HtmlTag.CODE); 226 addModifier(member, code); 227 if (type == null) { 228 code.add(utils.isClass(member) ? "class" : "interface"); 229 code.add(Entity.NO_BREAK_SPACE); 230 } else { 231 List<? extends TypeParameterElement> list = utils.isExecutableElement(member) 232 ? ((ExecutableElement)member).getTypeParameters() 233 : null; 234 if (list != null && !list.isEmpty()) { 235 Content typeParameters = ((AbstractExecutableMemberWriter) this) 236 .getTypeParameters((ExecutableElement)member); 237 code.add(typeParameters); 238 //Code to avoid ugly wrapping in member summary table. 239 if (typeParameters.charCount() > 10) { 240 code.add(new HtmlTree(HtmlTag.BR)); 241 } else { 242 code.add(Entity.NO_BREAK_SPACE); 243 } 244 code.add( 245 writer.getLink(new LinkInfoImpl(configuration, 246 LinkInfoImpl.Kind.SUMMARY_RETURN_TYPE, type))); 247 } else { 248 code.add( 249 writer.getLink(new LinkInfoImpl(configuration, 250 LinkInfoImpl.Kind.SUMMARY_RETURN_TYPE, type))); 251 } 252 253 } 254 tdSummaryType.add(code); 255 } 256 257 /** 258 * Add the modifier for the member. 259 * 260 * @param member the member to add the type for 261 * @param code the content tree to which the modified will be added 262 */ 263 private void addModifier(Element member, Content code) { 264 if (utils.isProtected(member)) { 265 code.add("protected "); 266 } else if (utils.isPrivate(member)) { 267 code.add("private "); 268 } else if (!utils.isPublic(member)) { // Package private 269 code.add(resources.getText("doclet.Package_private")); 270 code.add(" "); 271 } 272 boolean isAnnotatedTypeElement = utils.isAnnotationType(member.getEnclosingElement()); 273 if (!isAnnotatedTypeElement && utils.isMethod(member)) { 274 if (!utils.isInterface(member.getEnclosingElement()) && utils.isAbstract(member)) { 275 code.add("abstract "); 276 } 277 if (utils.isDefault(member)) { 278 code.add("default "); 279 } 280 } 281 if (utils.isStatic(member)) { 282 code.add("static "); 283 } 284 } 285 286 /** 287 * Add the deprecated information for the given member. 288 * 289 * @param member the member being documented. 290 * @param contentTree the content tree to which the deprecated information will be added. 291 */ 292 protected void addDeprecatedInfo(Element member, Content contentTree) { 293 Content output = (new DeprecatedTaglet()).getTagletOutput(member, 294 writer.getTagletWriterInstance(false)); 295 if (!output.isEmpty()) { 296 Content deprecatedContent = output; 297 Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprecatedContent); 298 contentTree.add(div); 299 } 300 } 301 302 /** 303 * Add the comment for the given member. 304 * 305 * @param member the member being documented. 306 * @param htmltree the content tree to which the comment will be added. 307 */ 308 protected void addComment(Element member, Content htmltree) { 309 if (!utils.getFullBody(member).isEmpty()) { 310 writer.addInlineComment(member, htmltree); 311 } 312 } 313 314 protected String name(Element member) { 315 return utils.getSimpleName(member); 316 } 317 318 /** 319 * Return true if the given <code>ProgramElement</code> is inherited 320 * by the class that is being documented. 321 * 322 * @param ped The <code>ProgramElement</code> being checked. 323 * return true if the <code>ProgramElement</code> is being inherited and 324 * false otherwise. 325 *@return true if inherited 326 */ 327 protected boolean isInherited(Element ped){ 328 return (!utils.isPrivate(ped) && 329 (!utils.isPackagePrivate(ped) || 330 ped.getEnclosingElement().equals(ped.getEnclosingElement()))); 331 } 332 333 /** 334 * Add use information to the documentation tree. 335 * 336 * @param mems list of program elements for which the use information will be added 337 * @param heading the section heading 338 * @param contentTree the content tree to which the use information will be added 339 */ 340 protected void addUseInfo(List<? extends Element> mems, Content heading, Content contentTree) { 341 if (mems == null || mems.isEmpty()) { 342 return; 343 } 344 List<? extends Element> members = mems; 345 boolean printedUseTableHeader = false; 346 if (members.size() > 0) { 347 Table useTable = new Table(HtmlStyle.useSummary) 348 .setCaption(heading) 349 .setRowScopeColumn(1) 350 .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colSecond, HtmlStyle.colLast); 351 for (Element element : members) { 352 TypeElement te = (typeElement == null) 353 ? utils.getEnclosingTypeElement(element) 354 : typeElement; 355 if (!printedUseTableHeader) { 356 useTable.setHeader(getSummaryTableHeader(element)); 357 printedUseTableHeader = true; 358 } 359 Content summaryType = new ContentBuilder(); 360 addSummaryType(element, summaryType); 361 Content typeContent = new ContentBuilder(); 362 if (te != null 363 && !utils.isConstructor(element) 364 && !utils.isClass(element) 365 && !utils.isInterface(element) 366 && !utils.isAnnotationType(element)) { 367 HtmlTree name = new HtmlTree(HtmlTag.SPAN); 368 name.setStyle(HtmlStyle.typeNameLabel); 369 name.add(name(te) + "."); 370 typeContent.add(name); 371 } 372 addSummaryLink(utils.isClass(element) || utils.isInterface(element) 373 ? LinkInfoImpl.Kind.CLASS_USE 374 : LinkInfoImpl.Kind.MEMBER, 375 te, element, typeContent); 376 Content desc = new ContentBuilder(); 377 writer.addSummaryLinkComment(this, element, desc); 378 useTable.addRow(summaryType, typeContent, desc); 379 } 380 contentTree.add(useTable.toContent()); 381 } 382 } 383 384 protected void serialWarning(Element e, String key, String a1, String a2) { 385 if (configuration.getOptions().serialWarn) { 386 configuration.messages.warning(e, key, a1, a2); 387 } 388 } 389 390 /** 391 * Add the member summary for the given class. 392 * 393 * @param tElement the class that is being documented 394 * @param member the member being documented 395 * @param firstSentenceTags the first sentence tags to be added to the summary 396 */ 397 @Override 398 public void addMemberSummary(TypeElement tElement, Element member, 399 List<? extends DocTree> firstSentenceTags) { 400 if (tElement != typeElement) { 401 throw new IllegalStateException(); 402 } 403 Table table = getSummaryTable(); 404 List<Content> rowContents = new ArrayList<>(); 405 Content summaryType = new ContentBuilder(); 406 addSummaryType(member, summaryType); 407 if (!summaryType.isEmpty()) 408 rowContents.add(summaryType); 409 Content summaryLink = new ContentBuilder(); 410 addSummaryLink(tElement, member, summaryLink); 411 rowContents.add(summaryLink); 412 Content desc = new ContentBuilder(); 413 writer.addSummaryLinkComment(this, member, firstSentenceTags, desc); 414 rowContents.add(desc); 415 table.addRow(member, rowContents); 416 } 417 418 /** 419 * Add inherited member summary for the given class and member. 420 * 421 * @param tElement the class the inherited member belongs to 422 * @param nestedClass the inherited member that is summarized 423 * @param isFirst true if this is the first member in the list 424 * @param isLast true if this is the last member in the list 425 * @param linksTree the content tree to which the summary will be added 426 */ 427 @Override 428 public void addInheritedMemberSummary(TypeElement tElement, 429 Element nestedClass, boolean isFirst, boolean isLast, 430 Content linksTree) { 431 writer.addInheritedMemberSummary(this, tElement, nestedClass, isFirst, 432 linksTree); 433 } 434 435 /** 436 * Get the inherited summary header for the given class. 437 * 438 * @param tElement the class the inherited member belongs to 439 * @return a content tree for the inherited summary header 440 */ 441 @Override 442 public Content getInheritedSummaryHeader(TypeElement tElement) { 443 Content inheritedTree = writer.getMemberInheritedTree(); 444 writer.addInheritedSummaryHeader(this, tElement, inheritedTree); 445 return inheritedTree; 446 } 447 448 /** 449 * Get the inherited summary links tree. 450 * 451 * @return a content tree for the inherited summary links 452 */ 453 @Override 454 public Content getInheritedSummaryLinksTree() { 455 return new HtmlTree(HtmlTag.CODE); 456 } 457 458 /** 459 * Get the summary table tree for the given class. 460 * 461 * @param tElement the class for which the summary table is generated 462 * @return a content tree for the summary table 463 */ 464 @Override 465 public Content getSummaryTableTree(TypeElement tElement) { 466 if (tElement != typeElement) { 467 throw new IllegalStateException(); 468 } 469 Table table = getSummaryTable(); 470 if (table.needsScript()) { 471 writer.getMainBodyScript().append(table.getScript()); 472 } 473 return table.toContent(); 474 } 475 476 /** 477 * Get the member tree to be documented. 478 * 479 * @param memberTree the content tree of member to be documented 480 * @return a content tree that will be added to the class documentation 481 */ 482 @Override 483 public Content getMemberTree(Content memberTree) { 484 return writer.getMemberTree(memberTree); 485 } 486 487 /** 488 * A content builder for member signatures. 489 */ 490 class MemberSignature { 491 492 private Element element; 493 private Content typeParameters; 494 private Content returnType; 495 private Content parameters; 496 private Content exceptions; 497 498 // Threshold for length of type parameters before switching from inline to block representation. 499 private static final int TYPE_PARAMS_MAX_INLINE_LENGTH = 50; 500 501 // Threshold for combined length of modifiers, type params and return type before breaking 502 // it up with a line break before the return type. 503 private static final int RETURN_TYPE_MAX_LINE_LENGTH = 50; 504 505 /** 506 * Create a new member signature builder. 507 * 508 * @param element The element for which to create a signature. 509 */ 510 MemberSignature(Element element) { 511 this.element = element; 512 } 513 514 /** 515 * Add the type parameters for an executable member. 516 * 517 * @param typeParameters the content tree containing the type parameters to add. 518 * @return this MemberSignature instance 519 */ 520 MemberSignature addTypeParameters(Content typeParameters) { 521 this.typeParameters = typeParameters; 522 return this; 523 } 524 525 /** 526 * Add the return type for an executable member. 527 * 528 * @param returnType the content tree containing the return type to add. 529 * @return this MemberSignature instance 530 */ 531 MemberSignature addReturnType(Content returnType) { 532 this.returnType = returnType; 533 return this; 534 } 535 536 /** 537 * Add the type information for a non-executable member. 538 * 539 * @param type the type of the member. 540 * @return this MemberSignature instance 541 */ 542 MemberSignature addType(TypeMirror type) { 543 this.returnType = writer.getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.MEMBER, type)); 544 return this; 545 } 546 547 /** 548 * Add the parameter information of an executable member. 549 * 550 * @param paramTree the content tree containing the parameter information. 551 * @return this MemberSignature instance 552 */ 553 MemberSignature addParameters(Content paramTree) { 554 this.parameters = paramTree; 555 return this; 556 } 557 558 /** 559 * Add the exception information of an executable member. 560 * 561 * @param exceptionTree the content tree containing the exception information 562 * @return this MemberSignature instance 563 */ 564 MemberSignature addExceptions(Content exceptionTree) { 565 this.exceptions = exceptionTree; 566 return this; 567 } 568 569 /** 570 * Return a HTML tree containing the member signature. 571 * 572 * @return a HTML tree containing the member signature 573 */ 574 Content toContent() { 575 Content content = new ContentBuilder(); 576 // Position of last line separator. 577 int lastLineSeparator = 0; 578 579 // Annotations 580 Content annotationInfo = writer.getAnnotationInfo(element.getAnnotationMirrors(), true); 581 if (!annotationInfo.isEmpty()) { 582 content.add(HtmlTree.SPAN(HtmlStyle.annotations, annotationInfo)); 583 lastLineSeparator = content.charCount(); 584 } 585 586 // Modifiers 587 appendModifiers(content); 588 589 // Type parameters 590 if (typeParameters != null && !typeParameters.isEmpty()) { 591 lastLineSeparator = appendTypeParameters(content, lastLineSeparator); 592 } 593 594 // Return type 595 if (returnType != null) { 596 content.add(HtmlTree.SPAN(HtmlStyle.returnType, returnType)); 597 content.add(Entity.NO_BREAK_SPACE); 598 } 599 600 // Name 601 HtmlTree nameSpan = new HtmlTree(HtmlTag.SPAN); 602 nameSpan.setStyle(HtmlStyle.memberName); 603 if (configuration.getOptions().linkSource) { 604 Content name = new StringContent(name(element)); 605 writer.addSrcLink(element, name, nameSpan); 606 } else { 607 nameSpan.add(name(element)); 608 } 609 content.add(nameSpan); 610 611 612 // Parameters and exceptions 613 if (parameters != null) { 614 appendParametersAndExceptions(content, lastLineSeparator); 615 } 616 617 return HtmlTree.DIV(HtmlStyle.memberSignature, content); 618 } 619 620 /** 621 * Add the modifier for the member. The modifiers are ordered as specified 622 * by <em>The Java Language Specification</em>. 623 * 624 * @param htmltree the content tree to which the modifier information will be added. 625 */ 626 private void appendModifiers(Content htmltree) { 627 Set<Modifier> set = new TreeSet<>(element.getModifiers()); 628 629 // remove the ones we really don't need 630 set.remove(NATIVE); 631 set.remove(SYNCHRONIZED); 632 set.remove(STRICTFP); 633 634 // According to JLS, we should not be showing public modifier for 635 // interface methods. 636 if ((utils.isField(element) || utils.isMethod(element)) 637 && ((writer instanceof ClassWriterImpl 638 && utils.isInterface(((ClassWriterImpl) writer).getTypeElement()) || 639 writer instanceof AnnotationTypeWriterImpl) )) { 640 // Remove the implicit abstract and public modifiers 641 if (utils.isMethod(element) && 642 (utils.isInterface(element.getEnclosingElement()) || 643 utils.isAnnotationType(element.getEnclosingElement()))) { 644 set.remove(ABSTRACT); 645 set.remove(PUBLIC); 646 } 647 if (!utils.isMethod(element)) { 648 set.remove(PUBLIC); 649 } 650 } 651 if (!set.isEmpty()) { 652 String mods = set.stream().map(Modifier::toString).collect(Collectors.joining(" ")); 653 htmltree.add(HtmlTree.SPAN(HtmlStyle.modifiers, new StringContent(mods))); 654 htmltree.add(Entity.NO_BREAK_SPACE); 655 } 656 } 657 658 /** 659 * Append the type parameter information to the HTML tree. 660 * 661 * @param htmltree the HTML tree 662 * @param lastLineSeparator index of last line separator in HTML tree 663 * @return the new index of the last line separator 664 */ 665 private int appendTypeParameters(Content htmltree, int lastLineSeparator) { 666 // Apply different wrapping strategies for type parameters 667 // depending of combined length of type parameters and return type. 668 int typeParamLength = typeParameters.charCount(); 669 670 if (typeParamLength >= TYPE_PARAMS_MAX_INLINE_LENGTH) { 671 htmltree.add(HtmlTree.SPAN(HtmlStyle.typeParametersLong, typeParameters)); 672 } else { 673 htmltree.add(HtmlTree.SPAN(HtmlStyle.typeParameters, typeParameters)); 674 } 675 676 int lineLength = htmltree.charCount() - lastLineSeparator; 677 int newLastLineSeparator = lastLineSeparator; 678 679 // sum below includes length of modifiers plus type params added above 680 if (lineLength + returnType.charCount()> RETURN_TYPE_MAX_LINE_LENGTH) { 681 htmltree.add(DocletConstants.NL); 682 newLastLineSeparator = htmltree.charCount(); 683 } else { 684 htmltree.add(Entity.NO_BREAK_SPACE); 685 } 686 687 return newLastLineSeparator; 688 } 689 690 /** 691 * Append the parameters and exceptions information to the HTML tree. 692 * 693 * @param htmltree the HTML tree 694 * @param lastLineSeparator the index of the last line separator in HTML tree 695 */ 696 private void appendParametersAndExceptions(Content htmltree, int lastLineSeparator) { 697 // Record current position for indentation of exceptions 698 int indentSize = htmltree.charCount() - lastLineSeparator; 699 700 if (parameters.isEmpty()) { 701 htmltree.add("()"); 702 } else { 703 parameters.add(")"); 704 htmltree.add(Entity.ZERO_WIDTH_SPACE); 705 htmltree.add("("); 706 htmltree.add(HtmlTree.SPAN(HtmlStyle.arguments, parameters)); 707 } 708 709 // Exceptions 710 if (exceptions != null && !exceptions.isEmpty()) { 711 CharSequence indent = makeSpace(indentSize + 1 - 7); 712 htmltree.add(DocletConstants.NL); 713 htmltree.add(indent); 714 htmltree.add("throws "); 715 htmltree.add(HtmlTree.SPAN(HtmlStyle.exceptions, exceptions)); 716 } 717 } 718 } 719 }