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.Table; 50 import jdk.javadoc.internal.doclets.formats.html.markup.TableHeader; 51 import jdk.javadoc.internal.doclets.toolkit.Content; 52 import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; 53 import jdk.javadoc.internal.doclets.toolkit.Resources; 54 import jdk.javadoc.internal.doclets.toolkit.taglets.DeprecatedTaglet; 55 import jdk.javadoc.internal.doclets.toolkit.util.Utils; 56 57 import static javax.lang.model.element.Modifier.ABSTRACT; 58 import static javax.lang.model.element.Modifier.NATIVE; 59 import static javax.lang.model.element.Modifier.PUBLIC; 60 import static javax.lang.model.element.Modifier.STRICTFP; 61 import static javax.lang.model.element.Modifier.SYNCHRONIZED; 62 63 /** 64 * The base class for member writers. 65 * 66 * <p><b>This is NOT part of any supported API. 67 * If you write code that depends on this, you do so at your own risk. 68 * This code and its internal interfaces are subject to change or 69 * deletion without notice.</b> 70 * 71 * @author Robert Field 72 * @author Atul M Dambalkar 73 * @author Jamie Ho (Re-write) 74 * @author Bhavesh Patel (Modified) 75 */ 76 public abstract class AbstractMemberWriter implements MemberSummaryWriter { 77 78 protected final HtmlConfiguration configuration; 79 protected final Utils utils; 80 protected final SubWriterHolderWriter writer; 81 protected final Contents contents; 82 protected final Resources resources; 83 protected final Links links; 84 85 protected final TypeElement typeElement; 86 public final boolean nodepr; 87 88 protected boolean printedSummaryHeader = false; 89 90 public AbstractMemberWriter(SubWriterHolderWriter writer, TypeElement typeElement) { 91 this.configuration = writer.configuration; 92 this.writer = writer; 93 this.nodepr = configuration.nodeprecated; 94 this.typeElement = typeElement; 95 this.utils = configuration.utils; 96 this.contents = configuration.contents; 97 this.resources = configuration.resources; 98 this.links = writer.links; 99 } 100 101 public AbstractMemberWriter(SubWriterHolderWriter writer) { 102 this(writer, null); 103 } 104 105 /*** abstracts ***/ 106 107 /** 108 * Add the summary label for the member. 109 * 110 * @param memberTree the content tree to which the label will be added 111 */ 112 public abstract void addSummaryLabel(Content memberTree); 113 114 /** 115 * Get the summary for the member summary table. 116 * 117 * @return a string for the table summary 118 */ 119 private String getTableSummaryX() { return null; } 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 TableHeader getSummaryTableHeader(Element member); 128 129 private Table summaryTable; 130 131 private Table getSummaryTable() { 132 if (summaryTable == null) { 133 summaryTable = createSummaryTable(); 134 } 135 return summaryTable; 136 } 137 138 /** 139 * Create the summary table for this element. 140 * The table should be created and initialized if needed, and configured 141 * so that it is ready to add content with {@link Table#addRow(Content[])} 142 * and similar methods. 143 * 144 * @return the summary table 145 */ 146 protected abstract Table createSummaryTable(); 147 148 149 150 /** 151 * Add inherited summary label for the member. 152 * 153 * @param typeElement the TypeElement to which to link to 154 * @param inheritedTree the content tree to which the inherited summary label will be added 155 */ 156 public abstract void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree); 157 158 /** 159 * Add the anchor for the summary section of the member. 160 * 161 * @param typeElement the TypeElement to be documented 162 * @param memberTree the content tree to which the summary anchor will be added 163 */ 164 public abstract void addSummaryAnchor(TypeElement typeElement, Content memberTree); 165 166 /** 167 * Add the anchor for the inherited summary section of the member. 168 * 169 * @param typeElement the TypeElement to be documented 170 * @param inheritedTree the content tree to which the inherited summary anchor will be added 171 */ 172 public abstract void addInheritedSummaryAnchor(TypeElement typeElement, Content inheritedTree); 173 174 /** 175 * Add the summary type for the member. 176 * 177 * @param member the member to be documented 178 * @param tdSummaryType the content tree to which the type will be added 179 */ 180 protected abstract void addSummaryType(Element member, Content tdSummaryType); 181 182 /** 183 * Add the summary link for the member. 184 * 185 * @param typeElement the TypeElement to be documented 186 * @param member the member to be documented 187 * @param tdSummary the content tree to which the link will be added 188 */ 189 protected void addSummaryLink(TypeElement typeElement, Element member, Content tdSummary) { 190 addSummaryLink(LinkInfoImpl.Kind.MEMBER, typeElement, member, tdSummary); 191 } 192 193 /** 194 * Add the summary link for the member. 195 * 196 * @param context the id of the context where the link will be printed 197 * @param typeElement the TypeElement to be documented 198 * @param member the member to be documented 199 * @param tdSummary the content tree to which the summary link will be added 200 */ 201 protected abstract void addSummaryLink(LinkInfoImpl.Kind context, 202 TypeElement typeElement, Element member, Content tdSummary); 203 204 /** 205 * Add the inherited summary link for the member. 206 * 207 * @param typeElement the TypeElement to be documented 208 * @param member the member to be documented 209 * @param linksTree the content tree to which the inherited summary link will be added 210 */ 211 protected abstract void addInheritedSummaryLink(TypeElement typeElement, 212 Element member, Content linksTree); 213 214 /** 215 * Get the deprecated link. 216 * 217 * @param member the member being linked to 218 * @return a content tree representing the link 219 */ 220 protected abstract Content getDeprecatedLink(Element member); 221 222 /** 223 * Add the member name to the content tree. 224 * 225 * @param name the member name to be added to the content tree. 226 * @param htmltree the content tree to which the name will be added. 227 */ 228 protected void addName(String name, Content htmltree) { 229 htmltree.add(name); 230 } 231 232 /** 233 * Add the modifier for the member. The modifiers are ordered as specified 234 * by <em>The Java Language Specification</em>. 235 * 236 * @param member the member for which the modifier will be added. 237 * @param htmltree the content tree to which the modifier information will be added. 238 */ 239 protected void addModifiers(Element member, Content htmltree) { 240 Set<Modifier> set = new TreeSet<>(member.getModifiers()); 241 242 // remove the ones we really don't need 243 set.remove(NATIVE); 244 set.remove(SYNCHRONIZED); 245 set.remove(STRICTFP); 246 247 // According to JLS, we should not be showing public modifier for 248 // interface methods. 249 if ((utils.isField(member) || utils.isMethod(member)) 250 && ((writer instanceof ClassWriterImpl 251 && utils.isInterface(((ClassWriterImpl) writer).getTypeElement()) || 252 writer instanceof AnnotationTypeWriterImpl) )) { 253 // Remove the implicit abstract and public modifiers 254 if (utils.isMethod(member) && 255 (utils.isInterface(member.getEnclosingElement()) || 256 utils.isAnnotationType(member.getEnclosingElement()))) { 257 set.remove(ABSTRACT); 258 set.remove(PUBLIC); 259 } 260 if (!utils.isMethod(member)) { 261 set.remove(PUBLIC); 262 } 263 } 264 if (!set.isEmpty()) { 265 String mods = set.stream().map(Modifier::toString).collect(Collectors.joining(" ")); 266 htmltree.add(mods); 267 htmltree.add(Entity.NO_BREAK_SPACE); 268 } 269 } 270 271 protected CharSequence makeSpace(int len) { 272 if (len <= 0) { 273 return ""; 274 } 275 StringBuilder sb = new StringBuilder(len); 276 for (int i = 0; i < len; i++) { 277 sb.append(' '); 278 } 279 return sb; 280 } 281 282 /** 283 * Add the modifier and type for the member in the member summary. 284 * 285 * @param member the member to add the type for 286 * @param type the type to add 287 * @param tdSummaryType the content tree to which the modified and type will be added 288 */ 289 protected void addModifierAndType(Element member, TypeMirror type, 290 Content tdSummaryType) { 291 HtmlTree code = new HtmlTree(HtmlTag.CODE); 292 addModifier(member, code); 293 if (type == null) { 294 code.add(utils.isClass(member) ? "class" : "interface"); 295 code.add(Entity.NO_BREAK_SPACE); 296 } else { 297 List<? extends TypeParameterElement> list = utils.isExecutableElement(member) 298 ? ((ExecutableElement)member).getTypeParameters() 299 : null; 300 if (list != null && !list.isEmpty()) { 301 Content typeParameters = ((AbstractExecutableMemberWriter) this) 302 .getTypeParameters((ExecutableElement)member); 303 code.add(typeParameters); 304 //Code to avoid ugly wrapping in member summary table. 305 if (typeParameters.charCount() > 10) { 306 code.add(new HtmlTree(HtmlTag.BR)); 307 } else { 308 code.add(Entity.NO_BREAK_SPACE); 309 } 310 code.add( 311 writer.getLink(new LinkInfoImpl(configuration, 312 LinkInfoImpl.Kind.SUMMARY_RETURN_TYPE, type))); 313 } else { 314 code.add( 315 writer.getLink(new LinkInfoImpl(configuration, 316 LinkInfoImpl.Kind.SUMMARY_RETURN_TYPE, type))); 317 } 318 319 } 320 tdSummaryType.add(code); 321 } 322 323 /** 324 * Add the modifier for the member. 325 * 326 * @param member the member to add the type for 327 * @param code the content tree to which the modified will be added 328 */ 329 private void addModifier(Element member, Content code) { 330 if (utils.isProtected(member)) { 331 code.add("protected "); 332 } else if (utils.isPrivate(member)) { 333 code.add("private "); 334 } else if (!utils.isPublic(member)) { // Package private 335 code.add(resources.getText("doclet.Package_private")); 336 code.add(" "); 337 } 338 boolean isAnnotatedTypeElement = utils.isAnnotationType(member.getEnclosingElement()); 339 if (!isAnnotatedTypeElement && utils.isMethod(member)) { 340 if (!utils.isInterface(member.getEnclosingElement()) && utils.isAbstract(member)) { 341 code.add("abstract "); 342 } 343 if (utils.isDefault(member)) { 344 code.add("default "); 345 } 346 } 347 if (utils.isStatic(member)) { 348 code.add("static "); 349 } 350 } 351 352 /** 353 * Add the deprecated information for the given member. 354 * 355 * @param member the member being documented. 356 * @param contentTree the content tree to which the deprecated information will be added. 357 */ 358 protected void addDeprecatedInfo(Element member, Content contentTree) { 359 Content output = (new DeprecatedTaglet()).getTagletOutput(member, 360 writer.getTagletWriterInstance(false)); 361 if (!output.isEmpty()) { 362 Content deprecatedContent = output; 363 Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprecatedContent); 364 contentTree.add(div); 365 } 366 } 367 368 /** 369 * Add the comment for the given member. 370 * 371 * @param member the member being documented. 372 * @param htmltree the content tree to which the comment will be added. 373 */ 374 protected void addComment(Element member, Content htmltree) { 375 if (!utils.getFullBody(member).isEmpty()) { 376 writer.addInlineComment(member, htmltree); 377 } 378 } 379 380 protected String name(Element member) { 381 return utils.getSimpleName(member); 382 } 383 384 /** 385 * Return true if the given <code>ProgramElement</code> is inherited 386 * by the class that is being documented. 387 * 388 * @param ped The <code>ProgramElement</code> being checked. 389 * return true if the <code>ProgramElement</code> is being inherited and 390 * false otherwise. 391 *@return true if inherited 392 */ 393 protected boolean isInherited(Element ped){ 394 return (!utils.isPrivate(ped) && 395 (!utils.isPackagePrivate(ped) || 396 ped.getEnclosingElement().equals(ped.getEnclosingElement()))); 397 } 398 399 /** 400 * Add use information to the documentation tree. 401 * 402 * @param mems list of program elements for which the use information will be added 403 * @param heading the section heading 404 * @param contentTree the content tree to which the use information will be added 405 */ 406 protected void addUseInfo(List<? extends Element> mems, Content heading, Content contentTree) { 407 if (mems == null || mems.isEmpty()) { 408 return; 409 } 410 List<? extends Element> members = mems; 411 boolean printedUseTableHeader = false; 412 if (members.size() > 0) { 413 Table useTable = new Table(HtmlStyle.useSummary) 414 .setCaption(heading) 415 .setRowScopeColumn(1) 416 .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colSecond, HtmlStyle.colLast); 417 for (Element element : members) { 418 TypeElement te = (typeElement == null) 419 ? utils.getEnclosingTypeElement(element) 420 : typeElement; 421 if (!printedUseTableHeader) { 422 useTable.setHeader(getSummaryTableHeader(element)); 423 printedUseTableHeader = true; 424 } 425 Content summaryType = new ContentBuilder(); 426 addSummaryType(element, summaryType); 427 Content typeContent = new ContentBuilder(); 428 if (te != null 429 && !utils.isConstructor(element) 430 && !utils.isClass(element) 431 && !utils.isInterface(element) 432 && !utils.isAnnotationType(element)) { 433 HtmlTree name = new HtmlTree(HtmlTag.SPAN); 434 name.setStyle(HtmlStyle.typeNameLabel); 435 name.add(name(te) + "."); 436 typeContent.add(name); 437 } 438 addSummaryLink(utils.isClass(element) || utils.isInterface(element) 439 ? LinkInfoImpl.Kind.CLASS_USE 440 : LinkInfoImpl.Kind.MEMBER, 441 te, element, typeContent); 442 Content desc = new ContentBuilder(); 443 writer.addSummaryLinkComment(this, element, desc); 444 useTable.addRow(summaryType, typeContent, desc); 445 } 446 contentTree.add(useTable.toContent()); 447 } 448 } 449 450 protected void serialWarning(Element e, String key, String a1, String a2) { 451 if (configuration.serialwarn) { 452 configuration.messages.warning(e, key, a1, a2); 453 } 454 } 455 456 /** 457 * Add the member summary for the given class. 458 * 459 * @param tElement the class that is being documented 460 * @param member the member being documented 461 * @param firstSentenceTags the first sentence tags to be added to the summary 462 */ 463 @Override 464 public void addMemberSummary(TypeElement tElement, Element member, 465 List<? extends DocTree> firstSentenceTags) { 466 if (tElement != typeElement) { 467 throw new IllegalStateException(); 468 } 469 Table table = getSummaryTable(); 470 List<Content> rowContents = new ArrayList<>(); 471 Content summaryType = new ContentBuilder(); 472 addSummaryType(member, summaryType); 473 if (!summaryType.isEmpty()) 474 rowContents.add(summaryType); 475 Content summaryLink = new ContentBuilder(); 476 addSummaryLink(tElement, member, summaryLink); 477 rowContents.add(summaryLink); 478 Content desc = new ContentBuilder(); 479 writer.addSummaryLinkComment(this, member, firstSentenceTags, desc); 480 rowContents.add(desc); 481 table.addRow(member, rowContents); 482 } 483 484 /** 485 * Add inherited member summary for the given class and member. 486 * 487 * @param tElement the class the inherited member belongs to 488 * @param nestedClass the inherited member that is summarized 489 * @param isFirst true if this is the first member in the list 490 * @param isLast true if this is the last member in the list 491 * @param linksTree the content tree to which the summary will be added 492 */ 493 @Override 494 public void addInheritedMemberSummary(TypeElement tElement, 495 Element nestedClass, boolean isFirst, boolean isLast, 496 Content linksTree) { 497 writer.addInheritedMemberSummary(this, tElement, nestedClass, isFirst, 498 linksTree); 499 } 500 501 /** 502 * Get the inherited summary header for the given class. 503 * 504 * @param tElement the class the inherited member belongs to 505 * @return a content tree for the inherited summary header 506 */ 507 @Override 508 public Content getInheritedSummaryHeader(TypeElement tElement) { 509 Content inheritedTree = writer.getMemberInheritedTree(); 510 writer.addInheritedSummaryHeader(this, tElement, inheritedTree); 511 return inheritedTree; 512 } 513 514 /** 515 * Get the inherited summary links tree. 516 * 517 * @return a content tree for the inherited summary links 518 */ 519 @Override 520 public Content getInheritedSummaryLinksTree() { 521 return new HtmlTree(HtmlTag.CODE); 522 } 523 524 /** 525 * Get the summary table tree for the given class. 526 * 527 * @param tElement the class for which the summary table is generated 528 * @return a content tree for the summary table 529 */ 530 @Override 531 public Content getSummaryTableTree(TypeElement tElement) { 532 if (tElement != typeElement) { 533 throw new IllegalStateException(); 534 } 535 Table table = getSummaryTable(); 536 if (table.needsScript()) { 537 writer.getMainBodyScript().append(table.getScript()); 538 } 539 return table.toContent(); 540 } 541 542 /** 543 * Get the member tree to be documented. 544 * 545 * @param memberTree the content tree of member to be documented 546 * @return a content tree that will be added to the class documentation 547 */ 548 @Override 549 public Content getMemberTree(Content memberTree) { 550 return writer.getMemberTree(memberTree); 551 } 552 553 /** 554 * Get the member tree to be documented. 555 * 556 * @param memberTree the content tree of member to be documented 557 * @param isLastContent true if the content to be added is the last content 558 * @return a content tree that will be added to the class documentation 559 */ 560 public Content getMemberTree(Content memberTree, boolean isLastContent) { 561 if (isLastContent) 562 return HtmlTree.LI(HtmlStyle.blockListLast, memberTree); 563 else 564 return HtmlTree.LI(HtmlStyle.blockList, memberTree); 565 } 566 }