From 63d4afbeb17df4eff0f65041926373ee62a8a33a Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 23 Mar 2023 08:35:25 +0000 Subject: [PATCH] 8304671: javac regression: Compilation with --release 8 fails on underscore in enum identifiers Reviewed-by: vromero, darcy --- .../sun/tools/javac/parser/JavacParser.java | 16 +- .../tools/javac/parser/JavacParserTest.java | 181 +++++++++++++++++- 2 files changed, 188 insertions(+), 9 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index 661cf06d30f..33bee1d35d2 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -4303,10 +4303,13 @@ public class JavacParser implements Parser { return defs.toList(); } + @SuppressWarnings("fallthrough") private EnumeratorEstimate estimateEnumeratorOrMember(Name enumName) { // if we are seeing a record declaration inside of an enum we want the same error message as expected for a // let's say an interface declaration inside an enum - if (token.kind == TokenKind.IDENTIFIER && token.name() != enumName && + boolean ident = token.kind == TokenKind.IDENTIFIER || + token.kind == TokenKind.UNDERSCORE; + if (ident && token.name() != enumName && (!allowRecords || !isRecordStart())) { Token next = S.token(1); switch (next.kind) { @@ -4315,12 +4318,11 @@ public class JavacParser implements Parser { } } switch (token.kind) { - case IDENTIFIER: case MONKEYS_AT: case LT: - if (token.kind == IDENTIFIER) { - if (allowRecords && isRecordStart()) { - return EnumeratorEstimate.MEMBER; - } + case IDENTIFIER: + if (allowRecords && isRecordStart()) { + return EnumeratorEstimate.MEMBER; } + case MONKEYS_AT: case LT: case UNDERSCORE: return EnumeratorEstimate.UNKNOWN; default: return EnumeratorEstimate.MEMBER; diff --git a/test/langtools/tools/javac/parser/JavacParserTest.java b/test/langtools/tools/javac/parser/JavacParserTest.java index 6e742d259a1..1a48d31ba88 100644 --- a/test/langtools/tools/javac/parser/JavacParserTest.java +++ b/test/langtools/tools/javac/parser/JavacParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 + * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 * @summary tests error and diagnostics positions * @author Jan Lahoda * @modules jdk.compiler/com.sun.tools.javac.api @@ -2061,6 +2061,183 @@ public class JavacParserTest extends TestCase { }); } + @Test //JDK-8304671 + void testEnumConstantUnderscore() throws IOException { + record TestCase(String code, String release, String ast, String errors) {} + TestCase[] testCases = new TestCase[] { + new TestCase(""" + package t; + enum Test { + _ + } + """, + "8", + """ + package t; + \n\ + enum Test { + /*public static final*/ _ /* = new Test() */ /*enum*/ ; + } """, + """ + - compiler.warn.option.obsolete.source: 8 + - compiler.warn.option.obsolete.target: 8 + - compiler.warn.option.obsolete.suppression + Test.java:3:5: compiler.warn.underscore.as.identifier + """), + new TestCase(""" + package t; + enum Test { + _ + } + """, + System.getProperty("java.specification.version"), + """ + package t; + \n\ + enum Test { + /*public static final*/ _ /* = new Test() */ /*enum*/ ; + } """, + """ + Test.java:3:5: compiler.err.underscore.as.identifier + """), + new TestCase(""" + package t; + enum Test { + _; + } + """, + "8", + """ + package t; + \n\ + enum Test { + /*public static final*/ _ /* = new Test() */ /*enum*/ ; + } """, + """ + - compiler.warn.option.obsolete.source: 8 + - compiler.warn.option.obsolete.target: 8 + - compiler.warn.option.obsolete.suppression + Test.java:3:5: compiler.warn.underscore.as.identifier + """), + new TestCase(""" + package t; + enum Test { + _; + } + """, + System.getProperty("java.specification.version"), + """ + package t; + \n\ + enum Test { + /*public static final*/ _ /* = new Test() */ /*enum*/ ; + } """, + """ + Test.java:3:5: compiler.err.underscore.as.identifier + """), + new TestCase(""" + package t; + enum Test { + A; + void t() {} + _; + } + """, + "8", + """ + package t; + \n\ + enum Test { + /*public static final*/ A /* = new Test() */ /*enum*/ , + /*public static final*/ _ /* = new Test() */ /*enum*/ ; + \n\ + void t() { + } + } """, + """ + - compiler.warn.option.obsolete.source: 8 + - compiler.warn.option.obsolete.target: 8 + - compiler.warn.option.obsolete.suppression + Test.java:5:5: compiler.err.enum.constant.not.expected + Test.java:5:5: compiler.warn.underscore.as.identifier + """), + new TestCase(""" + package t; + enum Test { + A; + void t() {} + _; + } + """, + System.getProperty("java.specification.version"), + """ + package t; + \n\ + enum Test { + /*public static final*/ A /* = new Test() */ /*enum*/ , + /*public static final*/ _ /* = new Test() */ /*enum*/ ; + \n\ + void t() { + } + } """, + """ + Test.java:5:5: compiler.err.enum.constant.not.expected + """), + new TestCase(""" + package t; + enum Test { + _ {}, + A; + } + """, + "8", + """ + package t; + \n\ + enum Test { + /*public static final*/ _ /* = new Test() */ /*enum*/ { + }, + /*public static final*/ A /* = new Test() */ /*enum*/ ; + } """, + """ + - compiler.warn.option.obsolete.source: 8 + - compiler.warn.option.obsolete.target: 8 + - compiler.warn.option.obsolete.suppression + Test.java:3:5: compiler.warn.underscore.as.identifier + """), + new TestCase(""" + package t; + enum Test { + _ {}, + A; + } + """, + System.getProperty("java.specification.version"), + """ + package t; + \n\ + enum Test { + /*public static final*/ _ /* = new Test() */ /*enum*/ { + }, + /*public static final*/ A /* = new Test() */ /*enum*/ ; + } """, + """ + Test.java:3:5: compiler.err.underscore.as.identifier + """), + }; + for (TestCase testCase : testCases) { + StringWriter out = new StringWriter(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(out, fm, null, + List.of("-XDrawDiagnostics", "--release", testCase.release), + null, Arrays.asList(new MyFileObject(testCase.code))); + String ast = ct.parse().iterator().next().toString().replaceAll("\\R", "\n"); + assertEquals("Unexpected AST, got:\n" + ast, testCase.ast, ast); + assertEquals("Unexpected errors, got:\n" + out.toString(), + out.toString().replaceAll("\\R", "\n"), + testCase.errors); + } + } + void run(String[] args) throws Exception { int passed = 0, failed = 0; final Pattern p = (args != null && args.length > 0)