8290243: move seeTagToContent from HtmlDocletWriter to TagletWriterImpl

Reviewed-by: prappo
This commit is contained in:
Jonathan Gibbons 2022-07-29 21:55:20 +00:00
parent 15943e4242
commit 8179a191f0
5 changed files with 267 additions and 332 deletions

View File

@ -386,7 +386,7 @@ public class HtmlDocletWriter {
* @param context the enclosing context
* @return a TagletWriter
*/
public TagletWriter getTagletWriterInstance(TagletWriterImpl.Context context) {
public TagletWriterImpl getTagletWriterInstance(TagletWriterImpl.Context context) {
return new TagletWriterImpl(this, context);
}
@ -971,316 +971,6 @@ public class HtmlDocletWriter {
return label;
}
public Content seeTagToContent(Element element, DocTree see, TagletWriterImpl.Context context) {
Kind kind = see.getKind();
CommentHelper ch = utils.getCommentHelper(element);
String tagName = ch.getTagName(see);
String refText;
List<? extends DocTree> label;
switch (kind) {
case LINK, LINK_PLAIN -> {
// {@link[plain] reference label...}
LinkTree lt = (LinkTree) see;
var linkRef = lt.getReference();
if (linkRef == null) {
messages.warning(ch.getDocTreePath(see),"doclet.link.no_reference");
return invalidTagOutput(resources.getText("doclet.tag.invalid_input", lt.toString()),
Optional.empty());
}
refText = linkRef.toString();
label = lt.getLabel();
}
case SEE -> {
List<? extends DocTree> ref = ((SeeTree) see).getReference();
assert !ref.isEmpty();
DocTree ref0 = ref.get(0);
switch (ref0.getKind()) {
case TEXT, START_ELEMENT -> {
// @see "Reference"
// @see <a href="...">...</a>
return commentTagsToContent(element, ref, false, false);
}
case REFERENCE -> {
// @see reference label...
refText = ref0.toString();
label = ref.subList(1, ref.size());
}
case ERRONEOUS -> {
return invalidTagOutput(resources.getText("doclet.tag.invalid_input",
ref0.toString()),
Optional.empty());
}
default ->
throw new IllegalStateException(ref0.getKind().toString());
}
}
default ->
throw new IllegalStateException(kind.toString());
}
boolean isLinkPlain = kind == LINK_PLAIN;
Content labelContent = plainOrCode(isLinkPlain,
commentTagsToContent(element, label, context));
// The signature from the @see tag. We will output this text when a label is not specified.
Content text = plainOrCode(isLinkPlain,
Text.of(Objects.requireNonNullElse(ch.getReferencedSignature(see), "")));
TypeElement refClass = ch.getReferencedClass(see);
Element refMem = ch.getReferencedMember(see);
String refMemName = ch.getReferencedMemberName(see);
if (refMemName == null && refMem != null) {
refMemName = refMem.toString();
}
if (refClass == null) {
ModuleElement refModule = ch.getReferencedModule(see);
if (refModule != null && utils.isIncluded(refModule)) {
return getModuleLink(refModule, labelContent.isEmpty() ? text : labelContent);
}
//@see is not referencing an included class
PackageElement refPackage = ch.getReferencedPackage(see);
if (refPackage != null && utils.isIncluded(refPackage)) {
//@see is referencing an included package
if (labelContent.isEmpty())
labelContent = plainOrCode(isLinkPlain,
Text.of(refPackage.getQualifiedName()));
return getPackageLink(refPackage, labelContent);
} else {
// @see is not referencing an included class, module or package. Check for cross links.
String refModuleName = ch.getReferencedModuleName(see);
DocLink elementCrossLink = (refPackage != null) ? getCrossPackageLink(refPackage) :
(configuration.extern.isModule(refModuleName))
? getCrossModuleLink(utils.elementUtils.getModuleElement(refModuleName))
: null;
if (elementCrossLink != null) {
// Element cross link found
return links.createExternalLink(elementCrossLink,
(labelContent.isEmpty() ? text : labelContent));
} else {
// No cross link found so print warning
if (!configuration.isDocLintReferenceGroupEnabled()) {
messages.warning(ch.getDocTreePath(see),
"doclet.see.class_or_package_not_found",
"@" + tagName,
refText);
}
return invalidTagOutput(resources.getText("doclet.tag.invalid", tagName),
Optional.of(labelContent.isEmpty() ? text: labelContent));
}
}
} else if (refMemName == null) {
// Must be a class reference since refClass is not null and refMemName is null.
if (labelContent.isEmpty()) {
TypeMirror referencedType = ch.getReferencedType(see);
if (utils.isGenericType(referencedType)) {
// This is a generic type link, use the TypeMirror representation.
return plainOrCode(isLinkPlain, getLink(
new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.DEFAULT, referencedType)));
}
labelContent = plainOrCode(isLinkPlain, Text.of(utils.getSimpleName(refClass)));
}
return getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.DEFAULT, refClass)
.label(labelContent));
} else if (refMem == null) {
// Must be a member reference since refClass is not null and refMemName is not null.
// However, refMem is null, so this referenced member does not exist.
return (labelContent.isEmpty() ? text: labelContent);
} else {
// Must be a member reference since refClass is not null and refMemName is not null.
// refMem is not null, so this @see tag must be referencing a valid member.
TypeElement containing = utils.getEnclosingTypeElement(refMem);
// Find the enclosing type where the method is actually visible
// in the inheritance hierarchy.
ExecutableElement overriddenMethod = null;
if (refMem.getKind() == ElementKind.METHOD) {
VisibleMemberTable vmt = configuration.getVisibleMemberTable(containing);
overriddenMethod = vmt.getOverriddenMethod((ExecutableElement)refMem);
if (overriddenMethod != null)
containing = utils.getEnclosingTypeElement(overriddenMethod);
}
if (refText.trim().startsWith("#") &&
! (utils.isPublic(containing) || utils.isLinkable(containing))) {
// Since the link is relative and the holder is not even being
// documented, this must be an inherited link. Redirect it.
// The current class either overrides the referenced member or
// inherits it automatically.
if (this instanceof ClassWriterImpl writer) {
containing = writer.getTypeElement();
} else if (!utils.isPublic(containing)) {
messages.warning(
ch.getDocTreePath(see), "doclet.see.class_or_package_not_accessible",
tagName, utils.getFullyQualifiedName(containing));
} else {
if (!configuration.isDocLintReferenceGroupEnabled()) {
messages.warning(
ch.getDocTreePath(see), "doclet.see.class_or_package_not_found",
tagName, refText);
}
}
}
if (configuration.currentTypeElement != containing) {
refMemName = (utils.isConstructor(refMem))
? refMemName
: utils.getSimpleName(containing) + "." + refMemName;
}
if (utils.isExecutableElement(refMem)) {
if (refMemName.indexOf('(') < 0) {
refMemName += utils.makeSignature((ExecutableElement) refMem, null, true);
}
if (overriddenMethod != null) {
// The method to actually link.
refMem = overriddenMethod;
}
}
return getDocLink(HtmlLinkInfo.Kind.SEE_TAG, containing,
refMem, (labelContent.isEmpty()
? plainOrCode(isLinkPlain, Text.of(refMemName))
: labelContent), null, false);
}
}
// TODO: this method and seeTagToContent share much of the code; consider factoring common pieces out
public Content linkToContent(Element referrer, Element target, String targetSignature, String text) {
CommentHelper ch = utils.getCommentHelper(referrer);
boolean isLinkPlain = false; // TODO: for now
Content labelContent = plainOrCode(isLinkPlain, Text.of(text));
TypeElement refClass = ch.getReferencedClass(target);
Element refMem = ch.getReferencedMember(target);
String refMemName = ch.getReferencedMemberName(targetSignature);
if (refMemName == null && refMem != null) {
refMemName = refMem.toString();
}
if (refClass == null) {
ModuleElement refModule = ch.getReferencedModule(target);
if (refModule != null && utils.isIncluded(refModule)) {
return getModuleLink(refModule, labelContent);
}
//@see is not referencing an included class
PackageElement refPackage = ch.getReferencedPackage(target);
if (refPackage != null && utils.isIncluded(refPackage)) {
//@see is referencing an included package
if (labelContent.isEmpty())
labelContent = plainOrCode(isLinkPlain,
Text.of(refPackage.getQualifiedName()));
return getPackageLink(refPackage, labelContent);
} else {
// @see is not referencing an included class, module or package. Check for cross links.
String refModuleName = ch.getReferencedModuleName(targetSignature);
DocLink elementCrossLink = (refPackage != null) ? getCrossPackageLink(refPackage) :
(configuration.extern.isModule(refModuleName))
? getCrossModuleLink(utils.elementUtils.getModuleElement(refModuleName))
: null;
if (elementCrossLink != null) {
// Element cross link found
return links.createExternalLink(elementCrossLink, labelContent);
} else {
// No cross link found so print warning
// TODO:
// messages.warning(ch.getDocTreePath(see),
// "doclet.see.class_or_package_not_found",
// "@" + tagName,
// seeText);
return labelContent;
}
}
} else if (refMemName == null) {
// Must be a class reference since refClass is not null and refMemName is null.
if (labelContent.isEmpty()) {
if (!refClass.getTypeParameters().isEmpty() && targetSignature.contains("<")) {
// If this is a generic type link try to use the TypeMirror representation.
// TODO:
// TypeMirror refType = ch.getReferencedType(target);
TypeMirror refType = target.asType();
if (refType != null) {
return plainOrCode(isLinkPlain, getLink(
new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.DEFAULT, refType)));
}
}
labelContent = plainOrCode(isLinkPlain, Text.of(utils.getSimpleName(refClass)));
}
return getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.DEFAULT, refClass)
.label(labelContent));
} else if (refMem == null) {
// Must be a member reference since refClass is not null and refMemName is not null.
// However, refMem is null, so this referenced member does not exist.
return labelContent;
} else {
// Must be a member reference since refClass is not null and refMemName is not null.
// refMem is not null, so this @see tag must be referencing a valid member.
TypeElement containing = utils.getEnclosingTypeElement(refMem);
// Find the enclosing type where the method is actually visible
// in the inheritance hierarchy.
ExecutableElement overriddenMethod = null;
if (refMem.getKind() == ElementKind.METHOD) {
VisibleMemberTable vmt = configuration.getVisibleMemberTable(containing);
overriddenMethod = vmt.getOverriddenMethod((ExecutableElement)refMem);
if (overriddenMethod != null)
containing = utils.getEnclosingTypeElement(overriddenMethod);
}
if (targetSignature.trim().startsWith("#") &&
! (utils.isPublic(containing) || utils.isLinkable(containing))) {
// Since the link is relative and the holder is not even being
// documented, this must be an inherited link. Redirect it.
// The current class either overrides the referenced member or
// inherits it automatically.
if (this instanceof ClassWriterImpl writer) {
containing = writer.getTypeElement();
} else if (!utils.isPublic(containing)) {
// TODO:
// messages.warning(
// ch.getDocTreePath(see), "doclet.see.class_or_package_not_accessible",
// tagName, utils.getFullyQualifiedName(containing));
} else {
// TODO:
// messages.warning(
// ch.getDocTreePath(see), "doclet.see.class_or_package_not_found",
// tagName, seeText);
}
}
if (configuration.currentTypeElement != containing) {
refMemName = (utils.isConstructor(refMem))
? refMemName
: utils.getSimpleName(containing) + "." + refMemName;
}
if (utils.isExecutableElement(refMem)) {
if (refMemName.indexOf('(') < 0) {
refMemName += utils.makeSignature((ExecutableElement) refMem, null, true);
}
if (overriddenMethod != null) {
// The method to actually link.
refMem = overriddenMethod;
}
}
return getDocLink(HtmlLinkInfo.Kind.SEE_TAG, containing,
refMem, (labelContent.isEmpty()
? plainOrCode(isLinkPlain, Text.of(text))
: labelContent), null, false);
}
}
private String removeTrailingSlash(String s) {
return s.endsWith("/") ? s.substring(0, s.length() -1) : s;
}
private Content plainOrCode(boolean plain, Content body) {
return (plain || body.isEmpty()) ? body : HtmlTree.CODE(body);
}
/**
* Add the inline comment.
*
@ -1660,8 +1350,8 @@ public class HtmlDocletWriter {
}
content.add(label);
} else {
Content c = seeTagToContent(element, node, context.within(node));
content.add(c);
TagletWriterImpl t = getTagletWriterInstance(context.within(node));
content.add(t.linkTagOutput(element, node));
}
return false;
}
@ -1674,12 +1364,6 @@ public class HtmlDocletWriter {
return false;
}
@Override
public Boolean visitSee(SeeTree node, Content content) {
content.add(seeTagToContent(element, node, context));
return false;
}
@Override
public Boolean visitStartElement(StartElementTree node, Content content) {
Content attrs = new ContentBuilder();

View File

@ -29,8 +29,10 @@ import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import javax.lang.model.element.Element;
@ -46,6 +48,7 @@ import javax.lang.model.util.SimpleElementVisitor14;
import com.sun.source.doctree.DeprecatedTree;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.IndexTree;
import com.sun.source.doctree.LinkTree;
import com.sun.source.doctree.LiteralTree;
import com.sun.source.doctree.ParamTree;
import com.sun.source.doctree.ReturnTree;
@ -66,6 +69,7 @@ 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.DocletElement;
import jdk.javadoc.internal.doclets.toolkit.Messages;
import jdk.javadoc.internal.doclets.toolkit.Resources;
import jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder;
import jdk.javadoc.internal.doclets.toolkit.taglets.ParamTaglet;
@ -79,6 +83,9 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
import jdk.javadoc.internal.doclets.toolkit.util.Utils.PreviewFlagProvider;
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
import static com.sun.source.doctree.DocTree.Kind.LINK_PLAIN;
/**
* The taglet writer that writes HTML.
@ -143,6 +150,9 @@ public class TagletWriterImpl extends TagletWriter {
private final HtmlOptions options;
private final Utils utils;
private final Resources resources;
private final Messages messages;
private final Contents contents;
private final Context context;
@ -186,6 +196,7 @@ public class TagletWriterImpl extends TagletWriter {
configuration = htmlWriter.configuration;
options = configuration.getOptions();
utils = configuration.utils;
messages = configuration.messages;
resources = configuration.getDocResources();
contents = configuration.getContents();
}
@ -270,6 +281,32 @@ public class TagletWriterImpl extends TagletWriter {
return result;
}
@Override
public Content linkTagOutput(Element element, LinkTree tag) {
CommentHelper ch = utils.getCommentHelper(element);
var linkRef = tag.getReference();
if (linkRef == null) {
messages.warning(ch.getDocTreePath(tag), "doclet.link.no_reference");
return invalidTagOutput(resources.getText("doclet.tag.invalid_input", tag.toString()),
Optional.empty());
}
DocTree.Kind kind = tag.getKind();
String tagName = ch.getTagName(tag);
String refSignature = ch.getReferencedSignature(linkRef);
return linkSeeReferenceOutput(element,
tag,
refSignature,
ch.getReferencedElement(tag),
tagName,
(kind == LINK_PLAIN),
htmlWriter.commentTagsToContent(element, tag.getLabel(), context),
(key, args) -> messages.warning(ch.getDocTreePath(tag), key, args)
);
}
@Override
protected Content literalTagOutput(Element element, LiteralTree tag) {
return Text.of(utils.normalizeNewlines(tag.getBody().getBody()));
@ -315,8 +352,9 @@ public class TagletWriterImpl extends TagletWriter {
@Override
public Content seeTagOutput(Element holder, List<? extends SeeTree> seeTags) {
List<Content> links = new ArrayList<>();
for (DocTree dt : seeTags) {
links.add(htmlWriter.seeTagToContent(holder, dt, context.within(dt)));
for (SeeTree dt : seeTags) {
TagletWriterImpl t = new TagletWriterImpl(htmlWriter, context.within(dt));
links.add(t.seeTagOutput(holder, dt));
}
if (utils.isVariableElement(holder) && ((VariableElement)holder).getConstantValue() != null &&
htmlWriter instanceof ClassWriterImpl writer) {
@ -363,6 +401,203 @@ public class TagletWriterImpl extends TagletWriter {
return s.length() > SEE_TAG_MAX_INLINE_LENGTH || s.contains(",");
}
/**
* {@return the output for a single {@code @see} tag}
*
* @param element the element that has the documentation comment containing this tag
* @param seeTag the tag
*/
private Content seeTagOutput(Element element, SeeTree seeTag) {
List<? extends DocTree> ref = seeTag.getReference();
assert !ref.isEmpty();
DocTree ref0 = ref.get(0);
switch (ref0.getKind()) {
case TEXT, START_ELEMENT -> {
// @see "Reference"
// @see <a href="...">...</a>
return htmlWriter.commentTagsToContent(element, ref, false, false);
}
case REFERENCE -> {
// @see reference label...
CommentHelper ch = utils.getCommentHelper(element);
String tagName = ch.getTagName(seeTag);
String refSignature = ch.getReferencedSignature(ref0);
List<? extends DocTree> label = ref.subList(1, ref.size());
return linkSeeReferenceOutput(element,
seeTag,
refSignature,
ch.getReferencedElement(seeTag),
tagName,
false,
htmlWriter.commentTagsToContent(element, label, context),
(key, args) -> messages.warning(ch.getDocTreePath(seeTag), key, args)
);
}
case ERRONEOUS -> {
return invalidTagOutput(resources.getText("doclet.tag.invalid_input",
ref0.toString()),
Optional.empty());
}
default -> throw new IllegalStateException(ref0.getKind().toString());
}
}
/**
* Worker method to generate a link from the information in different kinds of tags,
* such as {@code {@link ...}} tags, {@code @see ...} tags and the {@code link} markup tag
* in a {@code {@snippet ...}} tag.
*
* @param holder the element that has the documentation comment containing the information
* @param refTree the tree node containing the information, or {@code null} if not available
* @param refSignature the normalized signature of the target of the reference
* @param ref the target of the reference
* @param tagName the name of the tag in the source, to be used in diagnostics
* @param isLinkPlain {@code true} if the link should be presented in "plain" font,
* or {@code false} for "code" font
* @param label the label for the link,
* or an empty item to use a default label derived from the signature
* @param reportWarning a function to report warnings about issues found in the reference
*
* @return the output containing the generated link, or content indicating an error
*/
private Content linkSeeReferenceOutput(Element holder,
DocTree refTree,
String refSignature,
Element ref,
String tagName,
boolean isLinkPlain,
Content label,
BiConsumer<String, Object[]> reportWarning) {
Content labelContent = plainOrCode(isLinkPlain, label);
// The signature from the @see tag. We will output this text when a label is not specified.
Content text = plainOrCode(isLinkPlain,
Text.of(Objects.requireNonNullElse(refSignature, "")));
CommentHelper ch = utils.getCommentHelper(holder);
TypeElement refClass = ch.getReferencedClass(ref);
Element refMem = ch.getReferencedMember(ref);
String refMemName = ch.getReferencedMemberName(refSignature);
if (refMemName == null && refMem != null) {
refMemName = refMem.toString();
}
if (refClass == null) {
ModuleElement refModule = ch.getReferencedModule(ref);
if (refModule != null && utils.isIncluded(refModule)) {
return htmlWriter.getModuleLink(refModule, labelContent.isEmpty() ? text : labelContent);
}
//@see is not referencing an included class
PackageElement refPackage = ch.getReferencedPackage(ref);
if (refPackage != null && utils.isIncluded(refPackage)) {
//@see is referencing an included package
if (labelContent.isEmpty())
labelContent = plainOrCode(isLinkPlain,
Text.of(refPackage.getQualifiedName()));
return htmlWriter.getPackageLink(refPackage, labelContent);
} else {
// @see is not referencing an included class, module or package. Check for cross links.
String refModuleName = ch.getReferencedModuleName(refSignature);
DocLink elementCrossLink = (refPackage != null) ? htmlWriter.getCrossPackageLink(refPackage) :
(configuration.extern.isModule(refModuleName))
? htmlWriter.getCrossModuleLink(utils.elementUtils.getModuleElement(refModuleName))
: null;
if (elementCrossLink != null) {
// Element cross link found
return htmlWriter.links.createExternalLink(elementCrossLink,
(labelContent.isEmpty() ? text : labelContent));
} else {
// No cross link found so print warning
if (!configuration.isDocLintReferenceGroupEnabled()) {
reportWarning.accept(
"doclet.see.class_or_package_not_found",
new Object[] { "@" + tagName, refSignature});
}
return htmlWriter.invalidTagOutput(resources.getText("doclet.tag.invalid", tagName),
Optional.of(labelContent.isEmpty() ? text: labelContent));
}
}
} else if (refMemName == null) {
// Must be a class reference since refClass is not null and refMemName is null.
if (labelContent.isEmpty() && refTree != null) {
TypeMirror referencedType = ch.getReferencedType(refTree);
if (utils.isGenericType(referencedType)) {
// This is a generic type link, use the TypeMirror representation.
return plainOrCode(isLinkPlain, htmlWriter.getLink(
new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.DEFAULT, referencedType)));
}
labelContent = plainOrCode(isLinkPlain, Text.of(utils.getSimpleName(refClass)));
}
return htmlWriter.getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.DEFAULT, refClass)
.label(labelContent));
} else if (refMem == null) {
// Must be a member reference since refClass is not null and refMemName is not null.
// However, refMem is null, so this referenced member does not exist.
return (labelContent.isEmpty() ? text: labelContent);
} else {
// Must be a member reference since refClass is not null and refMemName is not null.
// refMem is not null, so this @see tag must be referencing a valid member.
TypeElement containing = utils.getEnclosingTypeElement(refMem);
// Find the enclosing type where the method is actually visible
// in the inheritance hierarchy.
ExecutableElement overriddenMethod = null;
if (refMem.getKind() == ElementKind.METHOD) {
VisibleMemberTable vmt = configuration.getVisibleMemberTable(containing);
overriddenMethod = vmt.getOverriddenMethod((ExecutableElement)refMem);
if (overriddenMethod != null)
containing = utils.getEnclosingTypeElement(overriddenMethod);
}
if (refSignature.trim().startsWith("#") &&
! (utils.isPublic(containing) || utils.isLinkable(containing))) {
// Since the link is relative and the holder is not even being
// documented, this must be an inherited link. Redirect it.
// The current class either overrides the referenced member or
// inherits it automatically.
if (htmlWriter instanceof ClassWriterImpl writer) {
containing = writer.getTypeElement();
} else if (!utils.isPublic(containing)) {
reportWarning.accept("doclet.see.class_or_package_not_accessible",
new Object[] { tagName, utils.getFullyQualifiedName(containing)});
} else {
if (!configuration.isDocLintReferenceGroupEnabled()) {
reportWarning.accept("doclet.see.class_or_package_not_found",
new Object[] { tagName, refSignature });
}
}
}
if (configuration.currentTypeElement != containing) {
refMemName = (utils.isConstructor(refMem))
? refMemName
: utils.getSimpleName(containing) + "." + refMemName;
}
if (utils.isExecutableElement(refMem)) {
if (refMemName.indexOf('(') < 0) {
refMemName += utils.makeSignature((ExecutableElement) refMem, null, true);
}
if (overriddenMethod != null) {
// The method to actually link.
refMem = overriddenMethod;
}
}
return htmlWriter.getDocLink(HtmlLinkInfo.Kind.SEE_TAG, containing,
refMem, (labelContent.isEmpty()
? plainOrCode(isLinkPlain, Text.of(refMemName))
: labelContent), null, false);
}
}
private Content plainOrCode(boolean plain, Content body) {
return (plain || body.isEmpty()) ? body : HtmlTree.CODE(body);
}
@Override
public Content simpleBlockTagOutput(Element element, List<? extends DocTree> simpleTags, String header) {
CommentHelper ch = utils.getCommentHelper(element);
@ -434,7 +669,14 @@ public class TagletWriterImpl extends TagletWriter {
//disable preview tagging inside the snippets:
PreviewFlagProvider prevPreviewProvider = utils.setPreviewFlagProvider(el -> false);
try {
c = new ContentBuilder(htmlWriter.linkToContent(element, e, t, sequence.toString()));
c = linkSeeReferenceOutput(element,
null,
t,
e,
"link",
false, // TODO: for now
Text.of(sequence.toString()),
(key, args) -> { /* TODO: report diagnostic */ });
} finally {
utils.setPreviewFlagProvider(prevPreviewProvider);
}

View File

@ -36,6 +36,7 @@ import javax.lang.model.type.TypeMirror;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.IndexTree;
import com.sun.source.doctree.LinkTree;
import com.sun.source.doctree.LiteralTree;
import com.sun.source.doctree.ParamTree;
import com.sun.source.doctree.ReturnTree;
@ -107,6 +108,16 @@ public abstract class TagletWriter {
*/
protected abstract Content deprecatedTagOutput(Element element);
/**
* Returns the output for a {@code {@link ...}} or {@code {@linkplain ...}} tag.
*
* @param element The element that owns the doc comment
* @param tag the tag
*
* @return the output
*/
protected abstract Content linkTagOutput(Element element, LinkTree tag);
/**
* Returns the output for a {@code {@literal ...}} tag.
*

View File

@ -156,8 +156,8 @@ public class CommentHelper {
public TypeMirror getType(ReferenceTree rtree) {
DocTreePath docTreePath = getDocTreePath(rtree);
if (docTreePath != null) {
DocTrees doctrees = configuration.docEnv.getDocTrees();
return doctrees.getType(docTreePath);
DocTrees docTrees = configuration.docEnv.getDocTrees();
return docTrees.getType(docTreePath);
}
return null;
}
@ -213,11 +213,6 @@ public class CommentHelper {
return (utils.isExecutableElement(e) || utils.isVariableElement(e)) ? e : null;
}
public String getReferencedMemberName(DocTree dtree) {
String s = getReferencedSignature(dtree);
return getReferencedMemberName(s);
}
public String getReferencedMemberName(String signature) {
if (signature == null) {
return null;
@ -259,7 +254,7 @@ public class CommentHelper {
return getFirstSentenceTrees(getBody(dtree));
}
private Element getReferencedElement(DocTree dtree) {
public Element getReferencedElement(DocTree dtree) {
return new ReferenceDocTreeVisitor<Element>() {
@Override
public Element visitReference(ReferenceTree node, Void p) {
@ -286,7 +281,10 @@ public class CommentHelper {
return null;
}
public String getReferencedSignature(DocTree dtree) {
/**
* {@return the normalized signature from a {@code ReferenceTree}}
*/
public String getReferencedSignature(DocTree dtree) {
return new ReferenceDocTreeVisitor<String>() {
@Override
public String visitReference(ReferenceTree node, Void p) {

View File

@ -66,7 +66,7 @@ public class TypeParameters<E> implements SubInterface<E> {
*
* @param <A> This is the first type parameter.
*/
public <A> void methodThatHasTypeParmaters(A... a) {}
public <A> void methodThatHasTypeParameters(A... a) {}
/**
* This method returns a TypeParameter array and takes in a TypeParameter array