Skip to content
Permalink
Browse files
8075778: Add javadoc tag to avoid duplication of return information i…
…n simple situations.

Reviewed-by: prappo, jlahoda
  • Loading branch information
jonathan-gibbons committed Dec 8, 2020
1 parent 48d8650 commit b29f9cd7b073a8c5e514efda91aaf7115400a97f
Show file tree
Hide file tree
Showing 21 changed files with 667 additions and 112 deletions.
@@ -30,13 +30,25 @@
/**
* A tree node for an {@code @return} block tag.
*
* <pre>
* &#064;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 @@ DocCommentTree newDocCommentTree(List<? extends DocTree> fullBody,
*/
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 long getEndPosition(CompilationUnitTree file, DocCommentTree comment, Doc
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 @@ protected DCTree blockTag() {
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 @@ protected DCTree inlineTag() {
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 @@ protected DCText inlineWord() {
* 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.
*/
@SuppressWarnings("fallthrough")
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(boolean allowNestedTags) {
ListBuffer<DCTree> trees = new ListBuffer<>();

skipWhitespace();
@@ -604,14 +611,23 @@ private List<DCTree> inlineContent() {
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 @@ String newString(int start, int end) {
}

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 @@ enum Kind { INLINE, BLOCK }
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 DCTree parse(int pos) throws ParseException {
}
},

// @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 String getSignature() {
}
}

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 <R, D> R accept(DocTreeVisitor<R, D> v, D d) {
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 Void visitReference(ReferenceTree node, Void p) {
@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 DCReference newReferenceTree(String signature, JCTree.JCExpression module

@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 @@ private Pair<List<DCTree>, List<DCTree>> splitBody(Collection<? extends DocTree>
continue;
}
switch (dt.getKind()) {
case RETURN:
case SUMMARY:
foundFirstSentence = true;
break;

1 comment on commit b29f9cd

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on b29f9cd Dec 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.