From 72f199024d58b53a1dff2f79dd2050ae0044e809 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 22 Jan 2024 10:55:10 +0000 Subject: [PATCH] 8323057: Recoverable errors may be reported before unrecoverable errors when annotation processing is skipped Reviewed-by: vromero --- .../sun/tools/javac/main/JavaCompiler.java | 34 +++--- .../JavacProcessingEnvironment.java | 4 +- .../classes/com/sun/tools/javac/util/Log.java | 11 ++ .../processing/errors/TestErrorOrder.java | 110 ++++++++++++++++++ 4 files changed, 141 insertions(+), 18 deletions(-) create mode 100644 test/langtools/tools/javac/processing/errors/TestErrorOrder.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 10f4d609c68..63950ed2f68 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -30,7 +30,7 @@ import java.nio.file.FileSystemNotFoundException; import java.nio.file.InvalidPathException; import java.nio.file.ReadOnlyFileSystemException; import java.util.Collection; -import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -41,6 +41,7 @@ import java.util.Queue; import java.util.ResourceBundle; import java.util.Set; import java.util.function.Function; +import java.util.function.ToIntFunction; import javax.annotation.processing.Processor; import javax.lang.model.SourceVersion; @@ -986,10 +987,7 @@ public class JavaCompiler { // In case an Abort was thrown before processAnnotations could be called, // we could have deferred diagnostics that haven't been reported. - if (deferredDiagnosticHandler != null) { - deferredDiagnosticHandler.reportDeferredDiagnostics(); - log.popDiagnosticHandler(deferredDiagnosticHandler); - } + reportDeferredDiagnosticAndClearHandler(); } finally { if (verbose) { elapsed_msec = elapsed(start_msec); @@ -1196,8 +1194,7 @@ public class JavaCompiler { // or other errors during enter which cannot be fixed by running // any annotation processors. if (processAnnotations) { - deferredDiagnosticHandler.reportDeferredDiagnostics(); - log.popDiagnosticHandler(deferredDiagnosticHandler); + reportDeferredDiagnosticAndClearHandler(); return ; } } @@ -1233,8 +1230,7 @@ public class JavaCompiler { // processing if (!explicitAnnotationProcessingRequested()) { log.error(Errors.ProcNoExplicitAnnotationProcessingRequested(classnames)); - deferredDiagnosticHandler.reportDeferredDiagnostics(); - log.popDiagnosticHandler(deferredDiagnosticHandler); + reportDeferredDiagnosticAndClearHandler(); return ; // TODO: Will this halt compilation? } else { boolean errors = false; @@ -1268,8 +1264,7 @@ public class JavaCompiler { } } if (errors) { - deferredDiagnosticHandler.reportDeferredDiagnostics(); - log.popDiagnosticHandler(deferredDiagnosticHandler); + reportDeferredDiagnosticAndClearHandler(); return ; } } @@ -1286,10 +1281,7 @@ public class JavaCompiler { } } catch (CompletionFailure ex) { log.error(Errors.CantAccess(ex.sym, ex.getDetailValue())); - if (deferredDiagnosticHandler != null) { - deferredDiagnosticHandler.reportDeferredDiagnostics(); - log.popDiagnosticHandler(deferredDiagnosticHandler); - } + reportDeferredDiagnosticAndClearHandler(); } } @@ -1859,6 +1851,18 @@ public class JavaCompiler { } } + public void reportDeferredDiagnosticAndClearHandler() { + if (deferredDiagnosticHandler != null) { + ToIntFunction diagValue = + d -> d.isFlagSet(RECOVERABLE) ? 1 : 0; + Comparator compareDiags = + (d1, d2) -> diagValue.applyAsInt(d1) - diagValue.applyAsInt(d2); + deferredDiagnosticHandler.reportDeferredDiagnostics(compareDiags); + log.popDiagnosticHandler(deferredDiagnosticHandler); + deferredDiagnosticHandler = null; + } + } + /** Close the compiler, flushing the logs */ public void close() { 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 c9fba238901..1870d487c59 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 @@ -1268,9 +1268,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea // we're specifically expecting Abort here, but if any Throwable // comes by, we should flush all deferred diagnostics, rather than // drop them on the ground. - deferredDiagnosticHandler.reportDeferredDiagnostics(); - log.popDiagnosticHandler(deferredDiagnosticHandler); - compiler.setDeferredDiagnosticHandler(null); + compiler.reportDeferredDiagnosticAndClearHandler(); throw t; } finally { if (!taskListener.isEmpty()) 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 2b21dda0545..b4260b84e1d 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 @@ -27,6 +27,7 @@ package com.sun.tools.javac.util; import java.io.*; import java.util.Arrays; +import java.util.Comparator; import java.util.EnumMap; import java.util.HashSet; import java.util.Map; @@ -172,6 +173,16 @@ public class Log extends AbstractLog { } deferred = null; // prevent accidental ongoing use } + + /** Report selected deferred diagnostics. */ + public void reportDeferredDiagnostics(Comparator order) { + JCDiagnostic[] diags = deferred.toArray(s -> new JCDiagnostic[s]); + Arrays.sort(diags, order); + for (JCDiagnostic d : diags) { + prev.report(d); + } + deferred = null; // prevent accidental ongoing use + } } public enum WriterKind { NOTICE, WARNING, ERROR, STDOUT, STDERR } diff --git a/test/langtools/tools/javac/processing/errors/TestErrorOrder.java b/test/langtools/tools/javac/processing/errors/TestErrorOrder.java new file mode 100644 index 00000000000..76946ff02aa --- /dev/null +++ b/test/langtools/tools/javac/processing/errors/TestErrorOrder.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2024, 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 8323057 + * @summary javac should print not-recoverable errors before recoverable errors + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.TestRunner toolbox.ToolBox TestErrorOrder + * @run main TestErrorOrder + */ + +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.Expect; +import toolbox.TestRunner; +import toolbox.TestRunner.Test; +import toolbox.ToolBox; + +public class TestErrorOrder extends TestRunner { + public static void main(String... args) throws Exception { + new TestErrorOrder().runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + private final ToolBox tb = new ToolBox(); + + public TestErrorOrder() { + super(System.err); + } + + @Test + public void testErrorsAfter(Path outerBase) throws Exception { + Path src = outerBase.resolve("src"); + tb.writeJavaFiles(src, + "package t;\n" + + "public class T {\n" + + " public void test(Undefined u) { }\n" + + " \n" + + " @SuppressWarnings(\"\")\n" + + " @SuppressWarnings(\"\")\n" + + " public void test() { }\n" + + "}"); + Path classes = outerBase.resolve("classes"); + Files.createDirectories(classes); + List actual = new JavacTask(tb) + .outdir(classes.toString()) + .options("-XDrawDiagnostics", + "-processor", "TestErrorOrder$P", + "-processorpath", System.getProperty("test.classes")) + .files(tb.findJavaFiles(src)) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + List expected = List.of( + "T.java:6:5: compiler.err.duplicate.annotation.missing.container: java.lang.SuppressWarnings", + "T.java:3:22: compiler.err.cant.resolve.location: kindname.class, Undefined, , , (compiler.misc.location: kindname.class, t.T, null)", + "2 errors" + ); + + tb.checkEqual(expected, actual); + } + + @SupportedAnnotationTypes("*") + public static class P extends AbstractProcessor { + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + return false; + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + } + +}