Skip to content

Commit 4b8f7db

Browse files
archiecobbsVicente Romero
authored andcommitted
8027682: javac wrongly accepts semicolons in package and import decls
Reviewed-by: vromero
1 parent c00d088 commit 4b8f7db

File tree

18 files changed

+125
-78
lines changed

18 files changed

+125
-78
lines changed

src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3839,16 +3839,32 @@ public JCTree.JCCompilationUnit parseCompilationUnit() {
38393839
defs.append(pd);
38403840
}
38413841

3842-
boolean checkForImports = true;
3843-
boolean firstTypeDecl = true;
3842+
boolean firstTypeDecl = true; // have we see a class, enum, or interface declaration yet?
38443843
while (token.kind != EOF) {
38453844
if (token.pos <= endPosTable.errorEndPos) {
38463845
// error recovery
3847-
skip(checkForImports, false, false, false);
3846+
skip(firstTypeDecl, false, false, false);
38483847
if (token.kind == EOF)
38493848
break;
38503849
}
3851-
if (checkForImports && mods == null && token.kind == IMPORT) {
3850+
// JLS 7.3 doesn't allow extra semicolons after package or import declarations,
3851+
// but here we try to provide a more helpful error message if we encounter any.
3852+
// Do that by slurping in as many semicolons as possible, and then seeing what
3853+
// comes after before deciding how best to handle them.
3854+
ListBuffer<JCTree> semiList = new ListBuffer<>();
3855+
while (firstTypeDecl && mods == null && token.kind == SEMI) {
3856+
semiList.append(toP(F.at(token.pos).Skip()));
3857+
nextToken();
3858+
if (token.kind == EOF)
3859+
break;
3860+
}
3861+
if (firstTypeDecl && mods == null && token.kind == IMPORT) {
3862+
if (!semiList.isEmpty()) {
3863+
if (source.compareTo(Source.JDK21) >= 0)
3864+
reportSyntaxError(semiList.first().pos, Errors.ExtraneousSemicolon);
3865+
else
3866+
log.warning(semiList.first().pos, Warnings.ExtraneousSemicolon);
3867+
}
38523868
seenImport = true;
38533869
defs.append(importDeclaration());
38543870
} else {
@@ -3860,6 +3876,12 @@ public JCTree.JCCompilationUnit parseCompilationUnit() {
38603876
if (mods != null || token.kind != SEMI)
38613877
mods = modifiersOpt(mods);
38623878
if (firstTypeDecl && token.kind == IDENTIFIER) {
3879+
if (!semiList.isEmpty()) {
3880+
if (source.compareTo(Source.JDK21) >= 0)
3881+
reportSyntaxError(semiList.first().pos, Errors.ExtraneousSemicolon);
3882+
else
3883+
log.warning(semiList.first().pos, Warnings.ExtraneousSemicolon);
3884+
}
38633885
ModuleKind kind = ModuleKind.STRONG;
38643886
if (token.name() == names.open) {
38653887
kind = ModuleKind.OPEN;
@@ -3876,12 +3898,11 @@ public JCTree.JCCompilationUnit parseCompilationUnit() {
38763898
reportSyntaxError(token.pos, Errors.ExpectedModule);
38773899
}
38783900
}
3901+
defs.appendList(semiList.toList());
38793902
JCTree def = typeDeclaration(mods, docComment);
38803903
if (def instanceof JCExpressionStatement statement)
38813904
def = statement.expr;
38823905
defs.append(def);
3883-
if (def instanceof JCClassDecl)
3884-
checkForImports = false;
38853906
mods = null;
38863907
firstTypeDecl = false;
38873908
}

src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2358,6 +2358,12 @@ compiler.err.enum.constant.expected=\
23582358
compiler.err.enum.constant.not.expected=\
23592359
enum constant not expected here
23602360

2361+
compiler.err.extraneous.semicolon=\
2362+
extraneous semicolon
2363+
2364+
compiler.warn.extraneous.semicolon=\
2365+
extraneous semicolon
2366+
23612367
## The following are related in form, but do not easily fit the above paradigm.
23622368
compiler.err.expected.module.or.open=\
23632369
''module'' or ''open'' expected

test/jdk/com/sun/jndi/dns/Parser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
import com.sun.jndi.dns.ResourceRecord;
3232
import javax.naming.CommunicationException;
33-
import javax.naming.InvalidNameException;;
33+
import javax.naming.InvalidNameException;
3434

3535
import java.lang.reflect.Constructor;
3636
import java.lang.reflect.InvocationTargetException;

test/jdk/java/lang/constant/methodTypeDesc/ResolveConstantDesc.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
import java.lang.invoke.MethodHandles;
3535
import java.lang.invoke.MethodHandles.Lookup;
3636
import java.lang.invoke.MethodType;
37-
import java.security.AccessControlException;;
38-
import java.security.Permission;;
37+
import java.security.AccessControlException;
38+
import java.security.Permission;
3939

4040
import static jdk.test.lib.Asserts.*;
4141

test/jdk/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
import javax.management.*;
4646
import javax.management.openmbean.CompositeData;
4747
import java.lang.management.*;
48-
import static java.lang.management.MemoryNotificationInfo.*;;
48+
import static java.lang.management.MemoryNotificationInfo.*;
4949
import static java.lang.management.ManagementFactory.*;
5050

5151
import jdk.test.whitebox.code.Compiler;

test/jdk/java/nio/channels/AsynchronousFileChannel/Basic.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
import java.util.concurrent.ExecutorService;
5252
import java.util.concurrent.Future;
5353
import java.util.concurrent.ThreadFactory;
54-
import java.util.concurrent.TimeoutException;;
54+
import java.util.concurrent.TimeoutException;
5555
import java.util.concurrent.TimeUnit;
5656
import java.util.concurrent.atomic.AtomicReference;
5757
import static java.nio.file.StandardOpenOption.*;

test/jdk/jdk/jfr/tool/ExecuteHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
import jdk.test.lib.JDKToolLauncher;
3434
import jdk.test.lib.Utils;
3535
import jdk.test.lib.process.OutputAnalyzer;
36-
import jdk.test.lib.process.ProcessTools;;
36+
import jdk.test.lib.process.ProcessTools;
3737

3838
final class ExecuteHelper {
3939

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
AnnotatedImport.java:10:13: compiler.err.expected: token.identifier
22
AnnotatedImport.java:10:16: compiler.err.expected4: class, interface, enum, record
3-
AnnotatedImport.java:11:7: compiler.err.expected: token.identifier
3+
AnnotatedImport.java:11:1: compiler.err.expected4: class, interface, enum, record
44
AnnotatedImport.java:11:11: compiler.err.expected4: class, interface, enum, record
5-
AnnotatedImport.java:12:18: compiler.err.expected: token.identifier
5+
AnnotatedImport.java:12:1: compiler.err.expected4: class, interface, enum, record
66
AnnotatedImport.java:12:21: compiler.err.expected4: class, interface, enum, record
77
6 errors
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
AnnotatedPackage1.java:9:14: compiler.err.expected: token.identifier
22
AnnotatedPackage1.java:9:17: compiler.err.expected4: class, interface, enum, record
3-
2 errors
3+
AnnotatedPackage1.java:11:1: compiler.err.expected4: class, interface, enum, record
4+
3 errors
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
AnnotatedPackage2.java:9:8: compiler.err.expected: token.identifier
22
AnnotatedPackage2.java:9:12: compiler.err.expected4: class, interface, enum, record
3-
2 errors
3+
AnnotatedPackage2.java:11:1: compiler.err.expected4: class, interface, enum, record
4+
3 errors

0 commit comments

Comments
 (0)