From 4166e5345283d118d76b20de579d73bd55436ea6 Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Fri, 12 Jul 2024 23:11:04 +0000 Subject: [PATCH] 8318106: Generated HTML for snippet does not always contain an id Reviewed-by: liach --- .../doclets/formats/html/HtmlIds.java | 32 +++++++++++++++++++ .../formats/html/taglets/SnippetTaglet.java | 6 +++- .../testMarkdown/TestMarkdownTaglets.java | 4 +-- .../testSnippetTag/TestLangProperties.java | 4 +-- .../testSnippetTag/TestSnippetMarkup.java | 5 +-- .../doclet/testSnippetTag/TestSnippetTag.java | 29 +++++++++++------ .../TestSnippetUnnamedPackage.java | 4 +-- 7 files changed, 65 insertions(+), 19 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java index fc772107274..48edce573d3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java @@ -36,6 +36,7 @@ import java.util.stream.Stream; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.ModuleElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; @@ -595,4 +596,35 @@ public class HtmlIds { } return HtmlId.of(idValue); } + + /** + * Returns an id for a snippet. + * + * @param e the element in whose documentation the snippet appears + * @param snippetIds the set of snippet ids already generated + * @return a unique id for the snippet + */ + public HtmlId forSnippet(Element e, Set snippetIds) { + String id = "snippet-"; + ElementKind kind = e.getKind(); + if (kind == ElementKind.PACKAGE) { + id += forPackage((PackageElement) e).name(); + } else if (kind.isDeclaredType()) { + id += forClass((TypeElement) e).name(); + } else if (kind.isExecutable()) { + id += forMember((ExecutableElement) e).getFirst().name(); + } else if (kind.isField()) { + id += forMember((VariableElement) e).name(); + } else if (kind == ElementKind.MODULE) { + id += ((ModuleElement) e).getQualifiedName(); + } else { + // while utterly unexpected, we shouldn't fail + id += "unknown-element"; + } + int counter = 1; + while (!snippetIds.add(id + counter)) { + counter++; + } + return HtmlId.of(id + counter); + } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java index e705fb0cc10..f03b3d1bde1 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 @@ -148,6 +148,8 @@ public class SnippetTaglet extends BaseTaglet { var pre = new HtmlTree(TagName.PRE).setStyle(HtmlStyle.snippet); if (id != null && !id.isBlank()) { pre.put(HtmlAttr.ID, id); + } else { + pre.put(HtmlAttr.ID, config.htmlIds.forSnippet(element, ids).name()); } var code = new HtmlTree(TagName.CODE) .addUnchecked(Text.EMPTY); // Make sure the element is always rendered @@ -232,6 +234,8 @@ public class SnippetTaglet extends BaseTaglet { return snippetContainer.add(pre.add(code)); } + private final Set ids = new HashSet<>(); + private static final class BadSnippetException extends Exception { @java.io.Serial diff --git a/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownTaglets.java b/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownTaglets.java index fa9d3bbad12..abf7bb13593 100644 --- a/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownTaglets.java +++ b/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownTaglets.java @@ -121,7 +121,7 @@ public class TestMarkdownTaglets extends JavadocTester {
-
   this is snippet_standalone
+                    
   this is snippet_standalone
                     
@@ -131,7 +131,7 @@ public class TestMarkdownTaglets extends JavadocTester {

First sentence.

Before.

-
   this is a snippet_wrapped
+                    
   this is a snippet_wrapped
                     
diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestLangProperties.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestLangProperties.java index 49b328f314d..2edd2d34c4c 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestLangProperties.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestLangProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, 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 @@ -179,7 +179,7 @@ public class TestLangProperties extends SnippetTester {
%s
""".formatted(index, getSnippetHtmlRepresentation("A.html", - t.expectedOutput(), Optional.of("properties"))); + t.expectedOutput(), Optional.of("properties"), Optional.of("snippet-case" + index + "()2"))); checkOutput("A.html", true, html); }); } diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java index 5d9eb794613..9a332fde1a9 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, 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 @@ -52,6 +52,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; import java.util.regex.MatchResult; @@ -365,7 +366,7 @@ First line // @highlight : case%s()
%s -
""".formatted(index, getSnippetHtmlRepresentation("A.html", t.expectedOutput())); + """.formatted(index, getSnippetHtmlRepresentation("A.html", t.expectedOutput(), Optional.empty(), Optional.of("snippet-case" + index + "()2"))); checkOutput("A.html", true, html); }); } diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java index b7b54dfdb26..7e79232ef72 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 @@ -220,8 +220,9 @@ public class TestSnippetTag extends SnippetTester { checkLinks(); for (int j = 0; j < snippets.size(); j++) { var attr = snippets.get(j); + Optional id = (attr.id() != null ? Optional.of(attr.id()) : Optional.of("snippet-case" + j + "()1")); var snippetHtml = getSnippetHtmlRepresentation("pkg/A.html", " Hello, Snippet!\n", - Optional.ofNullable(attr.lang()), Optional.ofNullable(attr.id())); + Optional.ofNullable(attr.lang()), id); checkOutput("pkg/A.html", true, """ case%s() @@ -879,7 +880,8 @@ public class TestSnippetTag extends SnippetTester { """ case%s()
- %s""".formatted(id, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput()))); + %s""".formatted(id, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput(), Optional.empty(), + Optional.of("snippet-case" + id + "()2")))); }); } @@ -971,7 +973,8 @@ public class TestSnippetTag extends SnippetTester { """ case%s()
- %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", expectedOutput))); + %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", expectedOutput, Optional.empty(), + Optional.of("snippet-case" + index + "()2")))); }); } @@ -1549,7 +1552,8 @@ public class TestSnippetTag extends SnippetTester { """ case%s()
- %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput()))); + %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput(), Optional.empty(), + Optional.of("snippet-case" + index + "()2")))); }); } @@ -1662,12 +1666,14 @@ public class TestSnippetTag extends SnippetTester { """ case0()
- """ + getSnippetHtmlRepresentation("pkg/A.html", "")); + """ + getSnippetHtmlRepresentation("pkg/A.html", "", Optional.empty(), + Optional.of("snippet-case0()2"))); checkOutput("pkg/A.html", true, """ case1()
- """ + getSnippetHtmlRepresentation("pkg/A.html", "")); + """ + getSnippetHtmlRepresentation("pkg/A.html", "", Optional.empty(), + Optional.of("snippet-case1()2"))); } @Test // TODO: use combinatorial methods @@ -1765,7 +1771,8 @@ public class TestSnippetTag extends SnippetTester { case%s()
%s - """.formatted(j, getSnippetHtmlRepresentation("pkg/A.html", "2"))); + """.formatted(j, getSnippetHtmlRepresentation("pkg/A.html", "2", Optional.empty(), + Optional.of("snippet-case" + j + "()2")))); } } @@ -1844,7 +1851,8 @@ public class TestSnippetTag extends SnippetTester { """ case%s()
- %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput()))); + %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput(), Optional.empty(), + Optional.of("snippet-case" + index + "()2")))); }); } @@ -2302,7 +2310,8 @@ public class TestSnippetTag extends SnippetTester { """ case%s()
- %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput()))); + %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput(), Optional.empty(), + Optional.of("snippet-case" + index + "()2")))); }); } diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetUnnamedPackage.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetUnnamedPackage.java index 4f5c3e32223..616eb3a7ed7 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetUnnamedPackage.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetUnnamedPackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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 @@ -91,6 +91,6 @@ public class TestSnippetUnnamedPackage extends SnippetTester { %s After.""".formatted(getSnippetHtmlRepresentation("C.html", - "public class S { }", Optional.of("java")))); + "public class S { }", Optional.of("java"), Optional.of("snippet-C1")))); } }