8225321: Repeated use of {@systemProperty} in a file causes duplicate ids
Reviewed-by: hannesw
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java Thu Jun 06 10:01:36 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java Thu Jun 06 10:36:43 2019 -0700
@@ -27,6 +27,7 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
@@ -197,6 +198,14 @@
protected Script mainBodyScript;
/**
+ * A table of the anchors used for at-index and related tags,
+ * so that they can be made unique by appending a suitable suffix.
+ * (Ideally, javadoc should be tracking all id's generated in a file
+ * to avoid generating duplicates.)
+ */
+ Map<String, Integer> indexAnchorTable = new HashMap<>();
+
+ /**
* Constructor to construct the HtmlStandardWriter object.
*
* @param configuration the configuration for this doclet
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java Thu Jun 06 10:01:36 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java Thu Jun 06 10:36:43 2019 -0700
@@ -409,11 +409,16 @@
}
private Content createAnchorAndSearchIndex(Element element, String tagText, String desc){
- String anchorName = htmlWriter.links.getName(tagText);
Content result = null;
if (isFirstSentence && inSummary) {
result = new StringContent(tagText);
} else {
+ String anchorName = htmlWriter.links.getName(tagText);
+ int count = htmlWriter.indexAnchorTable.computeIfAbsent(anchorName, s -> 0);
+ htmlWriter.indexAnchorTable.put(anchorName, count + 1);
+ if (count > 0) {
+ anchorName += "-" + count;
+ }
result = HtmlTree.A_ID(HtmlStyle.searchTagResult, anchorName, new StringContent(tagText));
if (configuration.createindex && !tagText.isEmpty()) {
SearchIndexItem si = new SearchIndexItem();
--- a/test/langtools/jdk/javadoc/doclet/testIndexTaglet/TestIndexTaglet.java Thu Jun 06 10:01:36 2019 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testIndexTaglet/TestIndexTaglet.java Thu Jun 06 10:36:43 2019 -0700
@@ -47,7 +47,7 @@
public static void main(String... args) throws Exception {
TestIndexTaglet tester = new TestIndexTaglet();
- tester.runTests(m -> new Object[]{Paths.get(m.getName())});
+ tester.runTests(m -> new Object[] { Paths.get(m.getName()) });
}
TestIndexTaglet() {
@@ -104,4 +104,27 @@
checkOutput(Output.OUT, true,
"warning: {@index} tag, which expands to <a>, within <a>");
}
+
+ @Test
+ public void testDuplicateReferences(Path base) throws Exception {
+ Path srcDir = base.resolve("src");
+ Path outDir = base.resolve("out");
+
+ new ClassBuilder(tb, "pkg.A")
+ .setModifiers("public", "class")
+ .setComments("This is a class. Here is {@index foo first}.")
+ .addMembers(MethodBuilder.parse("public void m() {}")
+ .setComments("This is a method. Here is {@index foo second}."))
+ .write(srcDir);
+
+ javadoc("-d", outDir.toString(),
+ "-sourcepath", srcDir.toString(),
+ "pkg");
+
+ checkExit(Exit.OK);
+
+ checkOutput("pkg/A.html", true,
+ "This is a class. Here is <a id=\"foo\" class=\"searchTagResult\">foo</a>.",
+ "This is a method. Here is <a id=\"foo-1\" class=\"searchTagResult\">foo</a>.");
+ }
}
--- a/test/langtools/jdk/javadoc/doclet/testSystemPropertyTaglet/TestSystemPropertyTaglet.java Thu Jun 06 10:01:36 2019 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testSystemPropertyTaglet/TestSystemPropertyTaglet.java Thu Jun 06 10:36:43 2019 -0700
@@ -47,7 +47,7 @@
public static void main(String... args) throws Exception {
TestSystemPropertyTaglet tester = new TestSystemPropertyTaglet();
- tester.runTests(m -> new Object[]{Paths.get(m.getName())});
+ tester.runTests(m -> new Object[] { Paths.get(m.getName()) });
}
TestSystemPropertyTaglet() {
@@ -118,4 +118,27 @@
checkOutput(Output.OUT, true,
"warning: {@systemProperty} tag, which expands to <a>, within <a>");
}
+
+ @Test
+ public void testDuplicateReferences(Path base) throws Exception {
+ Path srcDir = base.resolve("src");
+ Path outDir = base.resolve("out");
+
+ new ClassBuilder(tb, "pkg.A")
+ .setModifiers("public", "class")
+ .setComments("This is a class. Here is {@systemProperty foo}.")
+ .addMembers(MethodBuilder.parse("public void m() {}")
+ .setComments("This is a method. Here is {@systemProperty foo}."))
+ .write(srcDir);
+
+ javadoc("-d", outDir.toString(),
+ "-sourcepath", srcDir.toString(),
+ "pkg");
+
+ checkExit(Exit.OK);
+
+ checkOutput("pkg/A.html", true,
+ "This is a class. Here is <code><a id=\"foo\" class=\"searchTagResult\">foo</a></code>.",
+ "This is a method. Here is <code><a id=\"foo-1\" class=\"searchTagResult\">foo</a></code>.");
+ }
}