Skip to content

Commit 499406c

Browse files
committed
8285488: Improve DocFinder
8287796: Stop auto-inheriting documentation for subclasses of exceptions whose documentation is inherited 8291869: Match exceptions using types of javax.lang.model, not strings 8288045: Clean up ParamTaglet 8288046: Clean up ThrowsTaglet 8295277: Expand {@inheritdoc} in @throws fully Reviewed-by: jjg
1 parent 97ab2c3 commit 499406c

File tree

26 files changed

+1833
-614
lines changed

26 files changed

+1833
-614
lines changed

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -811,17 +811,17 @@ public Content getThrowsHeader() {
811811
return HtmlTree.DT(contents.throws_);
812812
}
813813

814-
@Override
815-
public Content throwsTagOutput(Element element, ThrowsTree throwsTag, TypeMirror substituteType) {
814+
@Deprecated(forRemoval = true)
815+
private Content throwsTagOutput(Element element, ThrowsTree throwsTag, TypeMirror substituteType) {
816816
ContentBuilder body = new ContentBuilder();
817817
CommentHelper ch = utils.getCommentHelper(element);
818818
Element exception = ch.getException(throwsTag);
819819
Content excName;
820820
if (substituteType != null) {
821-
excName = htmlWriter.getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.MEMBER,
821+
excName = htmlWriter.getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.MEMBER,
822822
substituteType));
823823
} else if (exception == null) {
824-
excName = RawHtml.of(throwsTag.getExceptionName().toString());
824+
excName = Text.of(throwsTag.getExceptionName().toString());
825825
} else if (exception.asType() == null) {
826826
excName = Text.of(utils.getFullyQualifiedName(exception));
827827
} else {
@@ -841,9 +841,16 @@ public Content throwsTagOutput(Element element, ThrowsTree throwsTag, TypeMirror
841841
}
842842

843843
@Override
844-
public Content throwsTagOutput(TypeMirror throwsType) {
845-
return HtmlTree.DD(HtmlTree.CODE(htmlWriter.getLink(
846-
new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.MEMBER, throwsType))));
844+
public Content throwsTagOutput(TypeMirror throwsType, Optional<Content> content) {
845+
var linkInfo = new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.MEMBER, throwsType);
846+
linkInfo.excludeTypeBounds = true;
847+
var link = htmlWriter.getLink(linkInfo);
848+
var concat = new ContentBuilder(HtmlTree.CODE(link));
849+
if (content.isPresent()) {
850+
concat.add(" - ");
851+
concat.add(content.get());
852+
}
853+
return HtmlTree.DD(concat);
847854
}
848855

849856
@Override

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ doclet.link.see.no_label=missing reference label
107107
doclet.see.class_or_package_not_found=Tag {0}: reference not found: {1}
108108
doclet.see.class_or_package_not_accessible=Tag {0}: reference not accessible: {1}
109109
doclet.see.nested_link=Tag {0}: nested link
110+
doclet.throws.reference_not_found=cannot find exception type by name
111+
doclet.throws.reference_bad_type=not an exception type: {0}
110112
doclet.tag.invalid_usage=invalid usage of tag {0}
111113
doclet.tag.invalid_input=invalid input: ''{0}''
112114
doclet.tag.invalid=invalid @{0}

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.List;
3434
import java.util.Map;
3535
import java.util.Objects;
36+
import java.util.Optional;
3637
import java.util.SortedSet;
3738
import java.util.TreeSet;
3839
import javax.lang.model.element.Element;
@@ -50,6 +51,7 @@
5051
import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
5152
import jdk.javadoc.internal.doclets.toolkit.WriterFactory;
5253
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
54+
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Result;
5355
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
5456
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
5557

@@ -260,19 +262,18 @@ private void buildSummary(MemberSummaryWriter writer,
260262
if (property != null && member instanceof ExecutableElement ee) {
261263
configuration.cmtUtils.updatePropertyMethodComment(ee, property);
262264
}
263-
List<? extends DocTree> firstSentenceTags = utils.getFirstSentenceTrees(member);
264-
if (utils.isMethod(member) && firstSentenceTags.isEmpty()) {
265-
//Inherit comments from overridden or implemented method if
266-
//necessary.
267-
DocFinder.Output inheritedDoc =
268-
DocFinder.search(configuration,
269-
new DocFinder.Input(utils, member));
270-
if (inheritedDoc.holder != null
271-
&& !utils.getFirstSentenceTrees(inheritedDoc.holder).isEmpty()) {
272-
firstSentenceTags = utils.getFirstSentenceTrees(inheritedDoc.holder);
273-
}
265+
if (utils.isMethod(member)) {
266+
var docFinder = utils.docFinder();
267+
Optional<List<? extends DocTree>> r = docFinder.search((ExecutableElement) member, (m -> {
268+
var firstSentenceTrees = utils.getFirstSentenceTrees(m);
269+
Optional<List<? extends DocTree>> optional = firstSentenceTrees.isEmpty() ? Optional.empty() : Optional.of(firstSentenceTrees);
270+
return Result.fromOptional(optional);
271+
})).toOptional();
272+
// The fact that we use `member` for possibly unrelated tags is suspicious
273+
writer.addMemberSummary(typeElement, member, r.orElse(List.of()));
274+
} else {
275+
writer.addMemberSummary(typeElement, member, utils.getFirstSentenceTrees(member));
274276
}
275-
writer.addMemberSummary(typeElement, member, firstSentenceTags);
276277
}
277278
summaryTreeList.add(writer.getSummaryTable(typeElement));
278279
}

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MethodBuilder.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@
3232
import javax.lang.model.element.TypeElement;
3333
import javax.lang.model.type.TypeMirror;
3434

35+
import com.sun.source.doctree.DocTree;
3536
import jdk.javadoc.internal.doclets.toolkit.BaseOptions;
3637
import jdk.javadoc.internal.doclets.toolkit.Content;
3738
import jdk.javadoc.internal.doclets.toolkit.DocletException;
3839
import jdk.javadoc.internal.doclets.toolkit.MethodWriter;
3940
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
41+
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Result;
4042

4143
import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*;
4244

@@ -165,13 +167,10 @@ protected void buildPreviewInfo(Content methodContent) {
165167
protected void buildMethodComments(Content methodContent) {
166168
if (!options.noComment()) {
167169
assert utils.isMethod(currentMethod); // not all executables are methods
168-
ExecutableElement method = currentMethod;
169-
if (utils.getFullBody(currentMethod).isEmpty()) {
170-
DocFinder.Output docs = DocFinder.search(configuration,
171-
new DocFinder.Input(utils, currentMethod));
172-
if (!docs.inlineTags.isEmpty())
173-
method = (ExecutableElement) docs.holder;
174-
}
170+
var docFinder = utils.docFinder();
171+
Optional<ExecutableElement> r = docFinder.search(currentMethod,
172+
m -> Result.fromOptional(utils.getFullBody(m).isEmpty() ? Optional.empty() : Optional.of(m))).toOptional();
173+
ExecutableElement method = r.orElse(currentMethod);
175174
TypeMirror containingType = method.getEnclosingElement().asType();
176175
writer.addComments(containingType, method, methodContent);
177176
}

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ doclet.Factory=Factory:
118118
doclet.UnknownTag={0} is an unknown tag.
119119
doclet.UnknownTagLowercase={0} is an unknown tag -- same as a known tag except for case.
120120
doclet.inheritDocWithinInappropriateTag=@inheritDoc cannot be used within this tag
121+
doclet.inheritDocNoDoc=overridden methods do not document exception type {0}
122+
doclet.throwsInheritDocUnsupported=@inheritDoc is not supported for exception-type type parameters \
123+
that are not declared by a method; document such exception types directly
121124
doclet.noInheritedDoc=@inheritDoc used but {0} does not override or implement any method.
122125
doclet.tag_misuse=Tag {0} cannot be used in {1} documentation. It can only be used in the following types of documentation: {2}.
123126
doclet.Package_Summary=Package Summary

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/InheritDocTaglet.java

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
package jdk.javadoc.internal.doclets.toolkit.taglets;
2727

2828
import java.util.EnumSet;
29+
import java.util.List;
30+
import java.util.Optional;
2931

3032
import javax.lang.model.element.Element;
3133
import javax.lang.model.element.ElementKind;
@@ -38,6 +40,7 @@
3840
import jdk.javadoc.internal.doclets.toolkit.Messages;
3941
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
4042
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
43+
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Result;
4144
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
4245

4346
/**
@@ -61,52 +64,75 @@ public InheritDocTaglet() {
6164
* such tag.</p>
6265
*
6366
* @param writer the writer that is writing the output.
64-
* @param e the {@link Element} that we are documenting.
67+
* @param method the method that we are documenting.
6568
* @param inheritDoc the {@code {@inheritDoc}} tag
6669
* @param isFirstSentence true if we only want to inherit the first sentence
6770
*/
6871
private Content retrieveInheritedDocumentation(TagletWriter writer,
69-
Element e,
72+
ExecutableElement method,
7073
DocTree inheritDoc,
7174
boolean isFirstSentence) {
7275
Content replacement = writer.getOutputInstance();
7376
BaseConfiguration configuration = writer.configuration();
7477
Messages messages = configuration.getMessages();
7578
Utils utils = configuration.utils;
76-
CommentHelper ch = utils.getCommentHelper(e);
79+
CommentHelper ch = utils.getCommentHelper(method);
7780
var path = ch.getDocTreePath(inheritDoc).getParentPath();
7881
DocTree holderTag = path.getLeaf();
79-
Taglet taglet = holderTag.getKind() == DocTree.Kind.DOC_COMMENT
80-
? null
81-
: configuration.tagletManager.getTaglet(ch.getTagName(holderTag));
82+
if (holderTag.getKind() == DocTree.Kind.DOC_COMMENT) {
83+
try {
84+
var docFinder = utils.docFinder();
85+
Optional<Documentation> r = docFinder.trySearch(method,
86+
m -> Result.fromOptional(extractMainDescription(m, isFirstSentence, utils))).toOptional();
87+
if (r.isPresent()) {
88+
replacement = writer.commentTagsToOutput(r.get().method, null,
89+
r.get().mainDescription, isFirstSentence);
90+
}
91+
} catch (DocFinder.NoOverriddenMethodsFound e) {
92+
String signature = utils.getSimpleName(method)
93+
+ utils.flatSignature(method, writer.getCurrentPageElement());
94+
messages.warning(method, "doclet.noInheritedDoc", signature);
95+
}
96+
return replacement;
97+
}
98+
99+
Taglet taglet = configuration.tagletManager.getTaglet(ch.getTagName(holderTag));
82100
if (taglet != null && !(taglet instanceof InheritableTaglet)) {
83101
// This tag does not support inheritance.
84102
messages.warning(path, "doclet.inheritDocWithinInappropriateTag");
85103
return replacement;
86104
}
87-
var input = new DocFinder.Input(utils, e, (InheritableTaglet) taglet,
88-
new DocFinder.DocTreeInfo(holderTag, e), isFirstSentence, true);
89-
DocFinder.Output inheritedDoc = DocFinder.search(configuration, input);
90-
if (inheritedDoc.isValidInheritDocTag) {
91-
if (!inheritedDoc.inlineTags.isEmpty()) {
92-
replacement = writer.commentTagsToOutput(inheritedDoc.holder, inheritedDoc.holderTag,
93-
inheritedDoc.inlineTags, isFirstSentence);
105+
106+
InheritableTaglet.Output inheritedDoc = ((InheritableTaglet) taglet).inherit(method, holderTag, isFirstSentence, configuration);
107+
if (inheritedDoc.isValidInheritDocTag()) {
108+
if (!inheritedDoc.inlineTags().isEmpty()) {
109+
replacement = writer.commentTagsToOutput(inheritedDoc.holder(), inheritedDoc.holderTag(),
110+
inheritedDoc.inlineTags(), isFirstSentence);
94111
}
95112
} else {
96-
String signature = utils.getSimpleName(e) +
97-
((utils.isExecutableElement(e))
98-
? utils.flatSignature((ExecutableElement) e, writer.getCurrentPageElement())
99-
: e.toString());
100-
messages.warning(e, "doclet.noInheritedDoc", signature);
113+
String signature = utils.getSimpleName(method)
114+
+ utils.flatSignature(method, writer.getCurrentPageElement());
115+
messages.warning(method, "doclet.noInheritedDoc", signature);
101116
}
102117
return replacement;
103118
}
104119

120+
private record Documentation(List<? extends DocTree> mainDescription, ExecutableElement method) { }
121+
122+
private static Optional<Documentation> extractMainDescription(ExecutableElement m,
123+
boolean extractFirstSentenceOnly,
124+
Utils utils) {
125+
List<? extends DocTree> docTrees = extractFirstSentenceOnly
126+
? utils.getFirstSentenceTrees(m)
127+
: utils.getFullBody(m);
128+
return docTrees.isEmpty() ? Optional.empty() : Optional.of(new Documentation(docTrees, m));
129+
}
130+
105131
@Override
106132
public Content getInlineTagOutput(Element e, DocTree inheritDoc, TagletWriter tagletWriter) {
107133
if (e.getKind() != ElementKind.METHOD) {
108134
return tagletWriter.getOutputInstance();
109135
}
110-
return retrieveInheritedDocumentation(tagletWriter, e, inheritDoc, tagletWriter.isFirstSentence);
136+
return retrieveInheritedDocumentation(tagletWriter, (ExecutableElement) e, inheritDoc, tagletWriter.isFirstSentence);
111137
}
112138
}

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/InheritableTaglet.java

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,38 @@
2525

2626
package jdk.javadoc.internal.doclets.toolkit.taglets;
2727

28-
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
28+
29+
import java.util.List;
30+
31+
import javax.lang.model.element.Element;
32+
33+
import com.sun.source.doctree.DocTree;
34+
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
2935

3036
/**
3137
* A taglet should implement this interface if it supports an {@code {@inheritDoc}}
3238
* tag or is automatically inherited if it is missing.
3339
*/
3440
public interface InheritableTaglet extends Taglet {
3541

36-
/**
37-
* Given an {@link jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Output}
38-
* object, set its values with the appropriate information to inherit
39-
* documentation.
42+
/*
43+
* Called by InheritDocTaglet on an inheritable taglet to expand {@inheritDoc}
44+
* found inside a tag corresponding to that taglet.
4045
*
41-
* @param input the input for documentation search
42-
* @param output the output for documentation search
46+
* When inheriting failed some assumption, or caused an error, the taglet
47+
* can return either of:
48+
*
49+
* - new Output(null, null, List.of(), false)
50+
* - new Output(null, null, List.of(), true)
51+
*
52+
* In the future, this could be reworked using some other mechanism,
53+
* such as throwing an exception.
4354
*/
44-
void inherit(DocFinder.Input input, DocFinder.Output output);
55+
Output inherit(Element owner, DocTree tag, boolean isFirstSentence, BaseConfiguration configuration);
56+
57+
record Output(DocTree holderTag,
58+
Element holder,
59+
List<? extends DocTree> inlineTags,
60+
boolean isValidInheritDocTag) {
61+
}
4562
}

0 commit comments

Comments
 (0)