8223805: DocCommentParser should allow for <main> and </main>

Reviewed-by: hannesw
This commit is contained in:
Jonathan Gibbons 2019-06-04 11:29:29 -07:00
parent 9965ded5dd
commit 45f6ff3894
6 changed files with 202 additions and 12 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2019, 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
@ -188,7 +188,7 @@ public class DocCommentParser {
if (isFileContent) {
switch (phase) {
case PREAMBLE:
if (peek("body")) {
if (isEndPreamble()) {
trees.add(html());
if (textStart == -1) {
textStart = bp;
@ -200,7 +200,7 @@ public class DocCommentParser {
}
break;
case BODY:
if (peek("/body")) {
if (isEndBody()) {
addPendingText(trees, lastNonWhite);
break loop;
}
@ -787,6 +787,94 @@ public class DocCommentParser {
}
}
/**
* Returns whether this is the end of the preamble of an HTML file.
* The preamble ends with start of {@code body} element followed by
* possible whitespace and the start of a {@code main} element.
*
* @return whether this is the end of the preamble
*/
boolean isEndPreamble() {
final int savedpos = bp;
try {
if (ch == '<')
nextChar();
if (isIdentifierStart(ch)) {
String name = StringUtils.toLowerCase(readIdentifier().toString());
switch (name) {
case "body":
// Check if also followed by <main>
// 1. skip rest of <body>
while (ch != -1 && ch != '>') {
nextChar();
}
if (ch == '>') {
nextChar();
}
// 2. skip any whitespce
while (ch != -1 && Character.isWhitespace(ch)) {
nextChar();
}
// 3. check if looking at "<main..."
if (ch == '<') {
nextChar();
if (isIdentifierStart(ch)) {
name = StringUtils.toLowerCase(readIdentifier().toString());
if (name.equals("main")) {
return false;
}
}
}
// if <body> is _not_ followed by <main> then this is the
// end of the preamble
return true;
case "main":
// <main> is unconditionally the end of the preamble
return true;
}
}
return false;
} finally {
bp = savedpos;
ch = buf[bp];
}
}
/**
* Returns whether this is the end of the main body of the content in a standalone
* HTML file.
* The content ends with the closing tag for a {@code main} or {@code body} element.
*
* @return whether this is the end of the main body of the content
*/
boolean isEndBody() {
final int savedpos = bp;
try {
if (ch == '<')
nextChar();
if (ch == '/') {
nextChar();
if (isIdentifierStart(ch)) {
String name = StringUtils.toLowerCase(readIdentifier().toString());
switch (name) {
case "body":
case "main":
return true;
}
}
}
return false;
} finally {
bp = savedpos;
ch = buf[bp];
}
}
boolean peek(String s) {
final int savedpos = bp;
try {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, 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
@ -39,6 +39,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.BreakIterator;
@ -98,14 +99,14 @@ public class DocCommentTreeApiTester {
test.runDocTreePath("Anchor.java", "package.html");
// test for correct parsing using valid and some invalid html tags
test.runFileObjectTest("overview0.html");
test.runFileObjectTest("overview1.html");
test.runFileObjectTest("overview2.html");
test.runFileObjectTest("overview3.html");
test.runFileObjectTest("overview4.html");
test.runFileObjectTest("overview5.html");
test.runFileObjectTest("overview6.html");
test.runFileObjectTest("overview7.html");
try (DirectoryStream<Path> ds = Files.newDirectoryStream(Path.of(testSrc))) {
for (Path entry: ds) {
String name = entry.getFileName().toString();
if (name.matches("overview[0-9]+\\.html")) {
test.runFileObjectTest(name);
}
}
}
} finally {
test.status();

View File

@ -0,0 +1,9 @@
<!-- /nodynamiccopyright/ -->
<HTML>
<HEAD>
</HEAD>
<BODY><MAIN>
This is the content.
@since 1.0
</MAIN></BODY>
</HTML>

View File

@ -0,0 +1,35 @@
EXPECT_START
DocComment[DOC_COMMENT, pos:0
preamble: 6
Comment[COMMENT, pos:0, <!--_/nodynamiccopyright/_-->]
StartElement[START_ELEMENT, pos:30
name:HTML
attributes: empty
]
StartElement[START_ELEMENT, pos:37
name:HEAD
attributes: empty
]
EndElement[END_ELEMENT, pos:44, HEAD]
StartElement[START_ELEMENT, pos:52
name:BODY
attributes: empty
]
StartElement[START_ELEMENT, pos:58
name:MAIN
attributes: empty
]
firstSentence: 1
Text[TEXT, pos:65, This_is_the_content.]
body: empty
block tags: 1
Since[SINCE, pos:86
body: 1
Text[TEXT, pos:93, 1.0]
]
postamble: 3
EndElement[END_ELEMENT, pos:97, MAIN]
EndElement[END_ELEMENT, pos:104, BODY]
EndElement[END_ELEMENT, pos:112, HTML]
]
EXPECT_END

View File

@ -0,0 +1,10 @@
<!-- /nodynamiccopyright/ -->
<HTML>
<HEAD>
</HEAD>
<BODY lang="en">
<main role="main">
This is the content.
@since 1.0
</main></BODY>
</HTML>

View File

@ -0,0 +1,47 @@
EXPECT_START
DocComment[DOC_COMMENT, pos:0
preamble: 6
Comment[COMMENT, pos:0, <!--_/nodynamiccopyright/_-->]
StartElement[START_ELEMENT, pos:30
name:HTML
attributes: empty
]
StartElement[START_ELEMENT, pos:37
name:HEAD
attributes: empty
]
EndElement[END_ELEMENT, pos:44, HEAD]
StartElement[START_ELEMENT, pos:52
name:BODY
attributes: 1
Attribute[ATTRIBUTE, pos:58
name: lang
vkind: DOUBLE
value: 1
Text[TEXT, pos:64, en]
]
]
StartElement[START_ELEMENT, pos:69
name:main
attributes: 1
Attribute[ATTRIBUTE, pos:75
name: role
vkind: DOUBLE
value: 1
Text[TEXT, pos:81, main]
]
]
firstSentence: 1
Text[TEXT, pos:88, This_is_the_content.]
body: empty
block tags: 1
Since[SINCE, pos:109
body: 1
Text[TEXT, pos:116, 1.0]
]
postamble: 3
EndElement[END_ELEMENT, pos:120, main]
EndElement[END_ELEMENT, pos:127, BODY]
EndElement[END_ELEMENT, pos:135, HTML]
]
EXPECT_END