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.SortedSet; 29 import java.util.TreeSet; 30 31 import javax.lang.model.element.Element; 32 import javax.lang.model.element.ExecutableElement; 33 import javax.lang.model.element.TypeElement; 34 import javax.lang.model.type.TypeMirror; 35 36 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; 37 import jdk.javadoc.internal.doclets.formats.html.markup.Entity; 38 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; 39 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; 40 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent; 41 import jdk.javadoc.internal.doclets.formats.html.markup.Table; 42 import jdk.javadoc.internal.doclets.formats.html.markup.TableHeader; 43 import jdk.javadoc.internal.doclets.toolkit.Content; 44 import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter; 45 import jdk.javadoc.internal.doclets.toolkit.MethodWriter; 46 import jdk.javadoc.internal.doclets.toolkit.util.Utils; 47 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; 48 49 /** 50 * Writes method documentation in HTML format. 51 * 52 * <p><b>This is NOT part of any supported API. 53 * If you write code that depends on this, you do so at your own risk. 54 * This code and its internal interfaces are subject to change or 55 * deletion without notice.</b> 56 */ 57 public class MethodWriterImpl extends AbstractExecutableMemberWriter 58 implements MethodWriter, MemberSummaryWriter { 59 60 /** 61 * Construct a new MethodWriterImpl. 62 * 63 * @param writer the writer for the class that the methods belong to. 64 * @param typeElement the class being documented. 65 */ 66 public MethodWriterImpl(SubWriterHolderWriter writer, TypeElement typeElement) { 67 super(writer, typeElement); 68 } 69 70 /** 71 * Construct a new MethodWriterImpl. 72 * 73 * @param writer The writer for the class that the methods belong to. 74 */ 75 public MethodWriterImpl(SubWriterHolderWriter writer) { 76 super(writer); 77 } 78 79 /** 80 * {@inheritDoc} 81 */ 82 @Override 83 public Content getMemberSummaryHeader(TypeElement typeElement, Content memberSummaryTree) { 84 memberSummaryTree.add(MarkerComments.START_OF_METHOD_SUMMARY); 85 Content memberTree = new ContentBuilder(); 86 writer.addSummaryHeader(this, memberTree); 87 return memberTree; 88 } 89 90 /** 91 * {@inheritDoc} 92 */ 93 @Override 94 public void addMemberTree(Content memberSummaryTree, Content memberTree) { 95 writer.addMemberTree(HtmlStyle.methodSummary, 96 SectionName.METHOD_SUMMARY, memberSummaryTree, memberTree); 97 } 98 99 /** 100 * {@inheritDoc} 101 */ 102 @Override 103 public Content getMethodDetailsTreeHeader(Content memberDetailsTree) { 104 memberDetailsTree.add(MarkerComments.START_OF_METHOD_DETAILS); 105 Content methodDetailsTree = new ContentBuilder(); 106 Content heading = HtmlTree.HEADING(Headings.TypeDeclaration.DETAILS_HEADING, 107 contents.methodDetailLabel); 108 methodDetailsTree.add(heading); 109 return methodDetailsTree; 110 } 111 112 /** 113 * {@inheritDoc} 114 */ 115 @Override 116 public Content getMethodDocTreeHeader(ExecutableElement method) { 117 String erasureAnchor; 118 Content methodDocTree = new ContentBuilder(); 119 HtmlTree heading = new HtmlTree(Headings.TypeDeclaration.MEMBER_HEADING, 120 new StringContent(name(method))); 121 if ((erasureAnchor = getErasureAnchor(method)) != null) { 122 heading.setId(erasureAnchor); 123 } 124 methodDocTree.add(heading); 125 return HtmlTree.SECTION(HtmlStyle.detail, methodDocTree) 126 .setId(links.getName(writer.getAnchor(method))); 127 } 128 129 /** 130 * Get the signature for the given method. 131 * 132 * @param method the method being documented. 133 * @return a content object for the signature 134 */ 135 @Override 136 public Content getSignature(ExecutableElement method) { 137 return new MemberSignature(method) 138 .addTypeParameters(getTypeParameters(method)) 139 .addReturnType(getReturnType(method)) 140 .addParameters(getParameters(method, true)) 141 .addExceptions(getExceptions(method)) 142 .toContent(); 143 } 144 145 /** 146 * {@inheritDoc} 147 */ 148 @Override 149 public void addDeprecated(ExecutableElement method, Content methodDocTree) { 150 addDeprecatedInfo(method, methodDocTree); 151 } 152 153 /** 154 * {@inheritDoc} 155 */ 156 @Override 157 public void addComments(TypeMirror holderType, ExecutableElement method, Content methodDocTree) { 158 TypeElement holder = utils.asTypeElement(holderType); 159 if (!utils.getFullBody(method).isEmpty()) { 160 if (holder.equals(typeElement) || 161 !(utils.isPublic(holder) || 162 utils.isLinkable(holder))) { 163 writer.addInlineComment(method, methodDocTree); 164 } else { 165 Content link = 166 writer.getDocLink(LinkInfoImpl.Kind.EXECUTABLE_ELEMENT_COPY, 167 holder, method, 168 utils.isIncluded(holder) 169 ? utils.getSimpleName(holder) 170 : utils.getFullyQualifiedName(holder), 171 false); 172 Content codeLink = HtmlTree.CODE(link); 173 Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel, 174 utils.isClass(holder) 175 ? contents.descfrmClassLabel 176 : contents.descfrmInterfaceLabel); 177 descfrmLabel.add(Entity.NO_BREAK_SPACE); 178 descfrmLabel.add(codeLink); 179 methodDocTree.add(HtmlTree.DIV(HtmlStyle.block, descfrmLabel)); 180 writer.addInlineComment(method, methodDocTree); 181 } 182 } 183 } 184 185 /** 186 * {@inheritDoc} 187 */ 188 @Override 189 public void addTags(ExecutableElement method, Content methodDocTree) { 190 writer.addTagsInfo(method, methodDocTree); 191 } 192 193 /** 194 * {@inheritDoc} 195 */ 196 @Override 197 public Content getMethodDetails(Content methodDetailsTreeHeader, Content methodDetailsTree) { 198 Content methodDetails = new ContentBuilder(methodDetailsTreeHeader, methodDetailsTree); 199 return getMemberTree(HtmlTree.SECTION(HtmlStyle.methodDetails, methodDetails) 200 .setId(SectionName.METHOD_DETAIL.getName())); 201 } 202 203 /** 204 * {@inheritDoc} 205 */ 206 @Override 207 public Content getMethodDoc(Content methodDocTree) { 208 return getMemberTree(methodDocTree); 209 } 210 211 /** 212 * {@inheritDoc} 213 */ 214 @Override 215 public void addSummaryLabel(Content memberTree) { 216 Content label = HtmlTree.HEADING(Headings.TypeDeclaration.SUMMARY_HEADING, 217 contents.methodSummary); 218 memberTree.add(label); 219 } 220 221 /** 222 * {@inheritDoc} 223 */ 224 @Override 225 public TableHeader getSummaryTableHeader(Element member) { 226 return new TableHeader(contents.modifierAndTypeLabel, contents.methodLabel, 227 contents.descriptionLabel); 228 } 229 230 @Override 231 protected Table createSummaryTable() { 232 return new Table(HtmlStyle.memberSummary) 233 .setHeader(getSummaryTableHeader(typeElement)) 234 .setRowScopeColumn(1) 235 .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colSecond, HtmlStyle.colLast) 236 .setDefaultTab(resources.getText("doclet.All_Methods")) 237 .addTab(resources.getText("doclet.Static_Methods"), utils::isStatic) 238 .addTab(resources.getText("doclet.Instance_Methods"), e -> !utils.isStatic(e)) 239 .addTab(resources.getText("doclet.Abstract_Methods"), utils::isAbstract) 240 .addTab(resources.getText("doclet.Concrete_Methods"), 241 e -> !utils.isAbstract(e) && !utils.isInterface(e.getEnclosingElement())) 242 .addTab(resources.getText("doclet.Default_Methods"), utils::isDefault) 243 .addTab(resources.getText("doclet.Deprecated_Methods"), 244 e -> utils.isDeprecated(e) || utils.isDeprecated(typeElement)) 245 .setTabScript(i -> "show(" + i + ");"); 246 } 247 248 /** 249 * {@inheritDoc} 250 */ 251 @Override 252 public void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree) { 253 Content classLink = writer.getPreQualifiedClassLink( 254 LinkInfoImpl.Kind.MEMBER, typeElement, false); 255 Content label; 256 if (configuration.summarizeOverriddenMethods) { 257 label = new StringContent(utils.isClass(typeElement) 258 ? resources.getText("doclet.Methods_Declared_In_Class") 259 : resources.getText("doclet.Methods_Declared_In_Interface")); 260 } else { 261 label = new StringContent(utils.isClass(typeElement) 262 ? resources.getText("doclet.Methods_Inherited_From_Class") 263 : resources.getText("doclet.Methods_Inherited_From_Interface")); 264 } 265 HtmlTree labelHeading = HtmlTree.HEADING(Headings.TypeDeclaration.INHERITED_SUMMARY_HEADING, 266 label); 267 labelHeading.setId(SectionName.METHODS_INHERITANCE.getName() 268 + links.getName(configuration.getClassName(typeElement))); 269 labelHeading.add(Entity.NO_BREAK_SPACE); 270 labelHeading.add(classLink); 271 inheritedTree.add(labelHeading); 272 } 273 274 /** 275 * {@inheritDoc} 276 */ 277 @Override 278 protected void addSummaryType(Element member, Content tdSummaryType) { 279 ExecutableElement meth = (ExecutableElement)member; 280 addModifierAndType(meth, utils.getReturnType(typeElement, meth), tdSummaryType); 281 } 282 283 /** 284 * {@inheritDoc} 285 */ 286 protected static void addOverridden(HtmlDocletWriter writer, 287 TypeMirror overriddenType, ExecutableElement method, Content dl) { 288 if (writer.configuration.nocomment) { 289 return; 290 } 291 Utils utils = writer.utils; 292 Contents contents = writer.contents; 293 TypeElement holder = utils.getEnclosingTypeElement(method); 294 if (!(utils.isPublic(holder) || 295 utils.isLinkable(holder))) { 296 //This is an implementation detail that should not be documented. 297 return; 298 } 299 if (utils.isIncluded(holder) && ! utils.isIncluded(method)) { 300 //The class is included but the method is not. That means that it 301 //is not visible so don't document this. 302 return; 303 } 304 Content label = contents.overridesLabel; 305 LinkInfoImpl.Kind context = LinkInfoImpl.Kind.METHOD_OVERRIDES; 306 307 if (method != null) { 308 if (utils.isAbstract(holder) && utils.isAbstract(method)){ 309 //Abstract method is implemented from abstract class, 310 //not overridden 311 label = contents.specifiedByLabel; 312 context = LinkInfoImpl.Kind.METHOD_SPECIFIED_BY; 313 } 314 Content dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.overrideSpecifyLabel, label)); 315 dl.add(dt); 316 Content overriddenTypeLink = 317 writer.getLink(new LinkInfoImpl(writer.configuration, context, overriddenType)); 318 Content codeOverriddenTypeLink = HtmlTree.CODE(overriddenTypeLink); 319 Content methlink = writer.getLink( 320 new LinkInfoImpl(writer.configuration, LinkInfoImpl.Kind.MEMBER, holder) 321 .where(writer.links.getName(writer.getAnchor(method))) 322 .label(method.getSimpleName())); 323 Content codeMethLink = HtmlTree.CODE(methlink); 324 Content dd = HtmlTree.DD(codeMethLink); 325 dd.add(Entity.NO_BREAK_SPACE); 326 dd.add(writer.contents.inClass); 327 dd.add(Entity.NO_BREAK_SPACE); 328 dd.add(codeOverriddenTypeLink); 329 dl.add(dd); 330 } 331 } 332 333 /** 334 * {@inheritDoc} 335 */ 336 protected static void addImplementsInfo(HtmlDocletWriter writer, 337 ExecutableElement method, Content dl) { 338 Utils utils = writer.utils; 339 if (utils.isStatic(method) || writer.configuration.nocomment) { 340 return; 341 } 342 Contents contents = writer.contents; 343 VisibleMemberTable vmt = writer.configuration 344 .getVisibleMemberTable(utils.getEnclosingTypeElement(method)); 345 SortedSet<ExecutableElement> implementedMethods = 346 new TreeSet<>(utils.makeOverrideUseComparator()); 347 implementedMethods.addAll(vmt.getImplementedMethods(method)); 348 for (ExecutableElement implementedMeth : implementedMethods) { 349 TypeMirror intfac = vmt.getImplementedMethodHolder(method, implementedMeth); 350 intfac = utils.getDeclaredType(utils.getEnclosingTypeElement(method), intfac); 351 Content intfaclink = writer.getLink(new LinkInfoImpl( 352 writer.configuration, LinkInfoImpl.Kind.METHOD_SPECIFIED_BY, intfac)); 353 Content codeIntfacLink = HtmlTree.CODE(intfaclink); 354 Content dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.overrideSpecifyLabel, contents.specifiedByLabel)); 355 dl.add(dt); 356 Content methlink = writer.getDocLink( 357 LinkInfoImpl.Kind.MEMBER, implementedMeth, 358 implementedMeth.getSimpleName(), false); 359 Content codeMethLink = HtmlTree.CODE(methlink); 360 Content dd = HtmlTree.DD(codeMethLink); 361 dd.add(Entity.NO_BREAK_SPACE); 362 dd.add(contents.inInterface); 363 dd.add(Entity.NO_BREAK_SPACE); 364 dd.add(codeIntfacLink); 365 dl.add(dd); 366 } 367 } 368 369 /** 370 * Get the return type for the given method. 371 * 372 * @param method the method being documented. 373 * @return content containing the return type 374 */ 375 protected Content getReturnType(ExecutableElement method) { 376 TypeMirror type = utils.getReturnType(typeElement, method); 377 if (type != null) { 378 return writer.getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.RETURN_TYPE, type)); 379 } 380 return new ContentBuilder(); 381 } 382 383 @Override 384 public Content getMemberTreeHeader(){ 385 return writer.getMemberTreeHeader(); 386 } 387 }