changeset 57708:a8680d72a2bf

8233655: NPE at jdk.compiler/com.sun.tools.javac.comp.Flow$FlowAnalyzer.visitApply Summary: Ensuring that errors reported during speculative attribution that belong to a different file are not lost. Reviewed-by: mcimadamore
author jlahoda
date Wed, 15 Jan 2020 11:31:16 +0100
parents d2f1fd498726
children 20c8599c64b7
files src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java test/langtools/tools/javac/T8177068/NoCompletionFailureSkipOnSpeculativeAttribution.java
diffstat 2 files changed, 62 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Tue Jan 14 20:19:51 2020 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Wed Jan 15 11:31:16 2020 +0100
@@ -505,14 +505,15 @@
     /**
      * Attribute the given tree, mostly reverting side-effects applied to shared
      * compiler state. Exceptions include the ArgumentAttr.argumentTypeCache,
-     * changes to which may be preserved if localCache is null.
+     * changes to which may be preserved if localCache is null and errors reported
+     * outside of the speculatively attributed tree.
      */
     <Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo,
                               Supplier<DiagnosticHandler> diagHandlerCreator, AttributionMode attributionMode,
                               LocalCacheContext localCache) {
         Env<AttrContext> speculativeEnv = env.dup(tree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
         speculativeEnv.info.attributionMode = attributionMode;
-        Log.DiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator != null ? diagHandlerCreator.get() : new DeferredDiagnosticHandler(log);
+        Log.DiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator != null ? diagHandlerCreator.get() : new DeferredAttrDiagHandler(log, tree);
         DeferredCompletionFailureHandler.Handler prevCFHandler = dcfh.setHandler(dcfh.speculativeCodeHandler);
         Queues prevQueues = annotate.setQueues(new Queues());
         int nwarnings = log.nwarnings;
@@ -531,6 +532,35 @@
             }
         }
     }
+    //where
+        static class DeferredAttrDiagHandler extends Log.DeferredDiagnosticHandler {
+
+            static class PosScanner extends TreeScanner {
+                DiagnosticPosition pos;
+                boolean found = false;
+
+                PosScanner(DiagnosticPosition pos) {
+                    this.pos = pos;
+                }
+
+                @Override
+                public void scan(JCTree tree) {
+                    if (tree != null &&
+                            tree.pos() == pos) {
+                        found = true;
+                    }
+                    super.scan(tree);
+                }
+            }
+
+            DeferredAttrDiagHandler(Log log, JCTree newTree) {
+                super(log, d -> {
+                    PosScanner posScanner = new PosScanner(d.getDiagnosticPosition());
+                    posScanner.scan(newTree);
+                    return posScanner.found;
+                });
+            }
+        }
 
     /**
      * A deferred context is created on each method check. A deferred context is
--- a/test/langtools/tools/javac/T8177068/NoCompletionFailureSkipOnSpeculativeAttribution.java	Tue Jan 14 20:19:51 2020 -0800
+++ b/test/langtools/tools/javac/T8177068/NoCompletionFailureSkipOnSpeculativeAttribution.java	Wed Jan 15 11:31:16 2020 +0100
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8177068
+ * @bug 8177068 8233655
  * @summary CompletionFailures occurring during speculative attribution should
  *          not be lost forever.
  * @library /tools/lib
@@ -72,6 +72,7 @@
 
     public static void main(String[] args) throws Exception {
         new NoCompletionFailureSkipOnSpeculativeAttribution().test();
+        new NoCompletionFailureSkipOnSpeculativeAttribution().test8233655();
     }
 
     public void test() throws Exception {
@@ -101,4 +102,32 @@
 
         Assert.check(output.equals(expectedOutput));
     }
+
+    public void test8233655() throws Exception {
+        ToolBox tb = new ToolBox();
+        tb.writeJavaFiles(Paths.get("."),
+                          "public class Test {" +
+                          "    private <T> T test(Class<?> c) {\n" +
+                          "        Class<?> c2 = test(test(Helper.class));\n" +
+                          "        return null;\n" +
+                          "    }\n" +
+                          "}",
+                          "public class Helper extends Unknown {}");
+
+        List<String> output = new JavacTask(tb)
+                .sourcepath(".")
+                .options("-XDrawDiagnostics")
+                .classpath(".")
+                .files("Test.java")
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        List<String> expectedOutput = List.of(
+                "Helper.java:1:29: compiler.err.cant.resolve: kindname.class, Unknown, , ",
+                "1 error"
+        );
+
+        Assert.check(output.equals(expectedOutput));
+    }
 }