8281969: Bad result for the snippet @link tag if substring/regex consists of whitespace

Reviewed-by: jjg
This commit is contained in:
Pavel Rappo 2022-07-14 22:27:53 +00:00
parent c8e0315114
commit 15d3329edd
2 changed files with 48 additions and 28 deletions
src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html
test/langtools/jdk/javadoc/doclet/testSnippetTag

@ -425,24 +425,13 @@ public class TagletWriterImpl extends TagletWriter {
return;
} else if (linkEncountered) {
assert e != null;
String line = sequence.toString();
String strippedLine = line.strip();
int idx = line.indexOf(strippedLine);
assert idx >= 0; // because the stripped line is a substring of the line being stripped
Text whitespace = Text.of(utils.normalizeNewlines(line.substring(0, idx)));
//disable preview tagging inside the snippets:
PreviewFlagProvider prevPreviewProvider = utils.setPreviewFlagProvider(el -> false);
try {
// If the leading whitespace is not excluded from the link,
// browsers might exhibit unwanted behavior. For example, a
// browser might display hand-click cursor while user hovers
// over that whitespace portion of the line; or use
// underline decoration.
c = new ContentBuilder(whitespace, htmlWriter.linkToContent(element, e, t, strippedLine));
c = new ContentBuilder(htmlWriter.linkToContent(element, e, t, sequence.toString()));
} finally {
utils.setPreviewFlagProvider(prevPreviewProvider);
}
// We don't care about trailing whitespace.
} else {
c = HtmlTree.SPAN(Text.of(text));
classes.forEach(((HtmlTree) c)::addStyle);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2022, 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
@ -23,7 +23,7 @@
/*
* @test
* @bug 8266666
* @bug 8266666 8281969
* @summary Implementation for snippets
* @library /tools/lib ../../lib
* @modules jdk.compiler/com.sun.tools.javac.api
@ -180,7 +180,28 @@ public class TestSnippetMarkup extends SnippetTester {
link(First) link(line)
Second line
""", "link\\((.+?)\\)", r -> link(true, "java.lang.Object#Object", r.group(1)))
));
),
new TestCase(
"""
First line
Second line // @link substring=" " target="java.lang.System#out"
""",
replace("""
First line
link( )Secondlink( )line
""", "link\\((.+?)\\)", r -> link(true, "java.lang.System#out", r.group(1)))
),
new TestCase(
"""
First line
Second line // @link regex=" " target="java.lang.System#in"
""",
replace("""
First line
link( )Secondlink( )line
""", "link\\((.+?)\\)", r -> link(true, "java.lang.System#in", r.group(1)))
)
);
testPositive(base, testCases);
}
@ -575,7 +596,7 @@ First line // @highlight :
""",
replace("""
First line
link(Third line)
link( Third line)
""", "link\\((.+?)\\)", r -> link(true, "java.lang.Object#equals(Object)", r.group(1)))
),
new TestCase("""
@ -717,19 +738,29 @@ First line // @highlight :
String content)
throws UncheckedIOException {
// The HTML <a> tag generated from the @link snippet markup tag is the
// same as that of the {@link} Standard doclet tag. This is specified
// and can be used for comparison and testing.
// The HTML A element generated for the @link snippet markup tag is
// the same as that for the similar Standard doclet {@link} tag.
// This fact can be used for comparison and testing.
// generate documentation for {@link} to grab its HTML <a> tag;
// generate documentation at low cost and do not interfere with the
// calling test state; for that, do not create file trees, do not write
// to std out/err, and generally try to keep everything in memory
// Generate documentation for {@link} to grab its HTML A element.
// Generate documentation cheaply and do not interfere with the
// calling test state; for that: do not create file trees, do not write
// to std out/err, and generally try to keep everything in memory.
String source = """
// Caveat: a label used in snippet's @link tag can start, end, or both,
// with whitespace. In this regard, snippet's @link differs from
// {@link} and {@linkplain} Standard doclet tags, which trim whitespace
// from labels. In particular, {@link} and {@linkplain} treat
// whitespace after the reference as an absent label, whereas
// snippet's @link does not. To avoid whitespace problems,
// LABEL_PLACEHOLDER is used. It is later substituted with "content",
// which might be an empty or blank string.
var LABEL_PLACEHOLDER = "label";
var source = """
/** {@link %s %s} */
public interface A { }
""".formatted(targetReference, content);
""".formatted(targetReference, LABEL_PLACEHOLDER);
JavaFileObject src = new JavaFileObject() {
@Override
@ -850,12 +881,12 @@ First line // @highlight :
}
String output = fileManager.getFileString(DOCUMENTATION_OUTPUT, "A.html");
// use the [^<>] regex to select HTML elements that immediately enclose "content"
Matcher m = Pattern.compile("(?is)<a href=\"[^<>]*\" title=\"[^<>]*\" class=\"[^<>]*\"><code>"
+ content + "</code></a>").matcher(output);
Matcher m = Pattern.compile("(?is)(<a href=\"[^<>]*\" title=\"[^<>]*\" class=\"[^<>]*\"><code>)"
+ LABEL_PLACEHOLDER + "(</code></a>)").matcher(output);
if (!m.find()) {
throw new IOException(output);
}
return m.group(0);
return m.group(1) + content + m.group(2);
} catch (IOException e) {
throw new UncheckedIOException(e);
}