8303895: Simplify and clean up LinkFactory code

Reviewed-by: prappo
This commit is contained in:
Hannes Wallnöfer 2023-03-14 16:20:35 +00:00
parent a00f5d24d3
commit 9f9ab02ff6
9 changed files with 497 additions and 531 deletions

View File

@ -72,9 +72,9 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite
* @return the type parameters.
*/
protected Content getTypeParameters(ExecutableElement member) {
HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration, LINK_TYPE_PARAMS_AND_BOUNDS, member);
linkInfo.addLineBreaksInTypeParameters = true;
linkInfo.showTypeParameterAnnotations = true;
HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration, LINK_TYPE_PARAMS_AND_BOUNDS, member)
.addLineBreaksInTypeParameters(true)
.showTypeParameterAnnotations(true);
return writer.getTypeParameterLinks(linkInfo);
}
@ -121,9 +121,9 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite
*/
protected void addParam(VariableElement param, TypeMirror paramType, boolean isVarArg,
Content target) {
HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration, LINK_TYPE_PARAMS,
paramType).varargs(isVarArg);
linkInfo.showTypeParameterAnnotations = true;
HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration, LINK_TYPE_PARAMS, paramType)
.varargs(isVarArg)
.showTypeParameterAnnotations(true);
Content link = writer.getLink(linkInfo);
target.add(link);
if(name(param).length() > 0) {
@ -142,8 +142,8 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite
* @param target the content to which the information will be added.
*/
protected void addReceiver(ExecutableElement member, TypeMirror rcvrType, Content target) {
var info = new HtmlLinkInfo(configuration, SHOW_TYPE_PARAMS_AND_BOUNDS, rcvrType);
info.linkToSelf = false;
var info = new HtmlLinkInfo(configuration, SHOW_TYPE_PARAMS_AND_BOUNDS, rcvrType)
.linkToSelf(false);
target.add(writer.getLink(info));
target.add(Entity.NO_BREAK_SPACE);
if (member.getKind() == ElementKind.CONSTRUCTOR) {

View File

@ -115,9 +115,8 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
div.add(pkgNameDiv);
}
HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration,
HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_AND_BOUNDS, typeElement);
//Let's not link to ourselves in the header.
linkInfo.linkToSelf = false;
HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_AND_BOUNDS, typeElement)
.linkToSelf(false); // Let's not link to ourselves in the header
var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING,
HtmlStyle.title, Text.of(header));
heading.add(getTypeParameterLinks(linkInfo));

View File

@ -1787,7 +1787,7 @@ public class HtmlDocletWriter {
ContentBuilder annotation,
Map<? extends ExecutableElement, ? extends AnnotationValue> map,
boolean linkBreak) {
linkInfo.label = Text.of("@" + annotationDoc.getSimpleName());
linkInfo.label("@" + annotationDoc.getSimpleName());
annotation.add(getLink(linkInfo));
if (!map.isEmpty()) {
annotation.add("(");
@ -1903,7 +1903,7 @@ public class HtmlDocletWriter {
String name = utils.isIncluded(t.asElement())
? t.asElement().getSimpleName().toString()
: utils.getFullyQualifiedName(t.asElement());
linkInfo.label = Text.of(name + utils.getDimension(t) + ".class");
linkInfo.label(name + utils.getDimension(t) + ".class");
return getLink(linkInfo);
}
@Override

View File

@ -33,8 +33,13 @@ import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.SimpleTypeVisitor14;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
@ -45,59 +50,200 @@ import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.Resources;
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
import jdk.javadoc.internal.doclets.toolkit.util.Utils.ElementFlag;
import jdk.javadoc.internal.doclets.toolkit.util.links.LinkFactory;
import jdk.javadoc.internal.doclets.toolkit.util.links.LinkInfo;
/**
* A factory that returns a link given the information about it.
*/
public class HtmlLinkFactory extends LinkFactory {
public class HtmlLinkFactory {
private final HtmlDocletWriter m_writer;
private final DocPaths docPaths;
private final Utils utils;
/**
* Constructs a new link factory.
*
* @param writer the HTML doclet writer
*/
public HtmlLinkFactory(HtmlDocletWriter writer) {
super(writer.configuration.utils);
m_writer = writer;
docPaths = writer.configuration.docPaths;
utils = writer.configuration.utils;
}
@Override
/**
* {@return a new instance of a content object}
*/
protected Content newContent() {
return new ContentBuilder();
}
@Override
protected Content getClassLink(LinkInfo linkInfo) {
/**
* Constructs a link from the given link information.
*
* @param linkInfo the information about the link.
* @return the link.
*/
public Content getLink(HtmlLinkInfo linkInfo) {
if (linkInfo.getType() != null) {
SimpleTypeVisitor14<Content, HtmlLinkInfo> linkVisitor = new SimpleTypeVisitor14<>() {
final Content link = newContent();
// handles primitives, no types and error types
@Override
protected Content defaultAction(TypeMirror type, HtmlLinkInfo linkInfo) {
link.add(utils.getTypeName(type, false));
return link;
}
int currentDepth = 0;
@Override
public Content visitArray(ArrayType type, HtmlLinkInfo linkInfo) {
// keep track of the dimension depth and replace the last dimension
// specifier with varargs, when the stack is fully unwound.
currentDepth++;
var componentType = type.getComponentType();
visit(componentType, linkInfo.forType(componentType));
currentDepth--;
if (utils.isAnnotated(type)) {
link.add(" ");
link.add(getTypeAnnotationLinks(linkInfo));
}
// use vararg if required
if (linkInfo.isVarArg() && currentDepth == 0) {
link.add("...");
} else {
link.add("[]");
}
return link;
}
@Override
public Content visitWildcard(WildcardType type, HtmlLinkInfo linkInfo) {
link.add(getTypeAnnotationLinks(linkInfo));
link.add("?");
TypeMirror extendsBound = type.getExtendsBound();
if (extendsBound != null) {
link.add(" extends ");
link.add(getLink(getBoundsLinkInfo(linkInfo, extendsBound)));
}
TypeMirror superBound = type.getSuperBound();
if (superBound != null) {
link.add(" super ");
link.add(getLink(getBoundsLinkInfo(linkInfo, superBound)));
}
return link;
}
@Override
public Content visitTypeVariable(TypeVariable type, HtmlLinkInfo linkInfo) {
link.add(getTypeAnnotationLinks(linkInfo));
TypeVariable typevariable = (utils.isArrayType(type))
? (TypeVariable) utils.getComponentType(type)
: type;
Element owner = typevariable.asElement().getEnclosingElement();
if (linkInfo.linkTypeParameters() && utils.isTypeElement(owner)) {
linkInfo.setTypeElement((TypeElement) owner);
Content label = newContent();
label.add(utils.getTypeName(type, false));
linkInfo.label(label).skipPreview(true);
link.add(getClassLink(linkInfo));
} else {
// No need to link method type parameters.
link.add(utils.getTypeName(typevariable, false));
}
if (linkInfo.showTypeBounds()) {
linkInfo.showTypeBounds(false);
TypeParameterElement tpe = ((TypeParameterElement) typevariable.asElement());
boolean more = false;
List<? extends TypeMirror> bounds = utils.getBounds(tpe);
for (TypeMirror bound : bounds) {
// we get everything as extends java.lang.Object we suppress
// all of them except those that have multiple extends
if (bounds.size() == 1 &&
utils.typeUtils.isSameType(bound, utils.getObjectType()) &&
!utils.isAnnotated(bound)) {
continue;
}
link.add(more ? " & " : " extends ");
link.add(getLink(getBoundsLinkInfo(linkInfo, bound)));
more = true;
}
}
return link;
}
@Override
public Content visitDeclared(DeclaredType type, HtmlLinkInfo linkInfo) {
TypeMirror enc = type.getEnclosingType();
if (enc instanceof DeclaredType dt && utils.isGenericType(dt)) {
// If an enclosing type has type parameters render them as separate links as
// otherwise this information is lost. On the other hand, plain enclosing types
// are not linked separately as they are easy to reach from the nested type.
visitDeclared(dt, linkInfo.forType(dt));
link.add(".");
}
link.add(getTypeAnnotationLinks(linkInfo));
linkInfo.setTypeElement(utils.asTypeElement(type));
link.add(getClassLink(linkInfo));
if (linkInfo.showTypeParameters()) {
link.add(getTypeParameterLinks(linkInfo));
}
return link;
}
};
return linkVisitor.visit(linkInfo.getType(), linkInfo);
} else if (linkInfo.getTypeElement() != null) {
Content link = newContent();
link.add(getClassLink(linkInfo));
if (linkInfo.showTypeParameters()) {
link.add(getTypeParameterLinks(linkInfo));
}
return link;
} else {
return null;
}
}
/**
* Returns a link to the given class.
*
* @param linkInfo the information about the link to construct
* @return the link for the given class.
*/
protected Content getClassLink(HtmlLinkInfo linkInfo) {
BaseConfiguration configuration = m_writer.configuration;
HtmlLinkInfo classLinkInfo = (HtmlLinkInfo) linkInfo;
TypeElement typeElement = classLinkInfo.typeElement;
TypeElement typeElement = linkInfo.getTypeElement();
// Create a tool tip if we are linking to a class or interface. Don't
// create one if we are linking to a member.
String title = "";
boolean hasWhere = classLinkInfo.fragment != null && classLinkInfo.fragment.length() != 0;
if (!hasWhere) {
boolean isTypeLink = classLinkInfo.type != null &&
utils.isTypeVariable(utils.getComponentType(classLinkInfo.type));
String fragment = linkInfo.getFragment();
boolean hasFragment = fragment != null && !fragment.isEmpty();
if (!hasFragment) {
boolean isTypeLink = linkInfo.getType() != null &&
utils.isTypeVariable(utils.getComponentType(linkInfo.getType()));
title = getClassToolTip(typeElement, isTypeLink);
}
Content label = classLinkInfo.getClassLinkLabel(configuration);
if (classLinkInfo.context == HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_IN_LABEL) {
Content label = linkInfo.getClassLinkLabel(configuration);
if (linkInfo.getContext() == HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_IN_LABEL) {
// For this kind of link, type parameters are included in the link label
// (and obviously not added after the link).
label.add(getTypeParameterLinks(classLinkInfo));
label.add(getTypeParameterLinks(linkInfo));
}
Set<ElementFlag> flags;
Element previewTarget;
boolean showPreview = !classLinkInfo.skipPreview;
if (!hasWhere && showPreview) {
boolean showPreview = !linkInfo.isSkipPreview();
if (!hasFragment && showPreview) {
flags = utils.elementFlags(typeElement);
previewTarget = typeElement;
} else if (classLinkInfo.context == HtmlLinkInfo.Kind.SHOW_PREVIEW
&& classLinkInfo.targetMember != null && showPreview) {
flags = utils.elementFlags(classLinkInfo.targetMember);
TypeElement enclosing = utils.getEnclosingTypeElement(classLinkInfo.targetMember);
} else if (linkInfo.getContext() == HtmlLinkInfo.Kind.SHOW_PREVIEW
&& linkInfo.getTargetMember() != null && showPreview) {
flags = utils.elementFlags(linkInfo.getTargetMember());
TypeElement enclosing = utils.getEnclosingTypeElement(linkInfo.getTargetMember());
Set<ElementFlag> enclosingFlags = utils.elementFlags(enclosing);
if (flags.contains(ElementFlag.PREVIEW) && enclosingFlags.contains(ElementFlag.PREVIEW)) {
if (enclosing.equals(m_writer.getCurrentPageElement())) {
@ -107,7 +253,7 @@ public class HtmlLinkFactory extends LinkFactory {
}
previewTarget = enclosing;
} else {
previewTarget = classLinkInfo.targetMember;
previewTarget = linkInfo.getTargetMember();
}
} else {
flags = EnumSet.noneOf(ElementFlag.class);
@ -117,12 +263,12 @@ public class HtmlLinkFactory extends LinkFactory {
Content link = new ContentBuilder();
if (utils.isIncluded(typeElement)) {
if (configuration.isGeneratedDoc(typeElement) && !utils.hasHiddenTag(typeElement)) {
DocPath filename = getPath(classLinkInfo);
if (linkInfo.linkToSelf || typeElement != m_writer.getCurrentPageElement()) {
DocPath filename = getPath(linkInfo);
if (linkInfo.linkToSelf() || typeElement != m_writer.getCurrentPageElement()) {
link.add(m_writer.links.createLink(
filename.fragment(classLinkInfo.fragment),
filename.fragment(linkInfo.getFragment()),
label,
classLinkInfo.style,
linkInfo.getStyle(),
title));
if (flags.contains(ElementFlag.PREVIEW)) {
link.add(HtmlTree.SUP(m_writer.links.createLink(
@ -134,8 +280,8 @@ public class HtmlLinkFactory extends LinkFactory {
}
} else {
Content crossLink = m_writer.getCrossClassLink(
typeElement, classLinkInfo.fragment,
label, classLinkInfo.style, true);
typeElement, linkInfo.getFragment(),
label, linkInfo.getStyle(), true);
if (crossLink != null) {
link.add(crossLink);
if (flags.contains(ElementFlag.PREVIEW)) {
@ -156,21 +302,26 @@ public class HtmlLinkFactory extends LinkFactory {
return link;
}
@Override
protected Content getTypeParameterLinks(LinkInfo linkInfo) {
/**
* Returns links to the type parameters.
*
* @param linkInfo the information about the link to construct
* @return the links to the type parameters
*/
protected Content getTypeParameterLinks(HtmlLinkInfo linkInfo) {
Content links = newContent();
List<TypeMirror> vars = new ArrayList<>();
TypeMirror ctype = linkInfo.type != null
? utils.getComponentType(linkInfo.type)
TypeMirror ctype = linkInfo.getType() != null
? utils.getComponentType(linkInfo.getType())
: null;
if (linkInfo.executableElement != null) {
linkInfo.executableElement.getTypeParameters().forEach(t -> vars.add(t.asType()));
} else if (linkInfo.type != null && utils.isDeclaredType(linkInfo.type)) {
vars.addAll(((DeclaredType) linkInfo.type).getTypeArguments());
if (linkInfo.getExecutableElement() != null) {
linkInfo.getExecutableElement().getTypeParameters().forEach(t -> vars.add(t.asType()));
} else if (linkInfo.getType() != null && utils.isDeclaredType(linkInfo.getType())) {
vars.addAll(((DeclaredType) linkInfo.getType()).getTypeArguments());
} else if (ctype != null && utils.isDeclaredType(ctype)) {
vars.addAll(((DeclaredType) ctype).getTypeArguments());
} else if (ctype == null && linkInfo.typeElement != null) {
linkInfo.typeElement.getTypeParameters().forEach(t -> vars.add(t.asType()));
} else if (ctype == null && linkInfo.getTypeElement() != null) {
linkInfo.getTypeElement().getTypeParameters().forEach(t -> vars.add(t.asType()));
} else {
// Nothing to document.
return links;
@ -182,11 +333,11 @@ public class HtmlLinkFactory extends LinkFactory {
if (many) {
links.add(",");
links.add(new HtmlTree(TagName.WBR));
if (linkInfo.addLineBreaksInTypeParameters) {
if (linkInfo.addLineBreaksInTypeParameters()) {
links.add(Text.NL);
}
}
links.add(getTypeParameterLink(linkInfo, t));
links.add(getLink(linkInfo.forType(t)));
many = true;
}
links.add(">");
@ -195,31 +346,18 @@ public class HtmlLinkFactory extends LinkFactory {
}
/**
* Returns a link to the given type parameter.
* Returns links to the type annotations.
*
* @param linkInfo the information about the link to construct
* @param typeParam the type parameter to link to
* @return the link
* @param linkInfo the information about the link to construct
* @return the links to the type annotations
*/
protected Content getTypeParameterLink(LinkInfo linkInfo, TypeMirror typeParam) {
HtmlLinkInfo typeLinkInfo = new HtmlLinkInfo(m_writer.configuration,
((HtmlLinkInfo) linkInfo).getContext(), typeParam);
typeLinkInfo.showTypeBounds = linkInfo.showTypeBounds;
typeLinkInfo.linkTypeParameters = linkInfo.linkTypeParameters;
typeLinkInfo.linkToSelf = linkInfo.linkToSelf;
typeLinkInfo.addLineBreaksInTypeParameters = linkInfo.addLineBreaksInTypeParameters;
typeLinkInfo.showTypeParameterAnnotations = linkInfo.showTypeParameterAnnotations;
return getLink(typeLinkInfo);
}
@Override
public Content getTypeAnnotationLinks(LinkInfo linkInfo) {
public Content getTypeAnnotationLinks(HtmlLinkInfo linkInfo) {
ContentBuilder links = new ContentBuilder();
List<? extends AnnotationMirror> annotations;
if (utils.isAnnotated(linkInfo.type)) {
annotations = linkInfo.type.getAnnotationMirrors();
} else if (utils.isTypeVariable(linkInfo.type) && linkInfo.showTypeParameterAnnotations) {
Element element = utils.typeUtils.asElement(linkInfo.type);
if (utils.isAnnotated(linkInfo.getType())) {
annotations = linkInfo.getType().getAnnotationMirrors();
} else if (utils.isTypeVariable(linkInfo.getType()) && linkInfo.showTypeParameterAnnotations()) {
Element element = utils.typeUtils.asElement(linkInfo.getType());
annotations = element.getAnnotationMirrors();
} else {
return links;
@ -237,6 +375,13 @@ public class HtmlLinkFactory extends LinkFactory {
return links;
}
/*
* Returns a link info for a type bounds link.
*/
private HtmlLinkInfo getBoundsLinkInfo(HtmlLinkInfo linkInfo, TypeMirror bound) {
return linkInfo.forType(bound).skipPreview(false);
}
/**
* Given a class, return the appropriate tool tip.
*
@ -272,6 +417,6 @@ public class HtmlLinkFactory extends LinkFactory {
* @param linkInfo the information about the link.
*/
private DocPath getPath(HtmlLinkInfo linkInfo) {
return m_writer.pathToRoot.resolve(docPaths.forClass(linkInfo.typeElement));
return m_writer.pathToRoot.resolve(docPaths.forClass(linkInfo.getTypeElement()));
}
}

View File

@ -28,20 +28,21 @@ package jdk.javadoc.internal.doclets.formats.html;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
import jdk.javadoc.internal.doclets.toolkit.util.links.LinkInfo;
/**
* HTML-specific information about a link.
*/
public class HtmlLinkInfo extends LinkInfo {
public class HtmlLinkInfo {
/**
* Enumeration of different kinds of links.
@ -79,29 +80,53 @@ public class HtmlLinkInfo extends LinkInfo {
LINK_TYPE_PARAMS_AND_BOUNDS;
}
public final HtmlConfiguration configuration;
private final HtmlConfiguration configuration;
/**
* The context of the link.
*/
public Kind context = Kind.PLAIN;
// The context of the link.
private Kind context = Kind.PLAIN;
/**
* The fragment of the link.
*/
public String fragment = "";
// The fragment of the link.
private String fragment = "";
/**
* The member this link points to (if any).
*/
public Element targetMember;
// The member this link points to (if any).
private Element targetMember;
/**
* Optional style for the link.
*/
public HtmlStyle style = null;
// Optional style for the link.
private HtmlStyle style = null;
public final Utils utils;
// The class we want to link to. Null if we are not linking to a class.
private TypeElement typeElement;
// The executable element we want to link to. Null if we are not linking to an executable element.
private ExecutableElement executableElement;
// The Type we want to link to. Null if we are not linking to a type.
private TypeMirror type;
// True if this is a link to a VarArg.
private boolean isVarArg = false;
// The label for the link.
private Content label;
// True if we should print the type bounds for the type parameter.
private boolean showTypeBounds = true;
// True if type parameters should be rendered as links.
private boolean linkTypeParameters = true;
// By default, the link can be to the page it's already on. However,
// there are cases where we don't want this (e.g. heading of class page).
private boolean linkToSelf = true;
// True iff the preview flags should be skipped for this link.
private boolean skipPreview;
// True if type parameters should be separated by line breaks.
private boolean addLineBreaksInTypeParameters = false;
// True if annotations on type parameters should be shown.
private boolean showTypeParameterAnnotations = false;
/**
* Construct a LinkInfo object.
@ -112,16 +137,10 @@ public class HtmlLinkInfo extends LinkInfo {
*/
public HtmlLinkInfo(HtmlConfiguration configuration, Kind context, ExecutableElement ee) {
this.configuration = configuration;
this.utils = configuration.utils;
this.executableElement = ee;
setContext(context);
}
@Override
protected Content newContent() {
return new ContentBuilder();
}
/**
* Construct a LinkInfo object.
*
@ -131,7 +150,6 @@ public class HtmlLinkInfo extends LinkInfo {
*/
public HtmlLinkInfo(HtmlConfiguration configuration, Kind context, TypeElement typeElement) {
this.configuration = configuration;
this.utils = configuration.utils;
this.typeElement = typeElement;
setContext(context);
}
@ -145,14 +163,63 @@ public class HtmlLinkInfo extends LinkInfo {
*/
public HtmlLinkInfo(HtmlConfiguration configuration, Kind context, TypeMirror type) {
this.configuration = configuration;
this.utils = configuration.utils;
this.type = type;
setContext(context);
}
/**
* Creates a copy of this HtmlLinkInfo instance with a different TypeMirror.
* This is used for contained types such as type parameters or array components.
*
* @param type the type mirror
* @return the new link info
*/
public HtmlLinkInfo forType(TypeMirror type) {
HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration, context, type);
linkInfo.showTypeBounds = showTypeBounds;
linkInfo.linkTypeParameters = linkTypeParameters;
linkInfo.linkToSelf = linkToSelf;
linkInfo.addLineBreaksInTypeParameters = addLineBreaksInTypeParameters;
linkInfo.showTypeParameterAnnotations = showTypeParameterAnnotations;
linkInfo.skipPreview = skipPreview;
return linkInfo;
}
/**
* Sets the typeElement
* @param typeElement the new typeElement object
*/
public void setTypeElement(TypeElement typeElement) {
this.typeElement = typeElement;
}
/**
* The class we want to link to. Null if we are not linking
* to a class.
*/
public TypeElement getTypeElement() {
return typeElement;
}
/**
* The executable element we want to link to. Null if we are not linking
* to an executable element.
*/
public ExecutableElement getExecutableElement() {
return executableElement;
}
/**
* The Type we want to link to. Null if we are not linking to a type.
*/
public TypeMirror getType() {
return type;
}
/**
* Set the label for the link.
* @param label plain-text label for the link
* @return this object
*/
public HtmlLinkInfo label(CharSequence label) {
this.label = Text.of(label);
@ -161,52 +228,182 @@ public class HtmlLinkInfo extends LinkInfo {
/**
* Set the label for the link.
* @param label the new value
* @return this object
*/
public HtmlLinkInfo label(Content label) {
this.label = label;
return this;
}
/**
* {@return the label for the link}
*/
public Content getLabel() {
return label;
}
/**
* Sets the style to be used for the link.
* @param style the new style value
* @return this object
*/
public HtmlLinkInfo style(HtmlStyle style) {
this.style = style;
return this;
}
/**
* {@return the optional style for the link}
*/
public HtmlStyle getStyle() {
return style;
}
/**
* Set whether or not this is a link to a varargs parameter.
* @param varargs the new value
* @return this object
*/
public HtmlLinkInfo varargs(boolean varargs) {
this.isVarArg = varargs;
return this;
}
/**
* {@return true if this is a link to a vararg member}
*/
public boolean isVarArg() {
return isVarArg;
}
/**
* Set the fragment specifier for the link.
* @param fragment the new fragment value
* @return this object
*/
public HtmlLinkInfo fragment(String fragment) {
this.fragment = fragment;
return this;
}
/**
* {@return the fragment of the link}
*/
public String getFragment() {
return fragment;
}
/**
* Sets the addLineBreaksInTypeParameters flag for this link.
* @param addLineBreaksInTypeParameters the new value
* @return this object
*/
public HtmlLinkInfo addLineBreaksInTypeParameters(boolean addLineBreaksInTypeParameters) {
this.addLineBreaksInTypeParameters = addLineBreaksInTypeParameters;
return this;
}
/**
* {@return true if type parameters should be separated by line breaks}
*/
public boolean addLineBreaksInTypeParameters() {
return addLineBreaksInTypeParameters;
}
/**
* Set the linkToSelf flag for this link.
* @param linkToSelf the new value
* @return this object
*/
public HtmlLinkInfo linkToSelf(boolean linkToSelf) {
this.linkToSelf = linkToSelf;
return this;
}
/**
* {@return true if we should generate links to the current page}
*/
public boolean linkToSelf() {
return linkToSelf;
}
/**
* {@return true if type parameters should be rendered as links}
*/
public boolean linkTypeParameters() {
return linkTypeParameters;
}
/**
* Set the showTypeBounds flag for this link
* @param showTypeBounds the new value
*/
public void showTypeBounds(boolean showTypeBounds) {
this.showTypeBounds = showTypeBounds;
}
/**
* {@return true if we should print the type bounds for the type parameter}
*/
public boolean showTypeBounds() {
return showTypeBounds;
}
/**
* Set the showTypeParameterAnnotations flag for this link.
* @param showTypeParameterAnnotations the new value
* @return this object
*/
public HtmlLinkInfo showTypeParameterAnnotations(boolean showTypeParameterAnnotations) {
this.showTypeParameterAnnotations = showTypeParameterAnnotations;
return this;
}
/**
* {@return true if annotations on type parameters should be shown}
*/
public boolean showTypeParameterAnnotations() {
return showTypeParameterAnnotations;
}
/**
* Set the member this link points to (if any).
* @param el the new member value
* @return this object
*/
public HtmlLinkInfo targetMember(Element el) {
this.targetMember = el;
return this;
}
/**
* {@return the member this link points to (if any)}
*/
public Element getTargetMember() {
return targetMember;
}
/**
* Set whether or not the preview flags should be skipped for this link.
* @param skipPreview the new value
* @return this object
*/
public HtmlLinkInfo skipPreview(boolean skipPreview) {
this.skipPreview = skipPreview;
return this;
}
/**
* {@return true iff the preview flags should be skipped for this link}
*/
public boolean isSkipPreview() {
return skipPreview;
}
/**
* {@return the link context}
*/
public Kind getContext() {
return context;
}
@ -217,7 +414,7 @@ public class HtmlLinkInfo extends LinkInfo {
*
* @param c the context id to set.
*/
public final void setContext(Kind c) {
private void setContext(Kind c) {
linkTypeParameters = c == Kind.LINK_TYPE_PARAMS || c == Kind.LINK_TYPE_PARAMS_AND_BOUNDS;
showTypeBounds = c == Kind.SHOW_TYPE_PARAMS_AND_BOUNDS || c == Kind.LINK_TYPE_PARAMS_AND_BOUNDS;
context = c;
@ -230,12 +427,15 @@ public class HtmlLinkInfo extends LinkInfo {
* @return true if this link is linkable and false if we can't link to the
* desired place.
*/
@Override
public boolean isLinkable() {
return configuration.utils.isLinkable(typeElement);
}
@Override
/**
* Returns true if links to declared types should include type parameters.
*
* @return true if type parameter links should be included
*/
public boolean showTypeParameters() {
// Type parameters for these kinds of links are either not desired
// or already included in the link label.
@ -243,12 +443,52 @@ public class HtmlLinkInfo extends LinkInfo {
&& context != Kind.SHOW_TYPE_PARAMS_IN_LABEL;
}
/**
* Return the label for this class link.
*
* @param configuration the current configuration of the doclet.
* @return the label for this class link.
*/
public Content getClassLinkLabel(BaseConfiguration configuration) {
if (label != null && !label.isEmpty()) {
return label;
} else if (isLinkable()) {
Content tlabel = newContent();
Utils utils = configuration.utils;
tlabel.add(type instanceof DeclaredType dt && utils.isGenericType(dt.getEnclosingType())
// If enclosing type is rendered as separate links only use own class name
? typeElement.getSimpleName().toString()
: configuration.utils.getSimpleName(typeElement));
return tlabel;
} else {
Content tlabel = newContent();
tlabel.add(configuration.getClassName(typeElement));
return tlabel;
}
}
/**
* {@return a new instance of a content object}
*/
protected Content newContent() {
return new ContentBuilder();
}
@Override
public String toString() {
return "HtmlLinkInfo{" +
"context=" + context +
"typeElement=" + typeElement +
", executableElement=" + executableElement +
", type=" + type +
", isVarArg=" + isVarArg +
", label=" + label +
", showTypeBounds=" + showTypeBounds +
", linkTypeParameters=" + linkTypeParameters +
", linkToSelf=" + linkToSelf +
", addLineBreaksInTypeParameters=" + addLineBreaksInTypeParameters +
", showTypeParameterAnnotations=" + showTypeParameterAnnotations +
", context=" + context +
", fragment=" + fragment +
", style=" + style +
super.toString() + '}';
", style=" + style + '}';
}
}

View File

@ -135,10 +135,9 @@ public class Signatures {
nameSpan.addStyle(HtmlStyle.typeNameLabel).add(className);
}
HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration,
HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_AND_BOUNDS, typeElement);
linkInfo.showTypeParameterAnnotations = true;
//Let's not link to ourselves in the signature.
linkInfo.linkToSelf = false;
HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_AND_BOUNDS, typeElement)
.linkToSelf(false) // Let's not link to ourselves in the signature
.showTypeParameterAnnotations(true);
nameSpan.add(writer.getTypeParameterLinks(linkInfo));
content.add(nameSpan);

View File

@ -1,230 +0,0 @@
/*
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.javadoc.internal.doclets.toolkit.util.links;
import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.SimpleTypeVisitor14;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
/**
* A factory that constructs links from given link information.
*/
public abstract class LinkFactory {
protected final Utils utils;
protected LinkFactory(Utils utils) {
this.utils = utils;
}
/**
* {@return a new instance of a content object}
*/
protected abstract Content newContent();
/**
* Constructs a link from the given link information.
*
* @param linkInfo the information about the link.
* @return the link.
*/
public Content getLink(LinkInfo linkInfo) {
if (linkInfo.type != null) {
SimpleTypeVisitor14<Content, LinkInfo> linkVisitor = new SimpleTypeVisitor14<>() {
final Content link = newContent();
// handles primitives, no types and error types
@Override
protected Content defaultAction(TypeMirror type, LinkInfo linkInfo) {
link.add(utils.getTypeName(type, false));
return link;
}
int currentDepth = 0;
@Override
public Content visitArray(ArrayType type, LinkInfo linkInfo) {
// keep track of the dimension depth and replace the last dimension
// specifier with varargs, when the stack is fully unwound.
currentDepth++;
linkInfo.type = type.getComponentType();
visit(linkInfo.type, linkInfo);
currentDepth--;
if (utils.isAnnotated(type)) {
linkInfo.type = type;
link.add(" ");
link.add(getTypeAnnotationLinks(linkInfo));
}
// use vararg if required
if (linkInfo.isVarArg && currentDepth == 0) {
link.add("...");
} else {
link.add("[]");
}
return link;
}
@Override
public Content visitWildcard(WildcardType type, LinkInfo linkInfo) {
link.add(getTypeAnnotationLinks(linkInfo));
link.add("?");
TypeMirror extendsBound = type.getExtendsBound();
if (extendsBound != null) {
link.add(" extends ");
setBoundsLinkInfo(linkInfo, extendsBound);
link.add(getLink(linkInfo));
}
TypeMirror superBound = type.getSuperBound();
if (superBound != null) {
link.add(" super ");
setBoundsLinkInfo(linkInfo, superBound);
link.add(getLink(linkInfo));
}
return link;
}
@Override
public Content visitTypeVariable(TypeVariable type, LinkInfo linkInfo) {
link.add(getTypeAnnotationLinks(linkInfo));
TypeVariable typevariable = (utils.isArrayType(type))
? (TypeVariable) utils.getComponentType(type)
: type;
Element owner = typevariable.asElement().getEnclosingElement();
if (linkInfo.linkTypeParameters && utils.isTypeElement(owner)) {
linkInfo.typeElement = (TypeElement) owner;
Content label = newContent();
label.add(utils.getTypeName(type, false));
linkInfo.label = label;
linkInfo.skipPreview = true;
link.add(getClassLink(linkInfo));
} else {
// No need to link method type parameters.
link.add(utils.getTypeName(typevariable, false));
}
if (linkInfo.showTypeBounds) {
linkInfo.showTypeBounds = false;
TypeParameterElement tpe = ((TypeParameterElement) typevariable.asElement());
boolean more = false;
List<? extends TypeMirror> bounds = utils.getBounds(tpe);
for (TypeMirror bound : bounds) {
// we get everything as extends java.lang.Object we suppress
// all of them except those that have multiple extends
if (bounds.size() == 1 &&
utils.typeUtils.isSameType(bound, utils.getObjectType()) &&
!utils.isAnnotated(bound)) {
continue;
}
link.add(more ? " & " : " extends ");
setBoundsLinkInfo(linkInfo, bound);
link.add(getLink(linkInfo));
more = true;
}
}
return link;
}
@Override
public Content visitDeclared(DeclaredType type, LinkInfo linkInfo) {
TypeMirror enc = type.getEnclosingType();
if (enc instanceof DeclaredType dt && utils.isGenericType(dt)) {
// If an enclosing type has type parameters render them as separate links as
// otherwise this information is lost. On the other hand, plain enclosing types
// are not linked separately as they are easy to reach from the nested type.
setEnclosingTypeLinkInfo(linkInfo, dt);
visitDeclared(dt, linkInfo);
link.add(".");
setEnclosingTypeLinkInfo(linkInfo, type);
}
link.add(getTypeAnnotationLinks(linkInfo));
linkInfo.typeElement = utils.asTypeElement(type);
link.add(getClassLink(linkInfo));
if (linkInfo.showTypeParameters()) {
link.add(getTypeParameterLinks(linkInfo));
}
return link;
}
};
return linkVisitor.visit(linkInfo.type, linkInfo);
} else if (linkInfo.typeElement != null) {
Content link = newContent();
link.add(getClassLink(linkInfo));
if (linkInfo.showTypeParameters()) {
link.add(getTypeParameterLinks(linkInfo));
}
return link;
} else {
return null;
}
}
private void setBoundsLinkInfo(LinkInfo linkInfo, TypeMirror bound) {
linkInfo.typeElement = null;
linkInfo.label = null;
linkInfo.type = bound;
linkInfo.skipPreview = false;
}
private void setEnclosingTypeLinkInfo(LinkInfo linkinfo, DeclaredType enclosing) {
linkinfo.typeElement = null;
linkinfo.label = null;
linkinfo.type = enclosing;
}
/**
* Returns a link to the given class.
*
* @param linkInfo the information about the link to construct
* @return the link for the given class.
*/
protected abstract Content getClassLink(LinkInfo linkInfo);
/**
* Returns links to the type parameters.
*
* @param linkInfo the information about the link to construct
* @return the links to the type parameters
*/
protected abstract Content getTypeParameterLinks(LinkInfo linkInfo);
/**
* Returns links to the type annotations.
*
* @param linkInfo the information about the link to construct
* @return the links to the type annotations
*/
public abstract Content getTypeAnnotationLinks(LinkInfo linkInfo);
}

View File

@ -1,158 +0,0 @@
/*
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.javadoc.internal.doclets.toolkit.util.links;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
/**
* Encapsulates information about a link.
*/
public abstract class LinkInfo {
/**
* The class we want to link to. Null if we are not linking
* to a class.
*/
public TypeElement typeElement;
/**
* The executable element we want to link to. Null if we are not linking
* to an executable element.
*/
public ExecutableElement executableElement;
/**
* The Type we want to link to. Null if we are not linking to a type.
*/
public TypeMirror type;
/**
* True if this is a link to a VarArg.
*/
public boolean isVarArg = false;
/**
* The label for the link.
*/
public Content label;
/**
* True if we should print the type bounds for the type parameter.
*/
public boolean showTypeBounds = true;
/**
* True if type parameters should be rendered as links.
*/
public boolean linkTypeParameters = true;
/**
* By default, the link can be to the page it's already on. However,
* there are cases where we don't want this (e.g. heading of class page).
*/
public boolean linkToSelf = true;
/**
* True iff the preview flags should be skipped for this link.
*/
public boolean skipPreview;
/**
* True if type parameters should be separated by line breaks.
*/
public boolean addLineBreaksInTypeParameters = false;
/**
* True if annotations on type parameters should be shown.
*/
public boolean showTypeParameterAnnotations = false;
/**
* {@return a new instance of a content object}
*/
protected abstract Content newContent();
/**
* Returns true if this link is linkable and false if we can't link to the
* desired place.
*
* @return true if this link is linkable and false if we can't link to the
* desired place.
*/
public abstract boolean isLinkable();
/**
* Returns true if links to declared types should include type parameters.
*
* @return true if type parameter links should be included
*/
public abstract boolean showTypeParameters();
/**
* Return the label for this class link.
*
* @param configuration the current configuration of the doclet.
* @return the label for this class link.
*/
public Content getClassLinkLabel(BaseConfiguration configuration) {
if (label != null && !label.isEmpty()) {
return label;
} else if (isLinkable()) {
Content tlabel = newContent();
Utils utils = configuration.utils;
tlabel.add(type instanceof DeclaredType dt && utils.isGenericType(dt.getEnclosingType())
// If enclosing type is rendered as separate links only use own class name
? typeElement.getSimpleName().toString()
: configuration.utils.getSimpleName(typeElement));
return tlabel;
} else {
Content tlabel = newContent();
tlabel.add(configuration.getClassName(typeElement));
return tlabel;
}
}
@Override
public String toString() {
return "LinkInfo{" + "typeElement=" + typeElement +
", executableElement=" + executableElement +
", type=" + type +
", isVarArg=" + isVarArg +
", label=" + label +
", showTypeBounds=" + showTypeBounds +
", linkTypeParameters=" + linkTypeParameters +
", linkToSelf=" + linkToSelf +
", addLineBreaksInTypeParameters=" + addLineBreaksInTypeParameters +
", showTypeParameterAnnotations=" + showTypeParameterAnnotations + '}';
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Provides a factory for constructing links.
*/
package jdk.javadoc.internal.doclets.toolkit.util.links;