AbstractMemberWriter.java revision 3827:44bdefe64114
1/* 2 * Copyright (c) 1997, 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 jdk.javadoc.internal.doclets.formats.html; 27 28import java.util.*; 29import java.util.stream.Collectors; 30 31import javax.lang.model.element.Element; 32import javax.lang.model.element.ExecutableElement; 33import javax.lang.model.element.Modifier; 34import javax.lang.model.element.TypeElement; 35import javax.lang.model.element.TypeParameterElement; 36import javax.lang.model.type.TypeMirror; 37 38import com.sun.source.doctree.DocTree; 39 40import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; 41import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants; 42import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; 43import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag; 44import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; 45import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; 46import jdk.javadoc.internal.doclets.toolkit.Content; 47import jdk.javadoc.internal.doclets.toolkit.Resources; 48import jdk.javadoc.internal.doclets.toolkit.taglets.DeprecatedTaglet; 49import jdk.javadoc.internal.doclets.toolkit.util.MethodTypes; 50import jdk.javadoc.internal.doclets.toolkit.util.Utils; 51import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap; 52 53import static javax.lang.model.element.Modifier.*; 54 55/** 56 * The base class for member writers. 57 * 58 * <p><b>This is NOT part of any supported API. 59 * If you write code that depends on this, you do so at your own risk. 60 * This code and its internal interfaces are subject to change or 61 * deletion without notice.</b> 62 * 63 * @author Robert Field 64 * @author Atul M Dambalkar 65 * @author Jamie Ho (Re-write) 66 * @author Bhavesh Patel (Modified) 67 */ 68public abstract class AbstractMemberWriter { 69 70 protected final ConfigurationImpl configuration; 71 protected final Utils utils; 72 protected final SubWriterHolderWriter writer; 73 protected final Contents contents; 74 protected final Resources resources; 75 76 protected final TypeElement typeElement; 77 protected Map<String, Integer> typeMap = new LinkedHashMap<>(); 78 protected Set<MethodTypes> methodTypes = EnumSet.noneOf(MethodTypes.class); 79 private int methodTypesOr = 0; 80 public final boolean nodepr; 81 82 protected boolean printedSummaryHeader = false; 83 84 public AbstractMemberWriter(SubWriterHolderWriter writer, TypeElement typeElement) { 85 this.configuration = writer.configuration; 86 this.writer = writer; 87 this.nodepr = configuration.nodeprecated; 88 this.typeElement = typeElement; 89 this.utils = configuration.utils; 90 this.contents = configuration.contents; 91 this.resources = configuration.resources; 92 } 93 94 public AbstractMemberWriter(SubWriterHolderWriter writer) { 95 this(writer, null); 96 } 97 98 /*** abstracts ***/ 99 100 /** 101 * Add the summary label for the member. 102 * 103 * @param memberTree the content tree to which the label will be added 104 */ 105 public abstract void addSummaryLabel(Content memberTree); 106 107 /** 108 * Get the summary for the member summary table. 109 * 110 * @return a string for the table summary 111 */ 112 public abstract String getTableSummary(); 113 114 /** 115 * Get the caption for the member summary table. 116 * 117 * @return a string for the table caption 118 */ 119 public abstract Content getCaption(); 120 121 /** 122 * Get the summary table header for the member. 123 * 124 * @param member the member to be documented 125 * @return the summary table header 126 */ 127 public abstract List<String> getSummaryTableHeader(Element member); 128 129 /** 130 * Add inherited summary label for the member. 131 * 132 * @param typeElement the TypeElement to which to link to 133 * @param inheritedTree the content tree to which the inherited summary label will be added 134 */ 135 public abstract void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree); 136 137 /** 138 * Add the anchor for the summary section of the member. 139 * 140 * @param typeElement the TypeElement to be documented 141 * @param memberTree the content tree to which the summary anchor will be added 142 */ 143 public abstract void addSummaryAnchor(TypeElement typeElement, Content memberTree); 144 145 /** 146 * Add the anchor for the inherited summary section of the member. 147 * 148 * @param typeElement the TypeElement to be documented 149 * @param inheritedTree the content tree to which the inherited summary anchor will be added 150 */ 151 public abstract void addInheritedSummaryAnchor(TypeElement typeElement, Content inheritedTree); 152 153 /** 154 * Add the summary type for the member. 155 * 156 * @param member the member to be documented 157 * @param tdSummaryType the content tree to which the type will be added 158 */ 159 protected abstract void addSummaryType(Element member, Content tdSummaryType); 160 161 /** 162 * Add the summary link for the member. 163 * 164 * @param typeElement the TypeElement to be documented 165 * @param member the member to be documented 166 * @param tdSummary the content tree to which the link will be added 167 */ 168 protected void addSummaryLink(TypeElement typeElement, Element member, Content tdSummary) { 169 addSummaryLink(LinkInfoImpl.Kind.MEMBER, typeElement, member, tdSummary); 170 } 171 172 /** 173 * Add the summary link for the member. 174 * 175 * @param context the id of the context where the link will be printed 176 * @param typeElement the TypeElement to be documented 177 * @param member the member to be documented 178 * @param tdSummary the content tree to which the summary link will be added 179 */ 180 protected abstract void addSummaryLink(LinkInfoImpl.Kind context, 181 TypeElement typeElement, Element member, Content tdSummary); 182 183 /** 184 * Add the inherited summary link for the member. 185 * 186 * @param typeElement the TypeElement to be documented 187 * @param member the member to be documented 188 * @param linksTree the content tree to which the inherited summary link will be added 189 */ 190 protected abstract void addInheritedSummaryLink(TypeElement typeElement, 191 Element member, Content linksTree); 192 193 /** 194 * Get the deprecated link. 195 * 196 * @param member the member being linked to 197 * @return a content tree representing the link 198 */ 199 protected abstract Content getDeprecatedLink(Element member); 200 201 /** 202 * Get the navigation summary link. 203 * 204 * @param typeElement the TypeElement to be documented 205 * @param link true if its a link else the label to be printed 206 * @return a content tree for the navigation summary link. 207 */ 208 protected abstract Content getNavSummaryLink(TypeElement typeElement, boolean link); 209 210 /** 211 * Add the navigation detail link. 212 * 213 * @param link true if its a link else the label to be printed 214 * @param liNav the content tree to which the navigation detail link will be added 215 */ 216 protected abstract void addNavDetailLink(boolean link, Content liNav); 217 218 /** 219 * Add the member name to the content tree. 220 * 221 * @param name the member name to be added to the content tree. 222 * @param htmltree the content tree to which the name will be added. 223 */ 224 protected void addName(String name, Content htmltree) { 225 htmltree.addContent(name); 226 } 227 228 /** 229 * Add the modifier for the member. The modifiers are ordered as specified 230 * by <em>The Java Language Specification</em>. 231 * 232 * @param member the member for which teh modifier will be added. 233 * @param htmltree the content tree to which the modifier information will be added. 234 */ 235 protected void addModifiers(Element member, Content htmltree) { 236 Set<Modifier> set = new TreeSet<>(member.getModifiers()); 237 238 // remove the ones we really don't need 239 set.remove(NATIVE); 240 set.remove(SYNCHRONIZED); 241 set.remove(STRICTFP); 242 243 // According to JLS, we should not be showing public modifier for 244 // interface methods. 245 if ((utils.isField(member) || utils.isMethod(member)) 246 && ((writer instanceof ClassWriterImpl 247 && utils.isInterface(((ClassWriterImpl) writer).getTypeElement()) || 248 writer instanceof AnnotationTypeWriterImpl) )) { 249 // Remove the implicit abstract and public modifiers 250 if (utils.isMethod(member) && 251 (utils.isInterface(member.getEnclosingElement()) || 252 utils.isAnnotationType(member.getEnclosingElement()))) { 253 set.remove(ABSTRACT); 254 set.remove(PUBLIC); 255 } 256 if (!utils.isMethod(member)) { 257 set.remove(PUBLIC); 258 } 259 } 260 if (!set.isEmpty()) { 261 String mods = set.stream().map(Modifier::toString).collect(Collectors.joining(" ")); 262 htmltree.addContent(mods); 263 htmltree.addContent(Contents.SPACE); 264 } 265 } 266 267 protected CharSequence makeSpace(int len) { 268 if (len <= 0) { 269 return ""; 270 } 271 StringBuilder sb = new StringBuilder(len); 272 for (int i = 0; i < len; i++) { 273 sb.append(' '); 274 } 275 return sb; 276 } 277 278 /** 279 * Add the modifier and type for the member in the member summary. 280 * 281 * @param member the member to add the type for 282 * @param type the type to add 283 * @param tdSummaryType the content tree to which the modified and type will be added 284 */ 285 protected void addModifierAndType(Element member, TypeMirror type, 286 Content tdSummaryType) { 287 HtmlTree code = new HtmlTree(HtmlTag.CODE); 288 addModifier(member, code); 289 if (type == null) { 290 code.addContent(utils.isClass(member) ? "class" : "interface"); 291 code.addContent(Contents.SPACE); 292 } else { 293 List<? extends TypeParameterElement> list = utils.isExecutableElement(member) 294 ? ((ExecutableElement)member).getTypeParameters() 295 : null; 296 if (list != null && !list.isEmpty()) { 297 Content typeParameters = ((AbstractExecutableMemberWriter) this) 298 .getTypeParameters((ExecutableElement)member); 299 code.addContent(typeParameters); 300 //Code to avoid ugly wrapping in member summary table. 301 if (typeParameters.charCount() > 10) { 302 code.addContent(new HtmlTree(HtmlTag.BR)); 303 } else { 304 code.addContent(Contents.SPACE); 305 } 306 code.addContent( 307 writer.getLink(new LinkInfoImpl(configuration, 308 LinkInfoImpl.Kind.SUMMARY_RETURN_TYPE, type))); 309 } else { 310 code.addContent( 311 writer.getLink(new LinkInfoImpl(configuration, 312 LinkInfoImpl.Kind.SUMMARY_RETURN_TYPE, type))); 313 } 314 315 } 316 tdSummaryType.addContent(code); 317 } 318 319 /** 320 * Add the modifier for the member. 321 * 322 * @param member the member to add the type for 323 * @param code the content tree to which the modified will be added 324 */ 325 private void addModifier(Element member, Content code) { 326 if (utils.isProtected(member)) { 327 code.addContent("protected "); 328 } else if (utils.isPrivate(member)) { 329 code.addContent("private "); 330 } else if (!utils.isPublic(member)) { // Package private 331 code.addContent(configuration.getText("doclet.Package_private")); 332 code.addContent(" "); 333 } 334 boolean isAnnotatedTypeElement = utils.isAnnotationType(member.getEnclosingElement()); 335 if (!isAnnotatedTypeElement && utils.isMethod(member)) { 336 if (!utils.isInterface(member.getEnclosingElement()) && utils.isAbstract(member)) { 337 code.addContent("abstract "); 338 } 339 if (utils.isDefault(member)) { 340 code.addContent("default "); 341 } 342 } 343 if (utils.isStatic(member)) { 344 code.addContent("static "); 345 } 346 } 347 348 /** 349 * Add the deprecated information for the given member. 350 * 351 * @param member the member being documented. 352 * @param contentTree the content tree to which the deprecated information will be added. 353 */ 354 protected void addDeprecatedInfo(Element member, Content contentTree) { 355 Content output = (new DeprecatedTaglet()).getTagletOutput(member, 356 writer.getTagletWriterInstance(false)); 357 if (!output.isEmpty()) { 358 Content deprecatedContent = output; 359 Content div = HtmlTree.DIV(HtmlStyle.block, deprecatedContent); 360 contentTree.addContent(div); 361 } 362 } 363 364 /** 365 * Add the comment for the given member. 366 * 367 * @param member the member being documented. 368 * @param htmltree the content tree to which the comment will be added. 369 */ 370 protected void addComment(Element member, Content htmltree) { 371 if (!utils.getFullBody(member).isEmpty()) { 372 writer.addInlineComment(member, htmltree); 373 } 374 } 375 376 protected String name(Element member) { 377 return utils.getSimpleName(member); 378 } 379 380 /** 381 * Get the header for the section. 382 * 383 * @param member the member being documented. 384 * @return a header content for the section. 385 */ 386 protected Content getHead(Element member) { 387 Content memberContent = new StringContent(name(member)); 388 Content heading = HtmlTree.HEADING(HtmlConstants.MEMBER_HEADING, memberContent); 389 return heading; 390 } 391 392 /** 393 * Return true if the given <code>ProgramElement</code> is inherited 394 * by the class that is being documented. 395 * 396 * @param ped The <code>ProgramElement</code> being checked. 397 * return true if the <code>ProgramElement</code> is being inherited and 398 * false otherwise. 399 *@return true if inherited 400 */ 401 protected boolean isInherited(Element ped){ 402 return (!utils.isPrivate(ped) && 403 (!utils.isPackagePrivate(ped) || 404 ped.getEnclosingElement().equals(ped.getEnclosingElement()))); 405 } 406 407 /** 408 * Add use information to the documentation tree. 409 * 410 * @param mems list of program elements for which the use information will be added 411 * @param heading the section heading 412 * @param tableSummary the summary for the use table 413 * @param contentTree the content tree to which the use information will be added 414 */ 415 protected void addUseInfo(List<? extends Element> mems, 416 Content heading, String tableSummary, Content contentTree) { 417 if (mems == null || mems.isEmpty()) { 418 return; 419 } 420 List<? extends Element> members = mems; 421 boolean printedUseTableHeader = false; 422 if (members.size() > 0) { 423 Content caption = writer.getTableCaption(heading); 424 Content table = (configuration.isOutputHtml5()) 425 ? HtmlTree.TABLE(HtmlStyle.useSummary, caption) 426 : HtmlTree.TABLE(HtmlStyle.useSummary, tableSummary, caption); 427 Content tbody = new HtmlTree(HtmlTag.TBODY); 428 boolean altColor = true; 429 for (Element element : members) { 430 TypeElement te = utils.getEnclosingTypeElement(element); 431 if (!printedUseTableHeader) { 432 table.addContent(writer.getSummaryTableHeader( 433 this.getSummaryTableHeader(element), "col")); 434 printedUseTableHeader = true; 435 } 436 HtmlTree tr = new HtmlTree(HtmlTag.TR); 437 tr.addStyle(altColor ? HtmlStyle.altColor : HtmlStyle.rowColor); 438 altColor = !altColor; 439 HtmlTree tdFirst = new HtmlTree(HtmlTag.TD); 440 tdFirst.addStyle(HtmlStyle.colFirst); 441 writer.addSummaryType(this, element, tdFirst); 442 tr.addContent(tdFirst); 443 HtmlTree thType = new HtmlTree(HtmlTag.TH); 444 thType.addStyle(HtmlStyle.colSecond); 445 thType.addAttr(HtmlAttr.SCOPE, "row"); 446 if (te != null 447 && !utils.isConstructor(element) 448 && !utils.isClass(element) 449 && !utils.isInterface(element) 450 && !utils.isAnnotationType(element)) { 451 HtmlTree name = new HtmlTree(HtmlTag.SPAN); 452 name.addStyle(HtmlStyle.typeNameLabel); 453 name.addContent(name(te) + "."); 454 thType.addContent(name); 455 } 456 addSummaryLink(utils.isClass(element) || utils.isInterface(element) 457 ? LinkInfoImpl.Kind.CLASS_USE 458 : LinkInfoImpl.Kind.MEMBER, 459 te, element, thType); 460 tr.addContent(thType); 461 HtmlTree tdDesc = new HtmlTree(HtmlTag.TD); 462 tdDesc.addStyle(HtmlStyle.colLast); 463 writer.addSummaryLinkComment(this, element, tdDesc); 464 tr.addContent(tdDesc); 465 tbody.addContent(tr); 466 } 467 table.addContent(tbody); 468 contentTree.addContent(table); 469 } 470 } 471 472 /** 473 * Add the navigation detail link. 474 * 475 * @param members the members to be linked 476 * @param liNav the content tree to which the navigation detail link will be added 477 */ 478 protected void addNavDetailLink(SortedSet<Element> members, Content liNav) { 479 addNavDetailLink(!members.isEmpty(), liNav); 480 } 481 482 /** 483 * Add the navigation summary link. 484 * 485 * @param members members to be linked 486 * @param visibleMemberMap the visible inherited members map 487 * @param liNav the content tree to which the navigation summary link will be added 488 */ 489 protected void addNavSummaryLink(SortedSet<? extends Element> members, 490 VisibleMemberMap visibleMemberMap, Content liNav) { 491 if (!members.isEmpty()) { 492 liNav.addContent(getNavSummaryLink(null, true)); 493 return; 494 } 495 496 TypeElement superClass = utils.getSuperClass(typeElement); 497 while (superClass != null) { 498 if (visibleMemberMap.hasMembers(superClass)) { 499 liNav.addContent(getNavSummaryLink(superClass, true)); 500 return; 501 } 502 superClass = utils.getSuperClass(superClass); 503 } 504 liNav.addContent(getNavSummaryLink(null, false)); 505 } 506 507 protected void serialWarning(Element e, String key, String a1, String a2) { 508 if (configuration.serialwarn) { 509 configuration.messages.warning(e, key, a1, a2); 510 } 511 } 512 513 /** 514 * Add the member summary for the given class. 515 * 516 * @param tElement the class that is being documented 517 * @param member the member being documented 518 * @param firstSentenceTags the first sentence tags to be added to the summary 519 * @param tableContents the list of contents to which the documentation will be added 520 * @param counter the counter for determining id and style for the table row 521 */ 522 public void addMemberSummary(TypeElement tElement, Element member, 523 List<? extends DocTree> firstSentenceTags, List<Content> tableContents, int counter) { 524 HtmlTree tdSummaryType = new HtmlTree(HtmlTag.TD); 525 tdSummaryType.addStyle(HtmlStyle.colFirst); 526 writer.addSummaryType(this, member, tdSummaryType); 527 HtmlTree tr = HtmlTree.TR(tdSummaryType); 528 HtmlTree thSummaryLink = new HtmlTree(HtmlTag.TH); 529 setSummaryColumnStyleAndScope(thSummaryLink); 530 addSummaryLink(tElement, member, thSummaryLink); 531 tr.addContent(thSummaryLink); 532 HtmlTree tdDesc = new HtmlTree(HtmlTag.TD); 533 tdDesc.addStyle(HtmlStyle.colLast); 534 writer.addSummaryLinkComment(this, member, firstSentenceTags, tdDesc); 535 tr.addContent(tdDesc); 536 if (utils.isMethod(member) && !utils.isAnnotationType(member)) { 537 int methodType = utils.isStatic(member) ? MethodTypes.STATIC.value() : 538 MethodTypes.INSTANCE.value(); 539 if (utils.isInterface(member.getEnclosingElement())) { 540 methodType = utils.isAbstract(member) 541 ? methodType | MethodTypes.ABSTRACT.value() 542 : methodType | MethodTypes.DEFAULT.value(); 543 } else { 544 methodType = utils.isAbstract(member) 545 ? methodType | MethodTypes.ABSTRACT.value() 546 : methodType | MethodTypes.CONCRETE.value(); 547 } 548 if (utils.isDeprecated(member) || utils.isDeprecated(typeElement)) { 549 methodType = methodType | MethodTypes.DEPRECATED.value(); 550 } 551 methodTypesOr = methodTypesOr | methodType; 552 String tableId = "i" + counter; 553 typeMap.put(tableId, methodType); 554 tr.addAttr(HtmlAttr.ID, tableId); 555 } 556 if (counter%2 == 0) 557 tr.addStyle(HtmlStyle.altColor); 558 else 559 tr.addStyle(HtmlStyle.rowColor); 560 tableContents.add(tr); 561 } 562 563 /** 564 * Generate the method types set and return true if the method summary table 565 * needs to show tabs. 566 * 567 * @return true if the table should show tabs 568 */ 569 public boolean showTabs() { 570 int value; 571 for (MethodTypes type : EnumSet.allOf(MethodTypes.class)) { 572 value = type.value(); 573 if ((value & methodTypesOr) == value) { 574 methodTypes.add(type); 575 } 576 } 577 boolean showTabs = methodTypes.size() > 1; 578 if (showTabs) { 579 methodTypes.add(MethodTypes.ALL); 580 } 581 return showTabs; 582 } 583 584 /** 585 * Set the style and scope attribute for the summary column. 586 * 587 * @param thTree the column for which the style and scope attribute will be set 588 */ 589 public void setSummaryColumnStyleAndScope(HtmlTree thTree) { 590 thTree.addStyle(HtmlStyle.colSecond); 591 thTree.addAttr(HtmlAttr.SCOPE, "row"); 592 } 593 594 /** 595 * Add inherited member summary for the given class and member. 596 * 597 * @param tElement the class the inherited member belongs to 598 * @param nestedClass the inherited member that is summarized 599 * @param isFirst true if this is the first member in the list 600 * @param isLast true if this is the last member in the list 601 * @param linksTree the content tree to which the summary will be added 602 */ 603 public void addInheritedMemberSummary(TypeElement tElement, 604 Element nestedClass, boolean isFirst, boolean isLast, 605 Content linksTree) { 606 writer.addInheritedMemberSummary(this, tElement, nestedClass, isFirst, 607 linksTree); 608 } 609 610 /** 611 * Get the inherited summary header for the given class. 612 * 613 * @param tElement the class the inherited member belongs to 614 * @return a content tree for the inherited summary header 615 */ 616 public Content getInheritedSummaryHeader(TypeElement tElement) { 617 Content inheritedTree = writer.getMemberTreeHeader(); 618 writer.addInheritedSummaryHeader(this, tElement, inheritedTree); 619 return inheritedTree; 620 } 621 622 /** 623 * Get the inherited summary links tree. 624 * 625 * @return a content tree for the inherited summary links 626 */ 627 public Content getInheritedSummaryLinksTree() { 628 return new HtmlTree(HtmlTag.CODE); 629 } 630 631 /** 632 * Get the summary table tree for the given class. 633 * 634 * @param tElement the class for which the summary table is generated 635 * @param tableContents list of contents to be displayed in the summary table 636 * @return a content tree for the summary table 637 */ 638 public Content getSummaryTableTree(TypeElement tElement, List<Content> tableContents) { 639 return writer.getSummaryTableTree(this, tElement, tableContents, showTabs()); 640 } 641 642 /** 643 * Get the member tree to be documented. 644 * 645 * @param memberTree the content tree of member to be documented 646 * @return a content tree that will be added to the class documentation 647 */ 648 public Content getMemberTree(Content memberTree) { 649 return writer.getMemberTree(memberTree); 650 } 651 652 /** 653 * Get the member tree to be documented. 654 * 655 * @param memberTree the content tree of member to be documented 656 * @param isLastContent true if the content to be added is the last content 657 * @return a content tree that will be added to the class documentation 658 */ 659 public Content getMemberTree(Content memberTree, boolean isLastContent) { 660 if (isLastContent) 661 return HtmlTree.UL(HtmlStyle.blockListLast, memberTree); 662 else 663 return HtmlTree.UL(HtmlStyle.blockList, memberTree); 664 } 665} 666