LinkFactory.java revision 3233:b5d08bc0d224
1/* 2 * Copyright (c) 2003, 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.toolkit.util.links; 27 28import java.util.ArrayList; 29import java.util.List; 30 31import javax.lang.model.element.AnnotationMirror; 32import javax.lang.model.element.Element; 33import javax.lang.model.element.TypeElement; 34import javax.lang.model.element.TypeParameterElement; 35import javax.lang.model.type.ArrayType; 36import javax.lang.model.type.DeclaredType; 37import javax.lang.model.type.TypeMirror; 38import javax.lang.model.type.TypeVariable; 39import javax.lang.model.type.WildcardType; 40import javax.lang.model.util.SimpleTypeVisitor9; 41 42import jdk.javadoc.internal.doclets.formats.html.LinkInfoImpl; 43import jdk.javadoc.internal.doclets.toolkit.Content; 44import jdk.javadoc.internal.doclets.toolkit.util.Utils; 45import com.sun.tools.javac.util.DefinedBy; 46import com.sun.tools.javac.util.DefinedBy.Api; 47 48/** 49 * A factory that constructs links from given link information. 50 * 51 * <p><b>This is NOT part of any supported API. 52 * If you write code that depends on this, you do so at your own risk. 53 * This code and its internal interfaces are subject to change or 54 * deletion without notice.</b> 55 * 56 * @author Jamie Ho 57 */ 58public abstract class LinkFactory { 59 60 /** 61 * Return an empty instance of a content object. 62 * 63 * @return an empty instance of a content object. 64 */ 65 protected abstract Content newContent(); 66 67 /** 68 * Constructs a link from the given link information. 69 * 70 * @param linkInfo the information about the link. 71 * @return the output of the link. 72 */ 73 public Content getLink(LinkInfo linkInfo) { 74 Utils utils = ((LinkInfoImpl) linkInfo).configuration.utils; 75 if (linkInfo.type != null) { 76 SimpleTypeVisitor9<Content, LinkInfo> linkVisitor = 77 new SimpleTypeVisitor9<Content, LinkInfo>() { 78 79 TypeMirror componentType = utils.getComponentType(linkInfo.type); 80 Content link = newContent(); 81 82 // handles primitives, no types and error types 83 @Override @DefinedBy(Api.LANGUAGE_MODEL) 84 protected Content defaultAction(TypeMirror type, LinkInfo linkInfo) { 85 link.addContent(utils.getTypeName(type, false)); 86 return link; 87 } 88 89 int currentDepth = 0; 90 @Override @DefinedBy(Api.LANGUAGE_MODEL) 91 public Content visitArray(ArrayType type, LinkInfo linkInfo) { 92 // keep track of the dimension depth and replace the last dimension 93 // specifier with vararags, when the stack is fully unwound. 94 currentDepth++; 95 linkInfo.type = type.getComponentType(); 96 visit(linkInfo.type, linkInfo); 97 currentDepth--; 98 if (utils.isAnnotated(type)) { 99 linkInfo.type = type; 100 link.addContent(" "); 101 link.addContent(getTypeAnnotationLinks(linkInfo)); 102 } 103 // use vararg if required 104 if (linkInfo.isVarArg && currentDepth == 0) { 105 link.addContent("..."); 106 } else { 107 link.addContent("[]"); 108 } 109 return link; 110 } 111 112 @Override @DefinedBy(Api.LANGUAGE_MODEL) 113 public Content visitWildcard(WildcardType type, LinkInfo linkInfo) { 114 linkInfo.isTypeBound = true; 115 link.addContent("?"); 116 TypeMirror extendsBound = type.getExtendsBound(); 117 if (extendsBound != null) { 118 link.addContent(" extends "); 119 setBoundsLinkInfo(linkInfo, extendsBound); 120 link.addContent(getLink(linkInfo)); 121 } 122 TypeMirror superBound = type.getSuperBound(); 123 if (superBound != null) { 124 link.addContent(" super "); 125 setBoundsLinkInfo(linkInfo, superBound); 126 link.addContent(getLink(linkInfo)); 127 } 128 return link; 129 } 130 131 @Override @DefinedBy(Api.LANGUAGE_MODEL) 132 public Content visitTypeVariable(TypeVariable type, LinkInfo linkInfo) { 133 link.addContent(getTypeAnnotationLinks(linkInfo)); 134 linkInfo.isTypeBound = true; 135 TypeVariable typevariable = (utils.isArrayType(type)) 136 ? (TypeVariable) componentType 137 : type; 138 Element owner = typevariable.asElement().getEnclosingElement(); 139 if ((!linkInfo.excludeTypeParameterLinks) && utils.isTypeElement(owner)) { 140 linkInfo.typeElement = (TypeElement) owner; 141 Content label = newContent(); 142 label.addContent(utils.getTypeName(type, false)); 143 linkInfo.label = label; 144 link.addContent(getClassLink(linkInfo)); 145 } else { 146 // No need to link method type parameters. 147 link.addContent(utils.getTypeName(typevariable, false)); 148 } 149 150 if (!linkInfo.excludeTypeBounds) { 151 linkInfo.excludeTypeBounds = true; 152 TypeParameterElement tpe = ((TypeParameterElement) typevariable.asElement()); 153 boolean more = false; 154 List<? extends TypeMirror> bounds = utils.getBounds(tpe); 155 for (TypeMirror bound : bounds) { 156 // we get everything as extends java.lang.Object we suppress 157 // all of them except those that have multiple extends 158 if (bounds.size() == 1 && 159 bound.equals(utils.getObjectType()) && 160 !utils.isAnnotated(bound)) { 161 continue; 162 } 163 link.addContent(more ? " & " : " extends "); 164 setBoundsLinkInfo(linkInfo, bound); 165 link.addContent(getLink(linkInfo)); 166 more = true; 167 } 168 } 169 return link; 170 } 171 172 @Override @DefinedBy(Api.LANGUAGE_MODEL) 173 public Content visitDeclared(DeclaredType type, LinkInfo linkInfo) { 174 if (linkInfo.isTypeBound && linkInfo.excludeTypeBoundsLinks) { 175 // Since we are excluding type parameter links, we should not 176 // be linking to the type bound. 177 link.addContent(utils.getTypeName(type, false)); 178 link.addContent(getTypeParameterLinks(linkInfo)); 179 return link; 180 } else { 181 link = newContent(); 182 link.addContent(getTypeAnnotationLinks(linkInfo)); 183 linkInfo.typeElement = utils.asTypeElement(type); 184 link.addContent(getClassLink(linkInfo)); 185 if (linkInfo.includeTypeAsSepLink) { 186 link.addContent(getTypeParameterLinks(linkInfo, false)); 187 } 188 } 189 return link; 190 } 191 }; 192 return linkVisitor.visit(linkInfo.type, linkInfo); 193 } else if (linkInfo.typeElement != null) { 194 Content link = newContent(); 195 link.addContent(getClassLink(linkInfo)); 196 if (linkInfo.includeTypeAsSepLink) { 197 link.addContent(getTypeParameterLinks(linkInfo, false)); 198 } 199 return link; 200 } else { 201 return null; 202 } 203 } 204 205 private void setBoundsLinkInfo(LinkInfo linkInfo, TypeMirror bound) { 206 linkInfo.typeElement = null; 207 linkInfo.label = null; 208 linkInfo.type = bound; 209 } 210 211 /** 212 * Return the link to the given class. 213 * 214 * @param linkInfo the information about the link to construct. 215 * 216 * @return the link for the given class. 217 */ 218 protected abstract Content getClassLink(LinkInfo linkInfo); 219 220 /** 221 * Return the link to the given type parameter. 222 * 223 * @param linkInfo the information about the link to construct. 224 * @param typeParam the type parameter to link to. 225 */ 226 protected abstract Content getTypeParameterLink(LinkInfo linkInfo, TypeMirror typeParam); 227 228 protected abstract Content getTypeAnnotationLink(LinkInfo linkInfo, AnnotationMirror annotation); 229 230 /** 231 * Return the links to the type parameters. 232 * 233 * @param linkInfo the information about the link to construct. 234 * @return the links to the type parameters. 235 */ 236 public Content getTypeParameterLinks(LinkInfo linkInfo) { 237 return getTypeParameterLinks(linkInfo, true); 238 } 239 240 /** 241 * Return the links to the type parameters. 242 * 243 * @param linkInfo the information about the link to construct. 244 * @param isClassLabel true if this is a class label. False if it is 245 * the type parameters portion of the link. 246 * @return the links to the type parameters. 247 */ 248 public Content getTypeParameterLinks(LinkInfo linkInfo, boolean isClassLabel) { 249 Utils utils = ((LinkInfoImpl)linkInfo).utils; 250 Content links = newContent(); 251 List<TypeMirror> vars = new ArrayList<>(); 252 TypeMirror ctype = linkInfo.type != null 253 ? utils.getComponentType(linkInfo.type) 254 : null; 255 if (linkInfo.executableElement != null) { 256 linkInfo.executableElement.getTypeParameters().stream().forEach((t) -> { 257 vars.add(t.asType()); 258 }); 259 } else if (linkInfo.type != null && utils.isDeclaredType(linkInfo.type)) { 260 ((DeclaredType)linkInfo.type).getTypeArguments().stream().forEach((t) -> { 261 vars.add(t); 262 }); 263 } else if (ctype != null && utils.isDeclaredType(ctype)) { 264 ((DeclaredType)ctype).getTypeArguments().stream().forEach((t) -> { 265 vars.add(t); 266 }); 267 } else if (linkInfo.typeElement != null) { 268 linkInfo.typeElement.getTypeParameters().stream().forEach((t) -> { 269 vars.add(t.asType()); 270 }); 271 } else { 272 // Nothing to document. 273 return links; 274 } 275 if (((linkInfo.includeTypeInClassLinkLabel && isClassLabel) 276 || (linkInfo.includeTypeAsSepLink && !isClassLabel)) && !vars.isEmpty()) { 277 links.addContent("<"); 278 boolean many = false; 279 for (TypeMirror t : vars) { 280 if (many) { 281 links.addContent(","); 282 } 283 links.addContent(getTypeParameterLink(linkInfo, t)); 284 many = true; 285 } 286 links.addContent(">"); 287 } 288 return links; 289 } 290 291 public Content getTypeAnnotationLinks(LinkInfo linkInfo) { 292 Utils utils = ((LinkInfoImpl)linkInfo).utils; 293 Content links = newContent(); 294 if (!utils.isAnnotated(linkInfo.type)) 295 return links; 296 297 List<? extends AnnotationMirror> annotations = linkInfo.type.getAnnotationMirrors(); 298 boolean needSpace = false; 299 for (AnnotationMirror anno : annotations) { 300 if (needSpace) { 301 links.addContent(" "); 302 } 303 links.addContent(getTypeAnnotationLink(linkInfo, anno)); 304 needSpace = true; 305 } 306 307 links.addContent(" "); 308 return links; 309 } 310} 311