From 316b1e2c8981b9a27e8ceb0d68eb14c0e7d4ed87 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 31 Jan 2025 13:27:09 +0100 Subject: [PATCH] 8349132: javac Analyzers should handle non-deferrable errors --- .../com/sun/tools/javac/comp/Analyzer.java | 4 +- .../classes/com/sun/tools/javac/util/Log.java | 12 +- .../tools/javac/analyzer/Diamond.java | 142 ++++++++++++++++++ 3 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 test/langtools/tools/javac/analyzer/Diamond.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java index 6a6e345365ca8..3caa17a4dd289 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -735,7 +735,7 @@ Log.DeferredDiagnosticHandler diagHandler() { erroneous = true; } return true; - }); + }, false); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java index 3d47354d9b6ec..56ee413ea0716 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java @@ -134,20 +134,28 @@ public void report(JCDiagnostic diag) { } public static class DeferredDiagnosticHandler extends DiagnosticHandler { private Queue deferred = new ListBuffer<>(); private final Predicate filter; + private final boolean passOnNonDeferrable; public DeferredDiagnosticHandler(Log log) { this(log, null); } - @SuppressWarnings("this-escape") public DeferredDiagnosticHandler(Log log, Predicate filter) { + this(log, filter, true); + } + + @SuppressWarnings("this-escape") + public DeferredDiagnosticHandler(Log log, Predicate filter, boolean passOnNonDeferrable) { this.filter = filter; + this.passOnNonDeferrable = passOnNonDeferrable; install(log); } @Override public void report(JCDiagnostic diag) { - if (!diag.isFlagSet(JCDiagnostic.DiagnosticFlag.NON_DEFERRABLE) && + boolean deferrable = !passOnNonDeferrable || + !diag.isFlagSet(JCDiagnostic.DiagnosticFlag.NON_DEFERRABLE); + if (deferrable && (filter == null || filter.test(diag))) { deferred.add(diag); } else { diff --git a/test/langtools/tools/javac/analyzer/Diamond.java b/test/langtools/tools/javac/analyzer/Diamond.java new file mode 100644 index 0000000000000..cee8d096cbd2c --- /dev/null +++ b/test/langtools/tools/javac/analyzer/Diamond.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2025, 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 8349132 + * @summary Check behavior of the diamond analyzer + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask + * @run main Diamond + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Objects; + +import toolbox.TestRunner; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class Diamond extends TestRunner { + + private final ToolBox tb; + + public static void main(String... args) throws Exception { + new Diamond().runTests(); + } + + Diamond() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test //JDK-8349132: + public void testMissingClassfileForConstructorParamType(Path base) throws Exception { + Path current = base.resolve("."); + Path lib = current.resolve("lib"); + Path libSrc = lib.resolve("src"); + Path libClasses = lib.resolve("classes"); + tb.writeJavaFiles(libSrc, + """ + package test; + public class Utils { + public static void run(Task uat) { + } + } + """, + """ + package test; + public interface Task { + public void run(T t) throws Exception; + } + """, + """ + package test; + public class Param { + } + """); + + Files.createDirectories(libClasses); + + new JavacTask(tb) + .outdir(libClasses) + .files(tb.findJavaFiles(libSrc)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + Files.delete(libClasses.resolve("test").resolve("Param.class")); + + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeJavaFiles(src, + """ + package test; + public class Test { + private static void test() { + Utils.run(new Task() { + @Override + public void run(Param parameter) throws Exception { + } + }); + } + } + """); + + Files.createDirectories(classes); + + var out = new JavacTask(tb) + .options("-XDfind=diamond", + "-XDshould-stop.at=FLOW", + "-XDrawDiagnostics") + .classpath(libClasses) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + var expectedOut = List.of( + "Test.java:4:28: compiler.err.cant.resolve.location: kindname.class, Param, , , (compiler.misc.location: kindname.class, test.Test, null)", + "Test.java:6:29: compiler.err.cant.resolve: kindname.class, Param, , ", + "2 errors" + ); + + if (!Objects.equals(expectedOut, out)) { + throw new AssertionError("Incorrect Output, expected: " + expectedOut + + ", actual: " + out); + + } + } + +}