8027682: javac wrongly accepts semicolons in package and import decls

Reviewed-by: vromero
This commit is contained in:
Archie L. Cobbs 2023-03-23 16:04:35 +00:00 committed by Vicente Romero
parent c00d0885ae
commit 4b8f7db6be
18 changed files with 125 additions and 78 deletions

View File

@ -3839,16 +3839,32 @@ public class JavacParser implements Parser {
defs.append(pd);
}
boolean checkForImports = true;
boolean firstTypeDecl = true;
boolean firstTypeDecl = true; // have we see a class, enum, or interface declaration yet?
while (token.kind != EOF) {
if (token.pos <= endPosTable.errorEndPos) {
// error recovery
skip(checkForImports, false, false, false);
skip(firstTypeDecl, false, false, false);
if (token.kind == EOF)
break;
}
if (checkForImports && mods == null && token.kind == IMPORT) {
// JLS 7.3 doesn't allow extra semicolons after package or import declarations,
// but here we try to provide a more helpful error message if we encounter any.
// Do that by slurping in as many semicolons as possible, and then seeing what
// comes after before deciding how best to handle them.
ListBuffer<JCTree> semiList = new ListBuffer<>();
while (firstTypeDecl && mods == null && token.kind == SEMI) {
semiList.append(toP(F.at(token.pos).Skip()));
nextToken();
if (token.kind == EOF)
break;
}
if (firstTypeDecl && mods == null && token.kind == IMPORT) {
if (!semiList.isEmpty()) {
if (source.compareTo(Source.JDK21) >= 0)
reportSyntaxError(semiList.first().pos, Errors.ExtraneousSemicolon);
else
log.warning(semiList.first().pos, Warnings.ExtraneousSemicolon);
}
seenImport = true;
defs.append(importDeclaration());
} else {
@ -3860,6 +3876,12 @@ public class JavacParser implements Parser {
if (mods != null || token.kind != SEMI)
mods = modifiersOpt(mods);
if (firstTypeDecl && token.kind == IDENTIFIER) {
if (!semiList.isEmpty()) {
if (source.compareTo(Source.JDK21) >= 0)
reportSyntaxError(semiList.first().pos, Errors.ExtraneousSemicolon);
else
log.warning(semiList.first().pos, Warnings.ExtraneousSemicolon);
}
ModuleKind kind = ModuleKind.STRONG;
if (token.name() == names.open) {
kind = ModuleKind.OPEN;
@ -3876,12 +3898,11 @@ public class JavacParser implements Parser {
reportSyntaxError(token.pos, Errors.ExpectedModule);
}
}
defs.appendList(semiList.toList());
JCTree def = typeDeclaration(mods, docComment);
if (def instanceof JCExpressionStatement statement)
def = statement.expr;
defs.append(def);
if (def instanceof JCClassDecl)
checkForImports = false;
mods = null;
firstTypeDecl = false;
}

View File

@ -2358,6 +2358,12 @@ compiler.err.enum.constant.expected=\
compiler.err.enum.constant.not.expected=\
enum constant not expected here
compiler.err.extraneous.semicolon=\
extraneous semicolon
compiler.warn.extraneous.semicolon=\
extraneous semicolon
## The following are related in form, but do not easily fit the above paradigm.
compiler.err.expected.module.or.open=\
''module'' or ''open'' expected

View File

@ -30,7 +30,7 @@
import com.sun.jndi.dns.ResourceRecord;
import javax.naming.CommunicationException;
import javax.naming.InvalidNameException;;
import javax.naming.InvalidNameException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

View File

@ -34,8 +34,8 @@ import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.security.AccessControlException;;
import java.security.Permission;;
import java.security.AccessControlException;
import java.security.Permission;
import static jdk.test.lib.Asserts.*;

View File

@ -45,7 +45,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import javax.management.*;
import javax.management.openmbean.CompositeData;
import java.lang.management.*;
import static java.lang.management.MemoryNotificationInfo.*;;
import static java.lang.management.MemoryNotificationInfo.*;
import static java.lang.management.ManagementFactory.*;
import jdk.test.whitebox.code.Compiler;

View File

@ -51,7 +51,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeoutException;;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static java.nio.file.StandardOpenOption.*;

View File

@ -33,7 +33,7 @@ import jdk.jfr.Recording;
import jdk.test.lib.JDKToolLauncher;
import jdk.test.lib.Utils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;;
import jdk.test.lib.process.ProcessTools;
final class ExecuteHelper {

View File

@ -1,7 +1,7 @@
AnnotatedImport.java:10:13: compiler.err.expected: token.identifier
AnnotatedImport.java:10:16: compiler.err.expected4: class, interface, enum, record
AnnotatedImport.java:11:7: compiler.err.expected: token.identifier
AnnotatedImport.java:11:1: compiler.err.expected4: class, interface, enum, record
AnnotatedImport.java:11:11: compiler.err.expected4: class, interface, enum, record
AnnotatedImport.java:12:18: compiler.err.expected: token.identifier
AnnotatedImport.java:12:1: compiler.err.expected4: class, interface, enum, record
AnnotatedImport.java:12:21: compiler.err.expected4: class, interface, enum, record
6 errors

View File

@ -1,3 +1,4 @@
AnnotatedPackage1.java:9:14: compiler.err.expected: token.identifier
AnnotatedPackage1.java:9:17: compiler.err.expected4: class, interface, enum, record
2 errors
AnnotatedPackage1.java:11:1: compiler.err.expected4: class, interface, enum, record
3 errors

View File

@ -1,3 +1,4 @@
AnnotatedPackage2.java:9:8: compiler.err.expected: token.identifier
AnnotatedPackage2.java:9:12: compiler.err.expected4: class, interface, enum, record
2 errors
AnnotatedPackage2.java:11:1: compiler.err.expected4: class, interface, enum, record
3 errors

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// key: compiler.err.extraneous.semicolon
import java.util.Map;; // NOTE: extra semicolon
import java.util.Set;
class ExtraImportSemicolonError {
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// key: compiler.warn.extraneous.semicolon
// options: --release 20
import java.util.Map;; // NOTE: extra semicolon
import java.util.Set;
class ExtraImportSemicolonWarning {
}

View File

@ -0,0 +1,13 @@
/*
* @test /nodynamiccopyright/
* @bug 5059679
* @summary Verify proper error reporting of extra semicolon before import statement
* @compile/fail/ref=ExtraImportSemicolon.out1 -XDrawDiagnostics ExtraImportSemicolon.java
* @compile/ref=ExtraImportSemicolon.out2 --release 20 -XDrawDiagnostics ExtraImportSemicolon.java
*/
import java.util.Map;; // NOTE: extra semicolon
import java.util.Set;
class ExtraImportSemicolon {
}

View File

@ -0,0 +1,2 @@
ExtraImportSemicolon.java:9:22: compiler.err.extraneous.semicolon
1 error

View File

@ -0,0 +1,2 @@
ExtraImportSemicolon.java:9:22: compiler.warn.extraneous.semicolon
1 warning

View File

@ -1,60 +0,0 @@
/*
* Copyright (c) 2011, 2015, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6963934
* @summary JCCompilationUnit.getImports does not report all imports
* @modules jdk.compiler
*/
import java.io.File;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;; // NOTE: extra semicolon for test
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ImportTree;
import com.sun.source.util.JavacTask;
; // NOTE: extra semicolon for test
public class T6963934 {
public static void main(String[] args) throws Exception {
File testSrc = new File(System.getProperty("test.src"));
File thisSrc = new File(testSrc, T6963934.class.getSimpleName() + ".java");
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) {
JavacTask task = (JavacTask) compiler.getTask(null, fileManager, null, null, null,
fileManager.getJavaFileObjects(thisSrc));
CompilationUnitTree tree = task.parse().iterator().next();
int count = 0;
for (ImportTree importTree : tree.getImports()) {
System.out.println(importTree);
count++;
}
int expected = 7;
if (count != expected)
throw new Exception("unexpected number of imports found: " + count + ", expected: " + expected);
}
}
}

View File

@ -23,7 +23,7 @@
package q;
import jdk.internal.perf.PerfCounter;;
import jdk.internal.perf.PerfCounter;
public class Counter {
public static void create(String name) {

View File

@ -464,7 +464,7 @@ public class TypeHarness {
String id;
String type;
String template = "#Package;\n" +
String template = "#Package\n" +
"#Imports\n" +
"class G#Id#TypeVars {\n" +
" #FieldType var;" +