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 static org.jdrupes.mdoclet.internal.doclets.formats.html.HtmlLinkInfo.Kind.LINK_TYPE_PARAMS; 029import static org.jdrupes.mdoclet.internal.doclets.formats.html.HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS; 030import static org.jdrupes.mdoclet.internal.doclets.formats.html.HtmlLinkInfo.Kind.PLAIN; 031import static org.jdrupes.mdoclet.internal.doclets.formats.html.HtmlLinkInfo.Kind.SHOW_PREVIEW; 032import static org.jdrupes.mdoclet.internal.doclets.formats.html.HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_AND_BOUNDS; 033 034import java.util.List; 035 036import javax.lang.model.element.Element; 037import javax.lang.model.element.ElementKind; 038import javax.lang.model.element.ExecutableElement; 039import javax.lang.model.element.TypeElement; 040import javax.lang.model.element.VariableElement; 041import javax.lang.model.type.DeclaredType; 042import javax.lang.model.type.ExecutableType; 043import javax.lang.model.type.TypeMirror; 044import javax.lang.model.util.SimpleTypeVisitor14; 045 046import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.ContentBuilder; 047import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Entity; 048import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlStyle; 049import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlTree; 050import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.TagName; 051import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Text; 052import org.jdrupes.mdoclet.internal.doclets.toolkit.Content; 053 054/** 055 * Print method and constructor info. 056 */ 057public abstract class AbstractExecutableMemberWriter 058 extends AbstractMemberWriter { 059 060 public AbstractExecutableMemberWriter(SubWriterHolderWriter writer, 061 TypeElement typeElement) { 062 super(writer, typeElement); 063 } 064 065 public AbstractExecutableMemberWriter(SubWriterHolderWriter writer) { 066 super(writer); 067 } 068 069 /** 070 * Get the type parameters for the executable member. 071 * 072 * @param member the member for which to get the type parameters. 073 * @return the type parameters. 074 */ 075 protected Content getTypeParameters(ExecutableElement member) { 076 HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration, 077 LINK_TYPE_PARAMS_AND_BOUNDS, member) 078 .addLineBreaksInTypeParameters(true) 079 .showTypeParameterAnnotations(true); 080 return writer.getTypeParameterLinks(linkInfo); 081 } 082 083 @Override 084 protected Content getSummaryLink(Element member) { 085 Content content = new ContentBuilder(); 086 content.add(utils.getFullyQualifiedName(member)); 087 if (!utils.isConstructor(member)) { 088 content.add("."); 089 content.add(member.getSimpleName()); 090 } 091 String signature 092 = utils.flatSignature((ExecutableElement) member, typeElement); 093 if (signature.length() > 2) { 094 content.add(new HtmlTree(TagName.WBR)); 095 } 096 content.add(signature); 097 098 return writer.getDocLink(SHOW_PREVIEW, 099 utils.getEnclosingTypeElement(member), 100 member, content, null, false); 101 } 102 103 @Override 104 protected void addSummaryLink(HtmlLinkInfo.Kind context, TypeElement te, 105 Element member, 106 Content target) { 107 ExecutableElement ee = (ExecutableElement) member; 108 Content memberLink = writer.getDocLink(context, te, ee, name(ee), 109 HtmlStyle.memberNameLink); 110 var code = HtmlTree.CODE(memberLink); 111 addParameters(ee, code); 112 target.add(code); 113 } 114 115 @Override 116 protected void addInheritedSummaryLink(TypeElement te, Element member, 117 Content target) { 118 target.add(writer.getDocLink(PLAIN, te, member, name(member))); 119 } 120 121 /** 122 * Add the parameter for the executable member. 123 * 124 * @param param the parameter that needs to be added. 125 * @param paramType the type of the parameter. 126 * @param isVarArg true if this is a link to var arg. 127 * @param target the content to which the parameter information will be added. 128 */ 129 protected void addParam(VariableElement param, TypeMirror paramType, 130 boolean isVarArg, 131 Content target) { 132 HtmlLinkInfo linkInfo 133 = new HtmlLinkInfo(configuration, LINK_TYPE_PARAMS, paramType) 134 .varargs(isVarArg) 135 .showTypeParameterAnnotations(true); 136 Content link = writer.getLink(linkInfo); 137 target.add(link); 138 if (name(param).length() > 0) { 139 target.add(Entity.NO_BREAK_SPACE); 140 target.add(name(param)); 141 } 142 } 143 144 /** 145 * Add the receiver information. 146 * 147 * <p>Note: receivers can only have type-use annotations.</p> 148 * 149 * @param member the member to write receiver annotations for. 150 * @param rcvrType the receiver type. 151 * @param target the content to which the information will be added. 152 */ 153 protected void addReceiver(ExecutableElement member, TypeMirror rcvrType, 154 Content target) { 155 var info = new HtmlLinkInfo(configuration, SHOW_TYPE_PARAMS_AND_BOUNDS, 156 rcvrType) 157 .linkToSelf(false); 158 target.add(writer.getLink(info)); 159 target.add(Entity.NO_BREAK_SPACE); 160 if (member.getKind() == ElementKind.CONSTRUCTOR) { 161 target.add(utils.getTypeName(rcvrType, false)); 162 target.add("."); 163 } 164 target.add("this"); 165 } 166 167 /** 168 * Returns {@code true} if a receiver type is annotated anywhere in its type for 169 * inclusion in member details. 170 * 171 * @param receiverType the receiver type. 172 * @return {@code true} if the receiver is annotated 173 */ 174 protected boolean isAnnotatedReceiver(TypeMirror receiverType) { 175 return new SimpleTypeVisitor14<Boolean, Void>() { 176 @Override 177 protected Boolean defaultAction(TypeMirror e, Void unused) { 178 return utils.isAnnotated(e); 179 } 180 181 @Override 182 public Boolean visitDeclared(DeclaredType t, Void unused) { 183 if (super.visitDeclared(t, unused) 184 || visit(t.getEnclosingType())) { 185 return true; 186 } 187 188 for (var e : t.getTypeArguments()) { 189 if (visit(e)) { 190 return true; 191 } 192 } 193 194 return false; 195 } 196 }.visit(receiverType); 197 } 198 199 /** 200 * Add all the parameters for the executable member. 201 * 202 * @param member the member to write parameters for. 203 * @param target the content to which the parameters information will be added. 204 */ 205 protected void addParameters(ExecutableElement member, Content target) { 206 Content params = getParameters(member, false); 207 if (params.charCount() > 2) { 208 // only add <wbr> for non-empty parameters 209 target.add(new HtmlTree(TagName.WBR)); 210 } 211 target.add(params); 212 } 213 214 /** 215 * Add all the parameters for the executable member. 216 * 217 * @param member the member to write parameters for. 218 * @param includeAnnotations true if annotation information needs to be added. 219 * @return the parameter information 220 */ 221 protected Content getParameters(ExecutableElement member, 222 boolean includeAnnotations) { 223 Content result = new ContentBuilder(); 224 result.add("("); 225 String sep = ""; 226 List<? extends VariableElement> parameters = member.getParameters(); 227 TypeMirror rcvrType = member.getReceiverType(); 228 if (includeAnnotations && rcvrType != null 229 && isAnnotatedReceiver(rcvrType)) { 230 addReceiver(member, rcvrType, result); 231 sep = "," + Text.NL + " "; 232 } 233 int paramstart; 234 ExecutableType instMeth 235 = utils.asInstantiatedMethodType(typeElement, member); 236 for (paramstart = 0; paramstart < parameters.size(); paramstart++) { 237 result.add(sep); 238 VariableElement param = parameters.get(paramstart); 239 TypeMirror paramType = instMeth.getParameterTypes().get(paramstart); 240 241 if (param.getKind() != ElementKind.INSTANCE_INIT) { 242 if (includeAnnotations) { 243 Content annotationInfo 244 = writer.getAnnotationInfo(param, false); 245 if (!annotationInfo.isEmpty()) { 246 result.add(annotationInfo) 247 .add(Text.NL) 248 .add(" "); 249 } 250 } 251 addParam(param, paramType, 252 (paramstart == parameters.size() - 1) && member.isVarArgs(), 253 result); 254 break; 255 } 256 } 257 258 for (int i = paramstart + 1; i < parameters.size(); i++) { 259 result.add(","); 260 result.add(Text.NL); 261 result.add(" "); 262 263 if (includeAnnotations) { 264 Content annotationInfo 265 = writer.getAnnotationInfo(parameters.get(i), false); 266 if (!annotationInfo.isEmpty()) { 267 result.add(annotationInfo) 268 .add(Text.NL) 269 .add(" "); 270 } 271 } 272 addParam(parameters.get(i), instMeth.getParameterTypes().get(i), 273 (i == parameters.size() - 1) && member.isVarArgs(), 274 result); 275 } 276 result.add(")"); 277 return result; 278 } 279 280 /** 281 * Get the exception information for the executable member. 282 * 283 * @param member the member to get the exception information for 284 * @return the exception information 285 */ 286 protected Content getExceptions(ExecutableElement member) { 287 List<? extends TypeMirror> exceptions = utils 288 .asInstantiatedMethodType(typeElement, member).getThrownTypes(); 289 Content result = new ContentBuilder(); 290 for (TypeMirror t : exceptions) { 291 if (!result.isEmpty()) { 292 result.add(","); 293 result.add(Text.NL); 294 } 295 Content link 296 = writer.getLink(new HtmlLinkInfo(configuration, PLAIN, t)); 297 result.add(link); 298 } 299 return result; 300 } 301 302 protected TypeElement implementsMethodInIntfac(ExecutableElement method, 303 List<TypeElement> intfacs) { 304 for (TypeElement intf : intfacs) { 305 List<ExecutableElement> methods = utils.getMethods(intf); 306 if (!methods.isEmpty()) { 307 for (ExecutableElement md : methods) { 308 if (name(md).equals(name(method)) && 309 md.toString().equals(method.toString())) { 310 return intf; 311 } 312 } 313 } 314 } 315 return null; 316 } 317}