diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java index 033703e073f..d7a0bd2d0a0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java @@ -500,31 +500,36 @@ public class CommentHelper { } public DocTreePath getDocTreePath(DocTree dtree) { - if (dcTree == null && element instanceof ExecutableElement ee) { - return getInheritedDocTreePath(dtree, ee); + if (dcTree == null) { + // Element does not have a doc comment. + return getInheritedDocTreePath(dtree); } - if (path == null || dcTree == null || dtree == null) { + if (path == null || dtree == null) { return null; } DocTreePath dtPath = DocTreePath.getPath(path, dcTree, dtree); - if (dtPath == null && element instanceof ExecutableElement ee) { - // The overriding element has a doc tree, but it doesn't contain what we're looking for. - return getInheritedDocTreePath(dtree, ee); - } - return dtPath; + // Doc tree isn't in current element's comment, it must be inherited. + return dtPath == null ? getInheritedDocTreePath(dtree) : dtPath; } - private DocTreePath getInheritedDocTreePath(DocTree dtree, ExecutableElement ee) { + private DocTreePath getInheritedDocTreePath(DocTree dtree) { Utils utils = configuration.utils; - var docFinder = utils.docFinder(); - Optional inheritedDoc = docFinder.search(ee, - (m -> { - Optional optional = utils.getFullBody(m).isEmpty() ? Optional.empty() : Optional.of(m); - return Result.fromOptional(optional); - })).toOptional(); - return inheritedDoc.isEmpty() || inheritedDoc.get().equals(ee) - ? null - : utils.getCommentHelper(inheritedDoc.get()).getDocTreePath(dtree); + if (element instanceof ExecutableElement ee) { + var docFinder = utils.docFinder(); + Optional inheritedDoc = docFinder.search(ee, + (m -> { + Optional optional = utils.getFullBody(m).isEmpty() ? Optional.empty() : Optional.of(m); + return Result.fromOptional(optional); + })).toOptional(); + return inheritedDoc.isEmpty() || inheritedDoc.get().equals(ee) + ? null + : utils.getCommentHelper(inheritedDoc.get()).getDocTreePath(dtree); + } else if (element instanceof TypeElement te + && te.getEnclosingElement() instanceof TypeElement enclType) { + // Block tags can be inherited from enclosing types. + return utils.getCommentHelper(enclType).getDocTreePath(dtree); + } + return null; } /** diff --git a/test/langtools/jdk/javadoc/doclet/testSinceTag/TestSinceTag.java b/test/langtools/jdk/javadoc/doclet/testSinceTag/TestSinceTag.java index 8d85fa176f6..de81fad8240 100644 --- a/test/langtools/jdk/javadoc/doclet/testSinceTag/TestSinceTag.java +++ b/test/langtools/jdk/javadoc/doclet/testSinceTag/TestSinceTag.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7180906 8026567 8239804 8324342 + * @bug 7180906 8026567 8239804 8324342 8332039 * @summary Test to make sure that the since tag works correctly * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -146,4 +146,45 @@ public class TestSinceTag extends JavadocTester {
99
"""); } + + @Test + public void testSinceDefault_NestedTag(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, """ + package p; + /** + * Class C. + * @since 99 {@link C} + */ + public class C { + public static class Nested1 { + /** Class Nested, with no explicit at-since. */ + public static class Nested { } + } + }"""); + javadoc("-d", base.resolve("api").toString(), + "-Xdoclint:none", + "-sourcepath", src.toString(), + "p"); + checkExit(Exit.OK); + + checkOutput("p/C.html", true, + """ +
+
Since:
+
99 C
"""); + + checkOutput("p/C.Nested1.html", true, + """ +
+
Since:
+
99 C
"""); + + checkOutput("p/C.Nested1.Nested.html", true, + """ +
+
Since:
+
99 C
"""); + + } }