8225321: Repeated use of {@systemProperty} in a file causes duplicate ids
authorjjg
Thu, 06 Jun 2019 10:36:43 -0700
changeset 55266 fb250e9cfe67
parent 55265 d80becbcd3c1
child 55267 eabe64456156
8225321: Repeated use of {@systemProperty} in a file causes duplicate ids Reviewed-by: hannesw
src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java
test/langtools/jdk/javadoc/doclet/testIndexTaglet/TestIndexTaglet.java
test/langtools/jdk/javadoc/doclet/testSystemPropertyTaglet/TestSystemPropertyTaglet.java
--- 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>.");
+    }
 }