mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8075778: Add javadoc tag to avoid duplication of return information in simple situations.
Reviewed-by: prappo, jlahoda
This commit is contained in:
parent
48d8650ae1
commit
b29f9cd7b0
@ -30,13 +30,25 @@ import java.util.List;
|
||||
/**
|
||||
* A tree node for an {@code @return} block tag.
|
||||
*
|
||||
* <pre>
|
||||
* @return description
|
||||
* </pre>
|
||||
* <pre>{@code
|
||||
* @return description
|
||||
* {@return description}
|
||||
* }</pre>
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface ReturnTree extends BlockTagTree {
|
||||
public interface ReturnTree extends BlockTagTree, InlineTagTree {
|
||||
/**
|
||||
* Returns whether this instance is an inline tag.
|
||||
*
|
||||
* @return {@code true} if this instance is an inline tag, and {@code false} otherwise
|
||||
* @implSpec this implementation returns {@code false}.
|
||||
* @since 16
|
||||
*/
|
||||
default boolean isInline() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description of the return value of a method.
|
||||
* @return the description
|
||||
|
||||
@ -265,6 +265,26 @@ public interface DocTreeFactory {
|
||||
*/
|
||||
ReturnTree newReturnTree(List<? extends DocTree> description);
|
||||
|
||||
/**
|
||||
* Creates a new {@code ReturnTree} object, to represent a {@code @return} tag
|
||||
* or {@code {@return}} tag.
|
||||
*
|
||||
* @implSpec This implementation throws {@code UnsupportedOperationException} if
|
||||
* {@code isInline} is {@code true}, and calls {@link #newReturnTree(List)} otherwise.
|
||||
*
|
||||
* @param description the description of the return value of a method
|
||||
* @return a {@code ReturnTree} object
|
||||
* @throws UnsupportedOperationException if inline {@code {@return}} tags are
|
||||
* not supported
|
||||
* @since 16
|
||||
*/
|
||||
default ReturnTree newReturnTree(boolean isInline, List<? extends DocTree> description) {
|
||||
if (isInline) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
return newReturnTree(description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code SeeTree} object, to represent a {@code @see} tag.
|
||||
* @param reference the reference
|
||||
|
||||
@ -300,9 +300,19 @@ public class JavacTrees extends DocTrees {
|
||||
return getEndPosition(file, comment, last) + correction;
|
||||
}
|
||||
|
||||
DCBlockTag block = (DCBlockTag) tree;
|
||||
int pos;
|
||||
String name;
|
||||
if (tree.getKind() == DocTree.Kind.RETURN) {
|
||||
DCTree.DCReturn dcReturn = (DCTree.DCReturn) tree;
|
||||
pos = dcReturn.pos;
|
||||
name = dcReturn.getTagName();
|
||||
} else {
|
||||
DCBlockTag block = (DCBlockTag) tree;
|
||||
pos = block.pos;
|
||||
name = block.getTagName();
|
||||
}
|
||||
|
||||
return dcComment.comment.getSourcePos(block.pos + block.getTagName().length() + 1);
|
||||
return dcComment.comment.getSourcePos(pos + name.length() + 1);
|
||||
}
|
||||
case ENTITY: {
|
||||
DCEntity endEl = (DCEntity) tree;
|
||||
|
||||
@ -269,11 +269,10 @@ public class DocCommentParser {
|
||||
List<DCTree> content = blockContent();
|
||||
return m.at(p).newUnknownBlockTagTree(name, content);
|
||||
} else {
|
||||
switch (tp.getKind()) {
|
||||
case BLOCK:
|
||||
return tp.parse(p);
|
||||
case INLINE:
|
||||
return erroneous("dc.bad.inline.tag", p);
|
||||
if (tp.allowsBlock()) {
|
||||
return tp.parse(p, TagParser.Kind.BLOCK);
|
||||
} else {
|
||||
return erroneous("dc.bad.inline.tag", p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -311,33 +310,29 @@ public class DocCommentParser {
|
||||
int p = bp - 1;
|
||||
try {
|
||||
nextChar();
|
||||
if (isIdentifierStart(ch)) {
|
||||
Name name = readTagName();
|
||||
TagParser tp = tagParsers.get(name);
|
||||
|
||||
if (tp == null) {
|
||||
if (!isIdentifierStart(ch)) {
|
||||
return erroneous("dc.no.tag.name", p);
|
||||
}
|
||||
Name name = readTagName();
|
||||
TagParser tp = tagParsers.get(name);
|
||||
if (tp == null) {
|
||||
skipWhitespace();
|
||||
DCTree text = inlineText(WhitespaceRetentionPolicy.REMOVE_ALL);
|
||||
nextChar();
|
||||
return m.at(p).newUnknownInlineTagTree(name, List.of(text)).setEndPos(bp);
|
||||
} else {
|
||||
if (!tp.retainWhiteSpace) {
|
||||
skipWhitespace();
|
||||
DCTree text = inlineText(WhitespaceRetentionPolicy.REMOVE_ALL);
|
||||
if (text != null) {
|
||||
nextChar();
|
||||
return m.at(p).newUnknownInlineTagTree(name, List.of(text)).setEndPos(bp);
|
||||
}
|
||||
} else {
|
||||
if (!tp.retainWhiteSpace) {
|
||||
skipWhitespace();
|
||||
}
|
||||
if (tp.getKind() == TagParser.Kind.INLINE) {
|
||||
DCEndPosTree<?> tree = (DCEndPosTree<?>) tp.parse(p);
|
||||
if (tree != null) {
|
||||
return tree.setEndPos(bp);
|
||||
}
|
||||
} else { // handle block tags (for example, @see) in inline content
|
||||
inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); // skip content
|
||||
nextChar();
|
||||
}
|
||||
}
|
||||
if (tp.allowsInline()) {
|
||||
DCEndPosTree<?> tree = (DCEndPosTree<?>) tp.parse(p, TagParser.Kind.INLINE);
|
||||
return tree.setEndPos(bp);
|
||||
} else { // handle block tags (for example, @see) in inline content
|
||||
DCTree text = inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); // skip content
|
||||
nextChar();
|
||||
return m.at(p).newUnknownInlineTagTree(name, List.of(text)).setEndPos(bp);
|
||||
}
|
||||
}
|
||||
return erroneous("dc.no.tag.name", p);
|
||||
} catch (ParseException e) {
|
||||
return erroneous(e.getMessage(), p);
|
||||
}
|
||||
@ -574,9 +569,21 @@ public class DocCommentParser {
|
||||
* Read general text content of an inline tag, including HTML entities and elements.
|
||||
* Matching pairs of { } are skipped; the text is terminated by the first
|
||||
* unmatched }. It is an error if the beginning of the next tag is detected.
|
||||
* Nested tags are not permitted.
|
||||
*/
|
||||
private List<DCTree> inlineContent() {
|
||||
return inlineContent(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read general text content of an inline tag, including HTML entities and elements.
|
||||
* Matching pairs of { } are skipped; the text is terminated by the first
|
||||
* unmatched }. It is an error if the beginning of the next tag is detected.
|
||||
*
|
||||
* @param allowNestedTags whether or not to allow nested tags
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
private List<DCTree> inlineContent() {
|
||||
private List<DCTree> inlineContent(boolean allowNestedTags) {
|
||||
ListBuffer<DCTree> trees = new ListBuffer<>();
|
||||
|
||||
skipWhitespace();
|
||||
@ -604,14 +611,23 @@ public class DocCommentParser {
|
||||
newline = false;
|
||||
addPendingText(trees, bp - 1);
|
||||
trees.add(html());
|
||||
textStart = bp;
|
||||
lastNonWhite = -1;
|
||||
break;
|
||||
|
||||
case '{':
|
||||
if (textStart == -1)
|
||||
textStart = bp;
|
||||
newline = false;
|
||||
depth++;
|
||||
nextChar();
|
||||
if (ch == '@' && allowNestedTags) {
|
||||
addPendingText(trees, bp - 2);
|
||||
trees.add(inlineTag());
|
||||
textStart = bp;
|
||||
lastNonWhite = -1;
|
||||
} else {
|
||||
depth++;
|
||||
}
|
||||
break;
|
||||
|
||||
case '}':
|
||||
@ -1071,7 +1087,7 @@ public class DocCommentParser {
|
||||
}
|
||||
|
||||
private static abstract class TagParser {
|
||||
enum Kind { INLINE, BLOCK }
|
||||
enum Kind { INLINE, BLOCK, EITHER }
|
||||
|
||||
final Kind kind;
|
||||
final DCTree.Kind treeKind;
|
||||
@ -1089,19 +1105,32 @@ public class DocCommentParser {
|
||||
this.retainWhiteSpace = retainWhiteSpace;
|
||||
}
|
||||
|
||||
Kind getKind() {
|
||||
return kind;
|
||||
boolean allowsBlock() {
|
||||
return kind != Kind.INLINE;
|
||||
}
|
||||
|
||||
boolean allowsInline() {
|
||||
return kind != Kind.BLOCK;
|
||||
}
|
||||
|
||||
DCTree.Kind getTreeKind() {
|
||||
return treeKind;
|
||||
}
|
||||
|
||||
abstract DCTree parse(int pos) throws ParseException;
|
||||
DCTree parse(int pos, Kind kind) throws ParseException {
|
||||
if (kind != this.kind && this.kind != Kind.EITHER) {
|
||||
throw new IllegalArgumentException(kind.toString());
|
||||
}
|
||||
return parse(pos);
|
||||
}
|
||||
|
||||
DCTree parse(int pos) throws ParseException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see <a href="https://docs.oracle.com/en/java/javase/14/docs/specs/javadoc/doc-comment-spec.html">Javadoc Tags</a>
|
||||
* @see <a href="https://docs.oracle.com/en/java/javase/15/docs/specs/javadoc/doc-comment-spec.html">JavaDoc Tags</a>
|
||||
*/
|
||||
private Map<Name, TagParser> createTagParsers() {
|
||||
TagParser[] parsers = {
|
||||
@ -1271,12 +1300,22 @@ public class DocCommentParser {
|
||||
}
|
||||
},
|
||||
|
||||
// @return description
|
||||
new TagParser(TagParser.Kind.BLOCK, DCTree.Kind.RETURN) {
|
||||
// @return description -or- {@return description}
|
||||
new TagParser(TagParser.Kind.EITHER, DCTree.Kind.RETURN) {
|
||||
@Override
|
||||
public DCTree parse(int pos) {
|
||||
List<DCTree> description = blockContent();
|
||||
return m.at(pos).newReturnTree(description);
|
||||
public DCTree parse(int pos, Kind kind) {
|
||||
List<DCTree> description;
|
||||
switch (kind) {
|
||||
case BLOCK:
|
||||
description = blockContent();
|
||||
break;
|
||||
case INLINE:
|
||||
description = inlineContent(true);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(kind.toString());
|
||||
}
|
||||
return m.at(pos).newReturnTree(kind == Kind.INLINE, description);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -677,13 +677,20 @@ public abstract class DCTree implements DocTree {
|
||||
}
|
||||
}
|
||||
|
||||
public static class DCReturn extends DCBlockTag implements ReturnTree {
|
||||
public static class DCReturn extends DCEndPosTree<DCReturn> implements ReturnTree {
|
||||
public final boolean inline;
|
||||
public final List<DCTree> description;
|
||||
|
||||
DCReturn(List<DCTree> description) {
|
||||
DCReturn(boolean inline, List<DCTree> description) {
|
||||
this.inline = inline;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public String getTagName() {
|
||||
return "return";
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public Kind getKind() {
|
||||
return Kind.RETURN;
|
||||
@ -694,6 +701,11 @@ public abstract class DCTree implements DocTree {
|
||||
return v.visitReturn(this, d);
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public boolean isInline() {
|
||||
return inline;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public List<? extends DocTree> getDescription() {
|
||||
return description;
|
||||
|
||||
@ -399,9 +399,15 @@ public class DocPretty implements DocTreeVisitor<Void,Void> {
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public Void visitReturn(ReturnTree node, Void p) {
|
||||
try {
|
||||
if (node.isInline()) {
|
||||
print("{");
|
||||
}
|
||||
printTagName(node);
|
||||
print(" ");
|
||||
print(node.getDescription());
|
||||
if (node.isInline()) {
|
||||
print("}");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
|
||||
@ -386,7 +386,12 @@ public class DocTreeMaker implements DocTreeFactory {
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public DCReturn newReturnTree(List<? extends DocTree> description) {
|
||||
DCReturn tree = new DCReturn(cast(description));
|
||||
return newReturnTree(false, description);
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public DCReturn newReturnTree(boolean isInline, List<? extends DocTree> description) {
|
||||
DCReturn tree = new DCReturn(isInline, cast(description));
|
||||
tree.pos = pos;
|
||||
return tree;
|
||||
}
|
||||
@ -533,6 +538,7 @@ public class DocTreeMaker implements DocTreeFactory {
|
||||
continue;
|
||||
}
|
||||
switch (dt.getKind()) {
|
||||
case RETURN:
|
||||
case SUMMARY:
|
||||
foundFirstSentence = true;
|
||||
break;
|
||||
|
||||
@ -174,22 +174,35 @@ public class JavadocFormatter {
|
||||
if (current.matches(t)) {
|
||||
if (!seenAny) {
|
||||
seenAny = true;
|
||||
if (result.charAt(result.length() - 1) != '\n')
|
||||
result.append("\n");
|
||||
result.append("\n");
|
||||
result.append(escape(CODE_UNDERLINE))
|
||||
.append(docSections.get(current))
|
||||
.append(escape(CODE_RESET))
|
||||
.append("\n");
|
||||
startSection(current);
|
||||
}
|
||||
|
||||
scan(t, null);
|
||||
}
|
||||
}
|
||||
if (current == Sections.RETURNS && !seenAny) {
|
||||
List<? extends DocTree> firstSentence = node.getFirstSentence();
|
||||
if (firstSentence.size() == 1
|
||||
&& firstSentence.get(0).getKind() == DocTree.Kind.RETURN) {
|
||||
startSection(current);
|
||||
scan(firstSentence.get(0), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void startSection(Sections current) {
|
||||
if (result.charAt(result.length() - 1) != '\n')
|
||||
result.append("\n");
|
||||
result.append("\n");
|
||||
result.append(escape(CODE_UNDERLINE))
|
||||
.append(docSections.get(current))
|
||||
.append(escape(CODE_RESET))
|
||||
.append("\n");
|
||||
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public Object visitText(TextTree node, Object p) {
|
||||
String text = node.getBody();
|
||||
@ -250,13 +263,34 @@ public class JavadocFormatter {
|
||||
return scan(node.getBody(), p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* {@code @return} is a bimodal tag and can be used as either a block tag or an inline
|
||||
* tag. If the parameter {@code p} is {@code null}, the node will be formatted according to
|
||||
* the value of {@link ReturnTree#isInline()}. If the parameter is not {@code null}, the node will
|
||||
* be formatted as a block tag.
|
||||
* @param node {@inheritDoc}
|
||||
* @param p not {@code null} to force the node to be formatted as a block tag
|
||||
* @return
|
||||
*/
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public Object visitReturn(ReturnTree node, Object p) {
|
||||
reflownTo = result.length();
|
||||
try {
|
||||
return super.visitReturn(node, p);
|
||||
} finally {
|
||||
reflow(result, reflownTo, 0, limit);
|
||||
if (node.isInline() && p == null) {
|
||||
String MARKER = "{0}";
|
||||
int p0 = inlineReturns.indexOf(MARKER);
|
||||
result.append(inlineReturns, 0, p0);
|
||||
try {
|
||||
return super.visitReturn(node, p);
|
||||
} finally {
|
||||
result.append(inlineReturns.substring(p0 + MARKER.length()));
|
||||
}
|
||||
} else {
|
||||
reflownTo = result.length();
|
||||
try {
|
||||
return super.visitReturn(node, p);
|
||||
} finally {
|
||||
reflow(result, reflownTo, 0, limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -569,6 +603,7 @@ public class JavadocFormatter {
|
||||
}
|
||||
|
||||
private static final Map<Sections, String> docSections = new LinkedHashMap<>();
|
||||
private static final String inlineReturns;
|
||||
|
||||
static {
|
||||
ResourceBundle bundle =
|
||||
@ -577,6 +612,7 @@ public class JavadocFormatter {
|
||||
docSections.put(Sections.PARAMS, bundle.getString("CAP_Parameters"));
|
||||
docSections.put(Sections.RETURNS, bundle.getString("CAP_Returns"));
|
||||
docSections.put(Sections.THROWS, bundle.getString("CAP_Thrown_Exceptions"));
|
||||
inlineReturns = bundle.getString("Inline_Returns");
|
||||
}
|
||||
|
||||
private static String indentString(int indent) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2016, 2020, 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
|
||||
@ -27,3 +27,4 @@ CAP_TypeParameters=Type Parameters:
|
||||
CAP_Parameters=Parameters:
|
||||
CAP_Returns=Returns:
|
||||
CAP_Thrown_Exceptions=Thrown Exceptions:
|
||||
Inline_Returns=Returns {0}.
|
||||
|
||||
@ -1384,9 +1384,8 @@ public class HtmlDocletWriter {
|
||||
StartElementTree st = (StartElementTree)tag;
|
||||
Name name = st.getName();
|
||||
if (name != null) {
|
||||
jdk.javadoc.internal.doclint.HtmlTag htag =
|
||||
jdk.javadoc.internal.doclint.HtmlTag.get(name);
|
||||
return htag != null && htag.equals(jdk.javadoc.internal.doclint.HtmlTag.A);
|
||||
HtmlTag htag = HtmlTag.get(name);
|
||||
return htag != null && htag.equals(HtmlTag.A);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -210,12 +210,13 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Content returnTagOutput(Element element, ReturnTree returnTag) {
|
||||
public Content returnTagOutput(Element element, ReturnTree returnTag, boolean inline) {
|
||||
CommentHelper ch = utils.getCommentHelper(element);
|
||||
return new ContentBuilder(
|
||||
HtmlTree.DT(contents.returns),
|
||||
HtmlTree.DD(htmlWriter.commentTagsToContent(
|
||||
returnTag, element, ch.getDescription(returnTag), false, inSummary)));
|
||||
List<? extends DocTree> desc = ch.getDescription(returnTag);
|
||||
Content content = htmlWriter.commentTagsToContent(returnTag, element, desc , false, inSummary);
|
||||
return inline
|
||||
? new ContentBuilder(contents.getContent("doclet.Returns_0", content))
|
||||
: new ContentBuilder(HtmlTree.DT(contents.returns), HtmlTree.DD(content));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -100,6 +100,7 @@ doclet.TypeParameters_dup_warn=Type parameter "{0}" is documented more than once
|
||||
doclet.RecordComponents_warn=@param argument "{0}" is not the name of a record component.
|
||||
doclet.RecordComponents_dup_warn=Record component "{0}" is documented more than once.
|
||||
doclet.Returns=Returns:
|
||||
doclet.Returns_0=Returns {0}.
|
||||
doclet.Return_tag_on_void_method=@return tag cannot be used in method with void return type.
|
||||
doclet.See_Also=See Also:
|
||||
doclet.SerialData=Serial Data:
|
||||
|
||||
@ -44,7 +44,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Input;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||
|
||||
/**
|
||||
* A taglet that represents the @return tag.
|
||||
* A taglet that represents the {@code @return} and {@code {@return }} tags.
|
||||
*
|
||||
* <p><b>This is NOT part of any supported API.
|
||||
* If you write code that depends on this, you do so at your own risk.
|
||||
@ -54,47 +54,77 @@ import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||
public class ReturnTaglet extends BaseTaglet implements InheritableTaglet {
|
||||
|
||||
public ReturnTaglet() {
|
||||
super(DocTree.Kind.RETURN, false, EnumSet.of(Location.METHOD));
|
||||
super(DocTree.Kind.RETURN, true, EnumSet.of(Location.METHOD));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockTag() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inherit(DocFinder.Input input, DocFinder.Output output) {
|
||||
List<? extends ReturnTree> tags = input.utils.getReturnTrees(input.element);
|
||||
CommentHelper ch = input.utils.getCommentHelper(input.element);
|
||||
Utils utils = input.utils;
|
||||
CommentHelper ch = utils.getCommentHelper(input.element);
|
||||
|
||||
ReturnTree tag = null;
|
||||
List<? extends ReturnTree> tags = utils.getReturnTrees(input.element);
|
||||
if (!tags.isEmpty()) {
|
||||
tag = tags.get(0);
|
||||
} else {
|
||||
List<? extends DocTree> firstSentence = utils.getFirstSentenceTrees(input.element);
|
||||
if (firstSentence.size() == 1 && firstSentence.get(0).getKind() == DocTree.Kind.RETURN) {
|
||||
tag = (ReturnTree) firstSentence.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (tag != null) {
|
||||
output.holder = input.element;
|
||||
output.holderTag = tags.get(0);
|
||||
output.holderTag = tag;
|
||||
output.inlineTags = input.isFirstSentence
|
||||
? ch.getFirstSentenceTrees(output.holderTag)
|
||||
: ch.getDescription(output.holderTag);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter writer) {
|
||||
return writer.returnTagOutput(element, (ReturnTree) tag, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Content getAllBlockTagOutput(Element holder, TagletWriter writer) {
|
||||
Messages messages = writer.configuration().getMessages();
|
||||
Utils utils = writer.configuration().utils;
|
||||
TypeMirror returnType = utils.getReturnType(writer.getCurrentPageElement(), (ExecutableElement)holder);
|
||||
List<? extends ReturnTree> tags = utils.getReturnTrees(holder);
|
||||
|
||||
//Make sure we are not using @return tag on method with void return type.
|
||||
// Make sure we are not using @return tag on method with void return type.
|
||||
TypeMirror returnType = utils.getReturnType(writer.getCurrentPageElement(), (ExecutableElement)holder);
|
||||
if (returnType != null && utils.isVoid(returnType)) {
|
||||
if (!tags.isEmpty()) {
|
||||
messages.warning(holder, "doclet.Return_tag_on_void_method");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (!tags.isEmpty())
|
||||
return writer.returnTagOutput(holder, tags.get(0));
|
||||
//Inherit @return tag if necessary.
|
||||
List<DocTree> ntags = new ArrayList<>();
|
||||
|
||||
if (!tags.isEmpty()) {
|
||||
return writer.returnTagOutput(holder, tags.get(0), false);
|
||||
}
|
||||
|
||||
// Check for inline tag in first sentence.
|
||||
List<? extends DocTree> firstSentence = utils.getFirstSentenceTrees(holder);
|
||||
if (firstSentence.size() == 1 && firstSentence.get(0).getKind() == DocTree.Kind.RETURN) {
|
||||
return writer.returnTagOutput(holder, (ReturnTree) firstSentence.get(0), false);
|
||||
}
|
||||
|
||||
// Inherit @return tag if necessary.
|
||||
Input input = new DocFinder.Input(utils, holder, this);
|
||||
DocFinder.Output inheritedDoc = DocFinder.search(writer.configuration(), input);
|
||||
if (inheritedDoc.holderTag != null) {
|
||||
CommentHelper ch = utils.getCommentHelper(input.element);
|
||||
ch.setOverrideElement(inheritedDoc.holder);
|
||||
ntags.add(inheritedDoc.holderTag);
|
||||
return writer.returnTagOutput(holder, (ReturnTree) inheritedDoc.holderTag, false);
|
||||
}
|
||||
return !ntags.isEmpty() ? writer.returnTagOutput(holder, (ReturnTree) ntags.get(0)) : null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -733,7 +733,8 @@ public class TagletManager {
|
||||
taglets.addAll(allTaglets.values());
|
||||
|
||||
for (Taglet t : taglets) {
|
||||
String name = t.isInlineTag() ? "{@" + t.getName() + "}" : "@" + t.getName();
|
||||
// give preference to simpler block form if a tag can be either
|
||||
String name = t.isBlockTag() ? "@" + t.getName() : "{@" + t.getName() + "}";
|
||||
out.println(String.format("%20s", name) + ": "
|
||||
+ format(t.isBlockTag(), "block")+ " "
|
||||
+ format(t.inOverview(), "overview") + " "
|
||||
|
||||
@ -145,12 +145,13 @@ public abstract class TagletWriter {
|
||||
/**
|
||||
* Returns the output for a {@code @return} tag.
|
||||
*
|
||||
* @param element The element that owns the doc comment
|
||||
* @param element the element that owns the doc comment
|
||||
* @param returnTag the return tag to document
|
||||
* @param inline whether this should be written as an inline instance or block instance
|
||||
*
|
||||
* @return the output
|
||||
*/
|
||||
protected abstract Content returnTagOutput(Element element, ReturnTree returnTag);
|
||||
protected abstract Content returnTagOutput(Element element, ReturnTree returnTag, boolean inline);
|
||||
|
||||
/**
|
||||
* Returns the output for {@code @see} tags.
|
||||
|
||||
@ -939,6 +939,12 @@ public class Checker extends DocTreePathScanner<Void, Void> {
|
||||
if (foundReturn) {
|
||||
env.messages.warning(REFERENCE, tree, "dc.exists.return");
|
||||
}
|
||||
if (tree.isInline()) {
|
||||
DocCommentTree dct = getCurrentPath().getDocComment();
|
||||
if (tree != dct.getFirstSentence().get(0)) {
|
||||
env.messages.warning(REFERENCE, tree, "dc.return.not.first");
|
||||
}
|
||||
}
|
||||
|
||||
Element e = env.trees.getElement(env.currPath);
|
||||
if (e.getKind() != ElementKind.METHOD
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2012, 2020, 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
|
||||
@ -57,8 +57,9 @@ dc.no.alt.attr.for.image = no "alt" attribute for image
|
||||
dc.no.summary.or.caption.for.table=no summary or caption for table
|
||||
dc.param.name.not.found = @param name not found
|
||||
dc.ref.not.found = reference not found
|
||||
dc.return.not.first = '{@return} not at beginning of description
|
||||
dc.service.not.found = service-type not found
|
||||
dc.tag.code.within.code = '{@code'} within <code>
|
||||
dc.tag.code.within.code = '{@code} within <code>
|
||||
dc.tag.empty = empty <{0}> tag
|
||||
dc.tag.a.within.a = {0} tag, which expands to <a>, within <a>
|
||||
dc.tag.end.not.permitted = invalid end tag: </{0}>
|
||||
@ -81,7 +82,7 @@ dc.tag.unknown = unknown tag: {0}
|
||||
dc.tag.not.supported = tag not supported in the generated HTML version: {0}
|
||||
dc.text.not.allowed = text not allowed in <{0}> element
|
||||
dc.unexpected.comment=documentation comment not expected here
|
||||
dc.value.not.allowed.here='{@value}' not allowed here
|
||||
dc.value.not.allowed.here='{@value} not allowed here
|
||||
dc.value.not.a.constant=value does not refer to a constant
|
||||
|
||||
dc.main.ioerror=IO error: {0}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2020, 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
|
||||
@ -137,7 +137,7 @@ public class JavadocFormatterTest {
|
||||
"1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" +
|
||||
"1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" +
|
||||
"1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234\n" +
|
||||
"1234 1234 1234 1234 1234 1234 1234 1234 1234\n";
|
||||
"1234 1234 1234 1234 1234 1234 1234 1234 1234 \n";
|
||||
|
||||
if (!Objects.equals(actual, expected)) {
|
||||
throw new AssertionError("Incorrect output: " + actual);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2020, 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
|
||||
@ -23,39 +23,409 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4490068
|
||||
* @summary Warn when a return tag is used on a method without a return type.
|
||||
* @library ../../lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.tool
|
||||
* @build javadoc.tester.*
|
||||
* @bug 4490068 8075778
|
||||
* @summary General tests for inline or block at-return tag
|
||||
* @library /tools/lib ../../lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.tool
|
||||
* @build toolbox.ToolBox javadoc.tester.*
|
||||
* @run main TestReturnTag
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javadoc.tester.JavadocTester;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
public class TestReturnTag extends JavadocTester {
|
||||
|
||||
/**
|
||||
* Trigger warning message when return tag is used on a void method.
|
||||
*
|
||||
* @return I really don't return anything.
|
||||
*/
|
||||
public void method() {}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
TestReturnTag tester = new TestReturnTag();
|
||||
tester.runTests();
|
||||
tester.runTests(m -> new Object[] { Path.of(m.getName()) });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tests() {
|
||||
ToolBox tb = new ToolBox();
|
||||
|
||||
@Test // 4490068
|
||||
public void testInvalidReturn(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
/** Comment. */
|
||||
public class C {
|
||||
/**
|
||||
* Trigger warning message when return tag is used on a void method.
|
||||
*
|
||||
* @return I really don't return anything.
|
||||
*/
|
||||
public void method() {}
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-Xdoclint:none",
|
||||
"-d", "out",
|
||||
"-sourcepath", testSrc,
|
||||
testSrc("TestReturnTag.java"));
|
||||
"-d", base.resolve("out").toString(),
|
||||
"-sourcepath", src.toString(),
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput(Output.OUT, true,
|
||||
"warning - @return tag cannot be used in method with void return type.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlock(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
/** Comment. */
|
||||
public class C {
|
||||
/**
|
||||
* First sentence. Second sentence.
|
||||
* @return the result
|
||||
*/
|
||||
public int m() { return 0; }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-Xdoclint:none",
|
||||
"-d", base.resolve("out").toString(),
|
||||
"-sourcepath", src.toString(),
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("C.html", true,
|
||||
"""
|
||||
<div class="block">First sentence. Second sentence.</div>
|
||||
<dl class="notes">
|
||||
<dt>Returns:</dt>
|
||||
<dd>the result</dd>
|
||||
</dl>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInlineShort(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
/** Comment. */
|
||||
public class C {
|
||||
/**
|
||||
* {@return the result}
|
||||
*/
|
||||
public int m() { return 0; }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-Xdoclint:none",
|
||||
"-d", base.resolve("out").toString(),
|
||||
"-sourcepath", src.toString(),
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("C.html", true,
|
||||
"""
|
||||
<div class="block">Returns the result.</div>
|
||||
<dl class="notes">
|
||||
<dt>Returns:</dt>
|
||||
<dd>the result</dd>
|
||||
</dl>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInlineLong(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
/** Comment. */
|
||||
public class C {
|
||||
/**
|
||||
* {@return the result} More text.
|
||||
*/
|
||||
public int m() { return 0; }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-Xdoclint:none",
|
||||
"-d", base.resolve("out").toString(),
|
||||
"-sourcepath", src.toString(),
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("C.html", true,
|
||||
"""
|
||||
<div class="block">Returns the result. More text.</div>
|
||||
<dl class="notes">
|
||||
<dt>Returns:</dt>
|
||||
<dd>the result</dd>
|
||||
</dl>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInlineMarkup(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
/** Comment. */
|
||||
public class C {
|
||||
/**
|
||||
* {@return abc {@code def} <b>ghi</b> jkl}
|
||||
*/
|
||||
public int m() { return 0; }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-Xdoclint:none",
|
||||
"-d", base.resolve("out").toString(),
|
||||
"-sourcepath", src.toString(),
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("C.html", true,
|
||||
"""
|
||||
<div class="block">Returns abc <code>def</code> <b>ghi</b> jkl.</div>
|
||||
<dl class="notes">
|
||||
<dt>Returns:</dt>
|
||||
<dd>abc <code>def</code> <b>ghi</b> jkl</dd>
|
||||
</dl>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockMarkup(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
/** Comment. */
|
||||
public class C {
|
||||
/**
|
||||
* @return abc {@code def} <b>ghi</b> jkl
|
||||
*/
|
||||
public int m() { return 0; }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-Xdoclint:none",
|
||||
"-d", base.resolve("out").toString(),
|
||||
"-sourcepath", src.toString(),
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("C.html", true,
|
||||
"""
|
||||
<dl class="notes">
|
||||
<dt>Returns:</dt>
|
||||
<dd>abc <code>def</code> <b>ghi</b> jkl</dd>
|
||||
</dl>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyInline(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
/** Comment. */
|
||||
public class C {
|
||||
/**
|
||||
* {@return}
|
||||
*/
|
||||
public int m() { return 0; }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"-sourcepath", src.toString(),
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput(Output.OUT, true,
|
||||
"C.java:4: warning: no description for @return");
|
||||
|
||||
checkOutput("C.html", true,
|
||||
"""
|
||||
<div class="block">Returns .</div>
|
||||
<dl class="notes">
|
||||
<dt>Returns:</dt>
|
||||
</dl>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInlineNotFirst(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
/** Comment. */
|
||||
public class C {
|
||||
/**
|
||||
* Some text. {@return the result} More text.
|
||||
*/
|
||||
public int m() { return 0; }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"-sourcepath", src.toString(),
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput(Output.OUT, true,
|
||||
"C.java:4: warning: {@return} not at beginning of description");
|
||||
|
||||
checkOutput("C.html", true,
|
||||
"""
|
||||
<div class="block">Some text. Returns the result. More text.</div>
|
||||
</section>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicate(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
/** Comment. */
|
||||
public class C {
|
||||
/**
|
||||
* {@return the result} More text.
|
||||
* @return again
|
||||
*/
|
||||
public int m() { return 0; }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc( "-d", base.resolve("out").toString(),
|
||||
"-sourcepath", src.toString(),
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput(Output.OUT, true,
|
||||
"C.java:5: warning: @return has already been specified");
|
||||
|
||||
checkOutput("C.html", true,
|
||||
"""
|
||||
<div class="block">Returns the result. More text.</div>
|
||||
<dl class="notes">
|
||||
<dt>Returns:</dt>
|
||||
<dd>again</dd>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleInheritBlock(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
/** Comment. */
|
||||
public class Super {
|
||||
/**
|
||||
* @return the result
|
||||
*/
|
||||
public int m() { return 0; }
|
||||
}
|
||||
""",
|
||||
"""
|
||||
/** Comment. */
|
||||
public class C extends Super {
|
||||
@Override
|
||||
public int m() { return 1; }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc( "-d", base.resolve("out").toString(),
|
||||
"-sourcepath", src.toString(),
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("C.html", true,
|
||||
"""
|
||||
<dl class="notes">
|
||||
<dt>Overrides:</dt>
|
||||
<dd><code>m</code> in class <code>Super</code></dd>
|
||||
<dt>Returns:</dt>
|
||||
<dd>the result</dd>
|
||||
</dl>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleInheritInline(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
/** Comment. */
|
||||
public class Super {
|
||||
/**
|
||||
* {@return the result}
|
||||
*/
|
||||
public int m() { return 0; }
|
||||
}
|
||||
""",
|
||||
"""
|
||||
/** Comment. */
|
||||
public class C extends Super {
|
||||
@Override
|
||||
public int m() { return 1; }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc( "-d", base.resolve("out").toString(),
|
||||
"-sourcepath", src.toString(),
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("C.html", true,
|
||||
"""
|
||||
<div class="block"><span class="descfrm-type-label">Description copied from class: <code>Super</code></span></div>
|
||||
<div class="block">Returns the result.</div>
|
||||
<dl class="notes">
|
||||
<dt>Overrides:</dt>
|
||||
<dd><code>m</code> in class <code>Super</code></dd>
|
||||
<dt>Returns:</dt>
|
||||
<dd>the result</dd>""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreferInlineOverInherit(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src,
|
||||
"""
|
||||
/** Comment. */
|
||||
public class Super {
|
||||
/**
|
||||
* {@return the result}
|
||||
*/
|
||||
public int m() { return 0; }
|
||||
}
|
||||
""",
|
||||
"""
|
||||
/** Comment. */
|
||||
public class C extends Super {
|
||||
/**
|
||||
* {@return the overriding result}
|
||||
*/
|
||||
@Override
|
||||
public int m() { return 1; }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc( "-d", base.resolve("out").toString(),
|
||||
"-sourcepath", src.toString(),
|
||||
src.resolve("C.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("C.html", true,
|
||||
"""
|
||||
<div class="block">Returns the overriding result.</div>
|
||||
<dl class="notes">
|
||||
<dt>Overrides:</dt>
|
||||
<dd><code>m</code> in class <code>Super</code></dd>
|
||||
<dt>Returns:</dt>
|
||||
<dd>the overriding result</dd>
|
||||
</dl>
|
||||
""");
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
@param: block ........ ...... ....... type constructor method ..... ...... ........
|
||||
@propertyDescription: block ........ ...... ....... .... ........... method field ...... ........
|
||||
@provides: block ........ module ....... .... ........... ...... ..... ...... ........
|
||||
@return: block ........ ...... ....... .... ........... method ..... ...... ........
|
||||
@return: block ........ ...... ....... .... ........... method ..... inline ........
|
||||
@see: block overview module package type constructor method field ...... ........
|
||||
@serial: block ........ ...... package type ........... ...... field ...... ........
|
||||
@serialData: block ........ ...... ....... .... ........... ...... ..... ...... ........
|
||||
|
||||
@ -102,6 +102,9 @@ public class EmptyHtmlTest extends TestRunner {
|
||||
case "LiteralTree" ->
|
||||
test(d, type, "{@literal abc}");
|
||||
|
||||
case "ReturnTree" ->
|
||||
test(d, type, "{@return abc}");
|
||||
|
||||
case "SummaryTree" ->
|
||||
test(d, type, "{@summary First sentence.}");
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user