8223805: DocCommentParser should allow for <main> and </main>
Reviewed-by: hannesw
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java Tue Jun 04 13:26:20 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java Tue Jun 04 11:29:29 2019 -0700
@@ -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 @@
if (isFileContent) {
switch (phase) {
case PREAMBLE:
- if (peek("body")) {
+ if (isEndPreamble()) {
trees.add(html());
if (textStart == -1) {
textStart = bp;
@@ -200,7 +200,7 @@
}
break;
case BODY:
- if (peek("/body")) {
+ if (isEndBody()) {
addPendingText(trees, lastNonWhite);
break loop;
}
@@ -787,6 +787,94 @@
}
}
+ /**
+ * 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 {
--- a/test/langtools/tools/javac/doctree/dcapi/DocCommentTreeApiTester.java Tue Jun 04 13:26:20 2019 -0400
+++ b/test/langtools/tools/javac/doctree/dcapi/DocCommentTreeApiTester.java Tue Jun 04 11:29:29 2019 -0700
@@ -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.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 @@
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();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/doctree/dcapi/overview8.html Tue Jun 04 11:29:29 2019 -0700
@@ -0,0 +1,9 @@
+<!-- /nodynamiccopyright/ -->
+<HTML>
+<HEAD>
+</HEAD>
+<BODY><MAIN>
+This is the content.
+@since 1.0
+</MAIN></BODY>
+</HTML>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/doctree/dcapi/overview8.html.out Tue Jun 04 11:29:29 2019 -0700
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/doctree/dcapi/overview9.html Tue Jun 04 11:29:29 2019 -0700
@@ -0,0 +1,10 @@
+<!-- /nodynamiccopyright/ -->
+<HTML>
+<HEAD>
+</HEAD>
+<BODY lang="en">
+<main role="main">
+This is the content.
+@since 1.0
+</main></BODY>
+</HTML>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/doctree/dcapi/overview9.html.out Tue Jun 04 11:29:29 2019 -0700
@@ -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