Skip to content

Commit 8323ddf

Browse files
committedFeb 27, 2025
8346659: SnippetTaglet should report an error if provided ambiguous links
Reviewed-by: hannesw, liach
1 parent 3c9d64e commit 8323ddf

File tree

4 files changed

+105
-29
lines changed

4 files changed

+105
-29
lines changed
 

‎src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java

+20-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -26,8 +26,6 @@
2626
package jdk.javadoc.internal.doclets.formats.html.taglets;
2727

2828
import java.io.IOException;
29-
import java.net.URI;
30-
import java.nio.file.Path;
3129
import java.util.EnumSet;
3230
import java.util.HashMap;
3331
import java.util.HashSet;
@@ -133,51 +131,47 @@ private Content snippetTagOutput(Element element, SnippetTree tag, StyledText co
133131
if (lang != null && !lang.isBlank()) {
134132
code.addStyle("language-" + lang);
135133
}
136-
137134
content.consumeBy((styles, sequence) -> {
138135
CharSequence text = Text.normalizeNewlines(sequence);
139136
if (styles.isEmpty()) {
140137
code.add(text);
141138
} else {
142139
Element e = null;
143-
String t = null;
144-
boolean linkEncountered = false;
140+
String linkTarget = null;
145141
boolean markupEncountered = false;
146142
Set<String> classes = new HashSet<>();
147143
for (Style s : styles) {
148-
if (s instanceof Style.Name n) {
149-
classes.add(n.name());
150-
} else if (s instanceof Style.Link l) {
151-
assert !linkEncountered; // TODO: do not assert; pick the first link report on subsequent
152-
linkEncountered = true;
153-
t = l.target();
154-
e = getLinkedElement(element, t);
155-
if (e == null) {
156-
// TODO: diagnostic output
144+
switch (s) {
145+
case Style.Name n -> classes.add(n.name());
146+
case Style.Link l -> {
147+
if (linkTarget != null) {
148+
messages.error(utils.getCommentHelper(element).getDocTreePath(tag),
149+
"doclet.error.snippet.ambiguous.link",
150+
linkTarget,
151+
l.target(),
152+
content.asCharSequence().toString().trim());
153+
}
154+
linkTarget = l.target();
155+
e = getLinkedElement(element, linkTarget);
156+
if (e == null) {
157+
// TODO: diagnostic output
158+
}
157159
}
158-
} else if (s instanceof Style.Markup) {
159-
markupEncountered = true;
160-
break;
161-
} else {
162-
// TODO: transform this if...else into an exhaustive
163-
// switch over the sealed Style hierarchy when "Pattern
164-
// Matching for switch" has been implemented (JEP 406
165-
// and friends)
166-
throw new AssertionError(styles);
160+
case Style.Markup m -> markupEncountered = true;
167161
}
168162
}
169163
Content c;
170164
if (markupEncountered) {
171165
return;
172-
} else if (linkEncountered) {
166+
} else if (linkTarget != null) {
173167
assert e != null;
174168
//disable preview tagging inside the snippets:
175169
Utils.PreviewFlagProvider prevPreviewProvider = utils.setPreviewFlagProvider(el -> false);
176170
try {
177171
var lt = (LinkTaglet) config.tagletManager.getTaglet(DocTree.Kind.LINK);
178172
c = lt.linkSeeReferenceOutput(element,
179173
null,
180-
t,
174+
linkTarget,
181175
e,
182176
false, // TODO: for now
183177
Text.of(sequence.toString()),

‎src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
33
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
#
55
# This code is free software; you can redistribute it and/or modify it
@@ -432,3 +432,7 @@ doclet.cannot_use_snippet_path=\
432432
# 0: path; 1: exception
433433
doclet.error_setting_snippet_path=\
434434
Error setting snippet path {0}: {1}
435+
436+
# 0: location
437+
doclet.error.snippet.ambiguous.link=\
438+
snippet link tags: {0} and {1} overlap in {2}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8346128 8346659
27+
* @summary Check that snippet generation is reproducible
28+
* @library /tools/lib ../../lib
29+
* @modules jdk.javadoc/jdk.javadoc.internal.tool
30+
* @build toolbox.ToolBox javadoc.tester.*
31+
* @run main ReproducibleSnippetTest
32+
*/
33+
34+
import javadoc.tester.JavadocTester;
35+
import toolbox.ToolBox;
36+
37+
import java.nio.file.Path;
38+
39+
public class ReproducibleSnippetTest extends JavadocTester {
40+
ToolBox tb = new ToolBox();
41+
42+
public static void main(String... args) throws Exception {
43+
var tester = new ReproducibleSnippetTest();
44+
tester.runTests();
45+
}
46+
47+
@Test
48+
public void test(Path base) throws Exception {
49+
Path src = base.resolve("src");
50+
tb.writeJavaFiles(src,
51+
"""
52+
package p;
53+
public interface One {
54+
/**
55+
* {@code One obj1}
56+
* {@snippet lang = java:
57+
* // @link substring="ab" target="One#ab" :
58+
* obj1.ab(a()); // @link substring="a" target="#a"
59+
*} class comment
60+
*/
61+
int a();
62+
void ab(int i);
63+
}
64+
""");
65+
javadoc("-d",
66+
"out",
67+
"-sourcepath",
68+
src.toString(),
69+
"p");
70+
checkExit(Exit.ERROR);
71+
72+
checkOutput(Output.OUT, true,
73+
"One.java:5: error: snippet link tags:",
74+
"#a",
75+
"One#ab",
76+
"overlap in obj1.ab(a());\n * {@snippet lang = java:\n ^");
77+
}
78+
}

‎test/langtools/jdk/javadoc/doclet/TestGlobalHtml/TestGlobalHtml.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,7 @@
2626
* @bug 8322708
2727
* @summary Test to make sure global tags work properly
2828
* @library /tools/lib ../../lib
29-
* @modules jdk.javadoc/jdk.javadoc.internal.tool
29+
* @modules jdk.javadoc/jdk.javadoc.internal.tool
3030
* @build toolbox.ToolBox javadoc.tester.*
3131
* @run main TestGlobalHtml
3232
*/

0 commit comments

Comments
 (0)
Please sign in to comment.