001/* 002 * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package org.jdrupes.mdoclet.internal.doclets.formats.html; 027 028import java.util.Collection; 029import java.util.SortedSet; 030import java.util.TreeSet; 031 032import javax.lang.model.element.Element; 033import javax.lang.model.element.ExecutableElement; 034import javax.lang.model.element.TypeElement; 035import javax.lang.model.type.TypeMirror; 036 037import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.ContentBuilder; 038import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Entity; 039import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlId; 040import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlStyle; 041import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlTree; 042import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Text; 043import org.jdrupes.mdoclet.internal.doclets.toolkit.Content; 044import org.jdrupes.mdoclet.internal.doclets.toolkit.MemberSummaryWriter; 045import org.jdrupes.mdoclet.internal.doclets.toolkit.MethodWriter; 046import org.jdrupes.mdoclet.internal.doclets.toolkit.util.Utils; 047import org.jdrupes.mdoclet.internal.doclets.toolkit.util.VisibleMemberTable; 048 049/** 050 * Writes method documentation in HTML format. 051 */ 052public class MethodWriterImpl extends AbstractExecutableMemberWriter 053 implements MethodWriter, MemberSummaryWriter { 054 055 /** 056 * Construct a new MethodWriterImpl. 057 * 058 * @param writer the writer for the class that the methods belong to. 059 * @param typeElement the class being documented. 060 */ 061 public MethodWriterImpl(SubWriterHolderWriter writer, 062 TypeElement typeElement) { 063 super(writer, typeElement); 064 } 065 066 /** 067 * Construct a new MethodWriterImpl. 068 * 069 * @param writer The writer for the class that the methods belong to. 070 */ 071 public MethodWriterImpl(SubWriterHolderWriter writer) { 072 super(writer); 073 } 074 075 @Override 076 public Content getMemberSummaryHeader(TypeElement typeElement, 077 Content target) { 078 target.add(MarkerComments.START_OF_METHOD_SUMMARY); 079 Content memberContent = new ContentBuilder(); 080 writer.addSummaryHeader(this, memberContent); 081 return memberContent; 082 } 083 084 @Override 085 public void addSummary(Content summariesList, Content content) { 086 writer.addSummary(HtmlStyle.methodSummary, 087 HtmlIds.METHOD_SUMMARY, summariesList, content); 088 } 089 090 @Override 091 public Content getMethodDetailsHeader(Content content) { 092 content.add(MarkerComments.START_OF_METHOD_DETAILS); 093 Content methodDetailsContent = new ContentBuilder(); 094 var heading = HtmlTree.HEADING(Headings.TypeDeclaration.DETAILS_HEADING, 095 contents.methodDetailLabel); 096 methodDetailsContent.add(heading); 097 return methodDetailsContent; 098 } 099 100 @Override 101 public Content getMethodHeader(ExecutableElement method) { 102 Content content = new ContentBuilder(); 103 var heading = HtmlTree.HEADING(Headings.TypeDeclaration.MEMBER_HEADING, 104 Text.of(name(method))); 105 HtmlId erasureAnchor; 106 if ((erasureAnchor = htmlIds.forErasure(method)) != null) { 107 heading.setId(erasureAnchor); 108 } 109 content.add(heading); 110 return HtmlTree.SECTION(HtmlStyle.detail, content) 111 .setId(htmlIds.forMember(method)); 112 } 113 114 @Override 115 public Content getSignature(ExecutableElement method) { 116 return new Signatures.MemberSignature(method, this) 117 .setTypeParameters(getTypeParameters(method)) 118 .setReturnType(getReturnType(method)) 119 .setParameters(getParameters(method, true)) 120 .setExceptions(getExceptions(method)) 121 .setAnnotations(writer.getAnnotationInfo(method, true)) 122 .toContent(); 123 } 124 125 @Override 126 public void addDeprecated(ExecutableElement method, Content methodContent) { 127 addDeprecatedInfo(method, methodContent); 128 } 129 130 @Override 131 public void addPreview(ExecutableElement method, Content content) { 132 addPreviewInfo(method, content); 133 } 134 135 @Override 136 public void addComments(TypeMirror holderType, ExecutableElement method, 137 Content methodContent) { 138 TypeElement holder = utils.asTypeElement(holderType); 139 if (!utils.getFullBody(method).isEmpty()) { 140 if (holder.equals(typeElement) || 141 !(utils.isPublic(holder) || 142 utils.isLinkable(holder))) { 143 writer.addInlineComment(method, methodContent); 144 } else { 145 if (!utils.hasHiddenTag(holder) 146 && !utils.hasHiddenTag(method)) { 147 Content link = writer.getDocLink(HtmlLinkInfo.Kind.PLAIN, 148 holder, method, 149 utils.isIncluded(holder) 150 ? utils.getSimpleName(holder) 151 : utils.getFullyQualifiedName(holder)); 152 var codeLink = HtmlTree.CODE(link); 153 var descriptionFromTypeLabel 154 = HtmlTree.SPAN(HtmlStyle.descriptionFromTypeLabel, 155 utils.isClass(holder) 156 ? contents.descriptionFromClassLabel 157 : contents.descriptionFromInterfaceLabel); 158 descriptionFromTypeLabel.add(Entity.NO_BREAK_SPACE); 159 descriptionFromTypeLabel.add(codeLink); 160 methodContent.add(HtmlTree.DIV(HtmlStyle.block, 161 descriptionFromTypeLabel)); 162 } 163 writer.addInlineComment(method, methodContent); 164 } 165 } 166 } 167 168 @Override 169 public void addTags(ExecutableElement method, Content methodContent) { 170 writer.addTagsInfo(method, methodContent); 171 } 172 173 @Override 174 public Content getMethodDetails(Content methodDetailsHeader, 175 Content methodDetails) { 176 Content c = new ContentBuilder(methodDetailsHeader, methodDetails); 177 return getMember(HtmlTree.SECTION(HtmlStyle.methodDetails, c) 178 .setId(HtmlIds.METHOD_DETAIL)); 179 } 180 181 @Override 182 public void addSummaryLabel(Content content) { 183 var label = HtmlTree.HEADING(Headings.TypeDeclaration.SUMMARY_HEADING, 184 contents.methodSummary); 185 content.add(label); 186 } 187 188 @Override 189 public TableHeader getSummaryTableHeader(Element member) { 190 return new TableHeader(contents.modifierAndTypeLabel, 191 contents.methodLabel, 192 contents.descriptionLabel); 193 } 194 195 @Override 196 protected Table<Element> createSummaryTable() { 197 return new Table<Element>(HtmlStyle.summaryTable) 198 .setHeader(getSummaryTableHeader(typeElement)) 199 .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colSecond, 200 HtmlStyle.colLast) 201 .setId(HtmlIds.METHOD_SUMMARY_TABLE) 202 .setDefaultTab(contents.getContent("doclet.All_Methods")) 203 .addTab(contents.getContent("doclet.Static_Methods"), 204 utils::isStatic) 205 .addTab(contents.getContent("doclet.Instance_Methods"), 206 e -> !utils.isStatic(e)) 207 .addTab(contents.getContent("doclet.Abstract_Methods"), 208 utils::isAbstract) 209 .addTab(contents.getContent("doclet.Concrete_Methods"), 210 e -> !utils.isAbstract(e) 211 && !utils.isPlainInterface(e.getEnclosingElement())) 212 .addTab(contents.getContent("doclet.Default_Methods"), 213 utils::isDefault) 214 .addTab(contents.getContent("doclet.Deprecated_Methods"), 215 e -> utils.isDeprecated(e) || utils.isDeprecated(typeElement)); 216 } 217 218 @Override 219 public void addInheritedSummaryLabel(TypeElement typeElement, 220 Content content) { 221 Content classLink = writer.getPreQualifiedClassLink( 222 HtmlLinkInfo.Kind.PLAIN, typeElement); 223 Content label; 224 if (options.summarizeOverriddenMethods()) { 225 label = Text.of(utils.isClass(typeElement) 226 ? resources.getText("doclet.Methods_Declared_In_Class") 227 : resources.getText("doclet.Methods_Declared_In_Interface")); 228 } else { 229 label = Text.of(utils.isClass(typeElement) 230 ? resources.getText("doclet.Methods_Inherited_From_Class") 231 : resources.getText("doclet.Methods_Inherited_From_Interface")); 232 } 233 var labelHeading = HtmlTree.HEADING( 234 Headings.TypeDeclaration.INHERITED_SUMMARY_HEADING, 235 label); 236 labelHeading.setId(htmlIds.forInheritedMethods(typeElement)); 237 labelHeading.add(Entity.NO_BREAK_SPACE); 238 labelHeading.add(classLink); 239 content.add(labelHeading); 240 } 241 242 @Override 243 protected void addSummaryType(Element member, Content content) { 244 ExecutableElement meth = (ExecutableElement) member; 245 addModifiersAndType(meth, utils.getReturnType(typeElement, meth), 246 content); 247 } 248 249 /** 250 * Adds "overrides" or "specified by" information about a method (if appropriate) 251 * into a definition list. 252 * 253 * @param writer the writer for the element 254 * @param overriddenType the superclass 255 * @param method the method 256 * @param dl the list in which to add the information. 257 */ 258 protected static void addOverridden(HtmlDocletWriter writer, 259 TypeMirror overriddenType, 260 ExecutableElement method, 261 Content dl) { 262 if (writer.options.noComment()) { 263 return; 264 } 265 Utils utils = writer.utils; 266 TypeElement holder = utils.getEnclosingTypeElement(method); 267 if (!(utils.isPublic(holder) || utils.isLinkable(holder))) { 268 // This is an implementation detail that should not be documented. 269 return; 270 } 271 if (utils.isIncluded(holder) && !utils.isIncluded(method)) { 272 // The class is included but the method is not. That means that it 273 // is not visible so don't document this. 274 return; 275 } 276 if (utils.hasHiddenTag(holder) || utils.hasHiddenTag(method)) { 277 return; 278 } 279 280 Contents contents = writer.contents; 281 Content label; 282 HtmlLinkInfo.Kind context; 283 if (utils.isAbstract(holder) && utils.isAbstract(method)) { 284 // Abstract method is implemented from abstract class, 285 // not overridden 286 label = contents.specifiedByLabel; 287 context = HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS; 288 } else { 289 label = contents.overridesLabel; 290 context = HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS; 291 } 292 dl.add(HtmlTree.DT(label)); 293 Content overriddenTypeLink = writer.getLink( 294 new HtmlLinkInfo(writer.configuration, context, overriddenType)); 295 var codeOverriddenTypeLink = HtmlTree.CODE(overriddenTypeLink); 296 Content methlink = writer.getLink( 297 new HtmlLinkInfo(writer.configuration, HtmlLinkInfo.Kind.PLAIN, 298 holder) 299 .fragment(writer.htmlIds.forMember(method).name()) 300 .label(method.getSimpleName())); 301 var codeMethLink = HtmlTree.CODE(methlink); 302 var dd = HtmlTree.DD(codeMethLink); 303 dd.add(Entity.NO_BREAK_SPACE); 304 dd.add(contents.inClass); 305 dd.add(Entity.NO_BREAK_SPACE); 306 dd.add(codeOverriddenTypeLink); 307 dl.add(dd); 308 } 309 310 /** 311 * Adds "implements" information for a method (if appropriate) 312 * into a definition list. 313 * 314 * @param writer the writer for the method 315 * @param method the method 316 * @param methods implemented methods 317 * @param dl the definition list 318 */ 319 protected static void addImplementsInfo(HtmlDocletWriter writer, 320 ExecutableElement method, 321 Collection<ExecutableElement> methods, 322 Content dl) { 323 Utils utils = writer.utils; 324 if (writer.options.noComment()) { 325 return; 326 } 327 Contents contents = writer.contents; 328 var enclosing = (TypeElement) method.getEnclosingElement(); 329 VisibleMemberTable vmt 330 = writer.configuration.getVisibleMemberTable(enclosing); 331 SortedSet<ExecutableElement> implementedMethods 332 = new TreeSet<>(utils.comparators.makeOverrideUseComparator()); 333 implementedMethods.addAll(methods); 334 for (ExecutableElement implementedMeth : implementedMethods) { 335 TypeMirror intfac 336 = vmt.getImplementedMethodHolder(method, implementedMeth); 337 intfac = utils.getDeclaredType(enclosing, intfac); 338 Content intfaclink = writer.getLink(new HtmlLinkInfo( 339 writer.configuration, 340 HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS, intfac)); 341 var codeIntfacLink = HtmlTree.CODE(intfaclink); 342 dl.add(HtmlTree.DT(contents.specifiedByLabel)); 343 Content methlink = writer.getDocLink( 344 HtmlLinkInfo.Kind.PLAIN, implementedMeth, 345 implementedMeth.getSimpleName()); 346 var codeMethLink = HtmlTree.CODE(methlink); 347 var dd = HtmlTree.DD(codeMethLink); 348 dd.add(Entity.NO_BREAK_SPACE); 349 dd.add(contents.inInterface); 350 dd.add(Entity.NO_BREAK_SPACE); 351 dd.add(codeIntfacLink); 352 dl.add(dd); 353 } 354 } 355 356 /** 357 * Get the return type for the given method. 358 * 359 * @param method the method being documented. 360 * @return the return type 361 */ 362 protected Content getReturnType(ExecutableElement method) { 363 TypeMirror type = utils.getReturnType(typeElement, method); 364 if (type != null) { 365 return writer.getLink(new HtmlLinkInfo(configuration, 366 HtmlLinkInfo.Kind.LINK_TYPE_PARAMS, type)); 367 } 368 return new ContentBuilder(); 369 } 370 371 @Override 372 public Content getMemberHeader() { 373 return writer.getMemberHeader(); 374 } 375}