8326332: Unclosed inline tags cause misalignment in summary tables

Reviewed-by: gli, jjg
This commit is contained in:
Hannes Wallnöfer 2024-03-08 20:59:00 +00:00
parent 33aa4b26b1
commit a6dc4bc2b8
3 changed files with 38 additions and 13 deletions

View File

@ -113,6 +113,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.Utils.PreviewSummary;
import jdk.javadoc.internal.doclint.HtmlTag; import jdk.javadoc.internal.doclint.HtmlTag;
import static com.sun.source.doctree.DocTree.Kind.COMMENT; import static com.sun.source.doctree.DocTree.Kind.COMMENT;
import static com.sun.source.doctree.DocTree.Kind.START_ELEMENT;
import static com.sun.source.doctree.DocTree.Kind.TEXT; import static com.sun.source.doctree.DocTree.Kind.TEXT;
@ -1171,21 +1172,28 @@ public abstract class HtmlDocletWriter {
} }
} }
boolean ignoreNonInlineTag(DocTree dtree) { boolean ignoreNonInlineTag(DocTree dtree, List<Name> openTags) {
Name name = null; Name name = null;
if (dtree.getKind() == Kind.START_ELEMENT) { Kind kind = dtree.getKind();
StartElementTree setree = (StartElementTree)dtree; if (kind == Kind.START_ELEMENT) {
name = setree.getName(); name = ((StartElementTree)dtree).getName();
} else if (dtree.getKind() == Kind.END_ELEMENT) { } else if (kind == Kind.END_ELEMENT) {
EndElementTree eetree = (EndElementTree)dtree; name = ((EndElementTree)dtree).getName();
name = eetree.getName();
} }
if (name != null) { if (name != null) {
HtmlTag htmlTag = HtmlTag.get(name); HtmlTag htmlTag = HtmlTag.get(name);
if (htmlTag != null && if (htmlTag != null) {
htmlTag.blockType != jdk.javadoc.internal.doclint.HtmlTag.BlockType.INLINE) { if (htmlTag.blockType != HtmlTag.BlockType.INLINE) {
return true; return true;
}
// Keep track of open inline tags that need to be closed, see 8326332
if (kind == START_ELEMENT && htmlTag.endKind == HtmlTag.EndKind.REQUIRED) {
openTags.add(name);
} else if (kind == Kind.END_ELEMENT && !openTags.isEmpty()
&& openTags.getLast().equals(name)) {
openTags.removeLast();
}
} }
} }
return false; return false;
@ -1257,6 +1265,7 @@ public abstract class HtmlDocletWriter {
CommentHelper ch = utils.getCommentHelper(element); CommentHelper ch = utils.getCommentHelper(element);
configuration.tagletManager.checkTags(element, trees); configuration.tagletManager.checkTags(element, trees);
commentRemoved = false; commentRemoved = false;
List<Name> openTags = new ArrayList<>();
for (ListIterator<? extends DocTree> iterator = trees.listIterator(); iterator.hasNext();) { for (ListIterator<? extends DocTree> iterator = trees.listIterator(); iterator.hasNext();) {
boolean isFirstNode = !iterator.hasPrevious(); boolean isFirstNode = !iterator.hasPrevious();
@ -1265,14 +1274,16 @@ public abstract class HtmlDocletWriter {
if (context.isFirstSentence) { if (context.isFirstSentence) {
// Ignore block tags // Ignore block tags
if (ignoreNonInlineTag(tag)) if (ignoreNonInlineTag(tag, openTags)) {
continue; continue;
}
// Ignore any trailing whitespace OR whitespace after removed html comment // Ignore any trailing whitespace OR whitespace after removed html comment
if ((isLastNode || commentRemoved) if ((isLastNode || commentRemoved)
&& tag.getKind() == TEXT && tag.getKind() == TEXT
&& ((tag instanceof TextTree tt) && tt.getBody().isBlank())) && ((tag instanceof TextTree tt) && tt.getBody().isBlank())) {
continue; continue;
}
// Ignore any leading html comments // Ignore any leading html comments
if ((isFirstNode || commentRemoved) && tag.getKind() == COMMENT) { if ((isFirstNode || commentRemoved) && tag.getKind() == COMMENT) {
@ -1466,6 +1477,10 @@ public abstract class HtmlDocletWriter {
if (allDone) if (allDone)
break; break;
} }
// Close any open inline tags
while (!openTags.isEmpty()) {
result.add(RawHtml.endElement(openTags.removeLast()));
}
return result; return result;
} }

View File

@ -23,7 +23,7 @@
/* /*
* @test * @test
* @bug 4165985 * @bug 4165985 8326332
* @summary Determine the end of the first sentence using BreakIterator. * @summary Determine the end of the first sentence using BreakIterator.
* If the first sentence of "method" is parsed correctly, the test passes. * If the first sentence of "method" is parsed correctly, the test passes.
* Correct Answer: "This is a class (i.e. it is indeed a class)." * Correct Answer: "This is a class (i.e. it is indeed a class)."
@ -76,5 +76,10 @@ public class TestBreakIterator extends JavadocTester {
""" """
<div class="block">A constant indicating that the keyLocation is indeterminate <div class="block">A constant indicating that the keyLocation is indeterminate
or not relevant.</div>"""); or not relevant.</div>""");
checkOutput("pkg/BreakIteratorTest.html", true,
"""
<div class="block">Inline tags <i><a href="../index-all.html">extending
beyond the first sentence.</a></i></div>""");
} }
} }

View File

@ -56,4 +56,9 @@ public class BreakIteratorTest {
*/ */
public void fe(){} public void fe(){}
/**
* Inline tags <i><a href="{@docRoot}/index-all.html">extending
* beyond the first sentence. Tags are closed here.</a></i>
*/
public void meh(){}
} }