diff --git a/src/jdk.compiler/share/classes/com/sun/source/doctree/ReturnTree.java b/src/jdk.compiler/share/classes/com/sun/source/doctree/ReturnTree.java index 73bf87b0c69..392700a3992 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/doctree/ReturnTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/doctree/ReturnTree.java @@ -30,13 +30,25 @@ import java.util.List; /** * A tree node for an {@code @return} block tag. * - *
- * @return description - *+ *
{@code
+ * @return description
+ * {@return description}
+ * }
*
* @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
diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java
index 54dc3d259bd..f5834a577d7 100644
--- a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java
@@ -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
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java
index 4a1c0702e06..6b14e35d93a 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java
@@ -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;
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java
index 440df2a35fa..6c89d5c537e 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java
@@ -269,11 +269,10 @@ public class DocCommentParser {
ListThis 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
+dc.tag.code.within.code = '{@code} within
dc.tag.empty = empty <{0}> tag
dc.tag.a.within.a = {0} tag, which expands to , within
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}
diff --git a/test/langtools/jdk/internal/shellsupport/doc/JavadocFormatterTest.java b/test/langtools/jdk/internal/shellsupport/doc/JavadocFormatterTest.java
index 043c7e95732..02915f5cefc 100644
--- a/test/langtools/jdk/internal/shellsupport/doc/JavadocFormatterTest.java
+++ b/test/langtools/jdk/internal/shellsupport/doc/JavadocFormatterTest.java
@@ -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);
diff --git a/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java b/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java
index 6b33ab2c15f..ba6bf527149 100644
--- a/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java
+++ b/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java
@@ -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,
+ """
+
+
+ """);
+ }
+
+ @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,
+ """
+
+
+ """);
+ }
+
+ @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,
+ """
+
+
+ """);
+ }
+
+ @Test
+ public void testInlineMarkup(Path base) throws IOException {
+ Path src = base.resolve("src");
+ tb.writeJavaFiles(src,
+ """
+ /** Comment. */
+ public class C {
+ /**
+ * {@return abc {@code def} ghi 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,
+ """
+ def ghi jkl.
+
+ """);
+ }
+
+ @Test
+ public void testBlockMarkup(Path base) throws IOException {
+ Path src = base.resolve("src");
+ tb.writeJavaFiles(src,
+ """
+ /** Comment. */
+ public class C {
+ /**
+ * @return abc {@code def} ghi 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,
+ """
+ def ghi jkl
+
+ """);
+ }
+
+ @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,
+ """
+ def ghi jkl
+
+ """);
+ }
+
+ @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,
+ """
+
+
+
+ """);
+ }
+
+ @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,
+ """
+ m in class SuperSuper
+
m in class Super
+
+ """);
+ }
}
diff --git a/test/langtools/jdk/javadoc/doclet/testTaglets/TestTaglets.out b/test/langtools/jdk/javadoc/doclet/testTaglets/TestTaglets.out
index efcf3e20d7b..a8a82d93cff 100644
--- a/test/langtools/jdk/javadoc/doclet/testTaglets/TestTaglets.out
+++ b/test/langtools/jdk/javadoc/doclet/testTaglets/TestTaglets.out
@@ -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 ........ ...... ....... .... ........... ...... ..... ...... ........
diff --git a/test/langtools/tools/doclint/EmptyHtmlTest.java b/test/langtools/tools/doclint/EmptyHtmlTest.java
index 7b07fa58825..f9df8c61cd3 100644
--- a/test/langtools/tools/doclint/EmptyHtmlTest.java
+++ b/test/langtools/tools/doclint/EmptyHtmlTest.java
@@ -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.}");
m in class Super