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