From 01ea1eff66e43f106640ecfd19fadf2c8245a1ad Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Sat, 14 Oct 2023 21:28:39 +0000 Subject: [PATCH] 8305971: NPE in JavacProcessingEnvironment for missing enum constructor body Reviewed-by: darcy --- .../JavacProcessingEnvironment.java | 2 +- .../CrashEmptyEnumConstructorTest.java | 131 ++++++++++++++++++ 2 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 test/langtools/tools/javac/annotations/crash_empty_enum_const/CrashEmptyEnumConstructorTest.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index d0dbbb56cfb..028b8ba8f9f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -1650,7 +1650,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea public void visitMethodDef(JCMethodDecl node) { // remove super constructor call that may have been added during attribution: if (TreeInfo.isConstructor(node) && node.sym != null && node.sym.owner.isEnum() && - node.body.stats.nonEmpty() && TreeInfo.isSuperCall(node.body.stats.head) && + node.body != null && node.body.stats.nonEmpty() && TreeInfo.isSuperCall(node.body.stats.head) && node.body.stats.head.pos == node.body.pos) { node.body.stats = node.body.stats.tail; } diff --git a/test/langtools/tools/javac/annotations/crash_empty_enum_const/CrashEmptyEnumConstructorTest.java b/test/langtools/tools/javac/annotations/crash_empty_enum_const/CrashEmptyEnumConstructorTest.java new file mode 100644 index 00000000000..29340dd720e --- /dev/null +++ b/test/langtools/tools/javac/annotations/crash_empty_enum_const/CrashEmptyEnumConstructorTest.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8305971 + * @summary NPE in JavacProcessingEnvironment for missing enum constructor body + * @library /tools/lib /tools/javac/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run main CrashEmptyEnumConstructorTest + */ + +import java.io.IOException; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import java.util.List; +import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.Task.Mode; +import toolbox.Task.OutputKind; +import toolbox.TestRunner; +import toolbox.ToolBox; + +public class CrashEmptyEnumConstructorTest extends TestRunner { + protected ToolBox tb; + + CrashEmptyEnumConstructorTest() { + super(System.err); + tb = new ToolBox(); + } + + public static void main(String... args) throws Exception { + new CrashEmptyEnumConstructorTest().runTests(); + } + + protected void runTests() throws Exception { + runTests(m -> new Object[]{Paths.get(m.getName())}); + } + + Path[] findJavaFiles(Path... paths) throws IOException { + return tb.findJavaFiles(paths); + } + + @Test + public void testEmptyEnumConstructor(Path base) throws Exception { + Path src = base.resolve("src"); + Path r = src.resolve("E"); + + Path classes = base.resolve("classes"); + + Files.createDirectories(classes); + + tb.writeJavaFiles(r, + """ + enum E { + ONE(""); + E(String one); + } + """); + + List expected = List.of( + "E.java:3: error: missing method body, or declare abstract", + " E(String one);", + " ^", + "1 error"); + + List log = new JavacTask(tb) + .options("-processor", SimpleProcessor.class.getName()) + .files(findJavaFiles(src)) + .outdir(classes) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + if (log.size() != expected.size()) { + throw new AssertionError("Unexpected output: " + log); + } else { + for (int i = 0; i < expected.size(); i++) { + if (!log.get(i).contains(expected.get(i))) { + throw new AssertionError("Unexpected output: " + log); + } + } + } + } + + @SupportedAnnotationTypes("*") + public static final class SimpleProcessor extends AbstractProcessor { + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + return false; + } + } +}