8191112: javac OutOfMemoryError caused by \"-Xlint:exports\" option
authorjlahoda
Tue, 21 Nov 2017 10:26:45 +0100
changeset 47873 7944849362f3
parent 47872 49e605998d2b
child 47874 a7d101e56b36
child 47875 93bba74ed8a3
child 55844 dbcbcda0e413
8191112: javac OutOfMemoryError caused by \"-Xlint:exports\" option Summary: When validating type visibility, ignore transitive automatic modules dependencies. Reviewed-by: abuckley, jjg
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
test/langtools/tools/javac/modules/ExportsUnexported.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Nov 21 01:25:36 2017 -0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Nov 21 10:26:45 2017 +0100
@@ -3918,6 +3918,8 @@
                     todo = todo.tail;
                     if (current == whatPackage.modle)
                         return ; //OK
+                    if ((current.flags() & Flags.AUTOMATIC_MODULE) != 0)
+                        continue; //for automatic modules, don't look into their dependencies
                     for (RequiresDirective req : current.requires) {
                         if (req.isTransitive()) {
                             todo = todo.prepend(req.module);
--- a/test/langtools/tools/javac/modules/ExportsUnexported.java	Tue Nov 21 01:25:36 2017 -0800
+++ b/test/langtools/tools/javac/modules/ExportsUnexported.java	Tue Nov 21 10:26:45 2017 +0100
@@ -23,6 +23,7 @@
 
 /*
  * @test
+ * @bug 8191112
  * @summary tests for module declarations
  * @library /tools/lib
  * @modules jdk.compiler/com.sun.tools.javac.api
@@ -31,12 +32,15 @@
  * @run main ExportsUnexported
  */
 
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
 
+import toolbox.JarTask;
 import toolbox.JavacTask;
 import toolbox.Task;
 
@@ -374,4 +378,98 @@
             throw new Exception("expected output not found");
     }
 
+    @Test
+    public void testTransitiveAndAutomaticModules(Path base) throws Exception {
+        Path modulePath = base.resolve("module-path");
+
+        Files.createDirectories(modulePath);
+
+        createAutomaticModule(base,
+                              modulePath.resolve("api-one-1.0.jar"),
+                              "package api1; public interface Api1 {}");
+        createAutomaticModule(base,
+                              modulePath.resolve("api-two-1.0.jar"),
+                              "package api2; public interface Api2 {}");
+        createAutomaticModule(base,
+                              modulePath.resolve("api-three-1.0.jar"),
+                              "package api3; public interface Api3 {}");
+
+        Path src = base.resolve("src");
+        Path src_api = src.resolve("api");
+        tb.writeJavaFiles(src_api,
+                          "module api {\n" +
+                          "    requires transitive dep;\n" +
+                          "    requires transitive api.one;\n" +
+                          "    exports api;\n" +
+                          "}\n",
+                          "package api;\n" +
+                          "public class Api extends dep.Dep implements api2.Api2 {}\n");
+        Path src_dep = src.resolve("dep");
+        tb.writeJavaFiles(src_dep,
+                          "module dep {\n" +
+                          "    requires transitive api.one;\n" +
+                          "    exports dep;\n" +
+                          "}\n",
+                          "package dep;\n" +
+                          "public class Dep {}\n");
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        List<String> log = new JavacTask(tb)
+                .options("-XDrawDiagnostics",
+                         "-Werror",
+                         "--module-source-path", src.toString(),
+                         "--module-path", modulePath.toString(),
+                         "-Xlint:exports,-requires-transitive-automatic")
+                .outdir(classes)
+                .files(findJavaFiles(src))
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        List<String> expected = Arrays.asList(
+            "Api.java:2:49: compiler.warn.leaks.not.accessible.not.required.transitive: kindname.interface, api2.Api2, api.two",
+            "- compiler.err.warnings.and.werror",
+            "1 error",
+            "1 warning"
+        );
+
+        if (!log.equals(expected))
+            throw new Exception("expected output not found");
+    }
+
+    private void createAutomaticModule(Path base, Path jar, String content) throws Exception {
+        Path scratch = base.resolve("scratch");
+        Files.createDirectories(scratch);
+        tb.cleanDirectory(scratch);
+        tb.writeJavaFiles(scratch,
+                          content);
+        Path scratchClasses = base.resolve("scratch-classes");
+        Files.createDirectories(scratchClasses);
+        tb.cleanDirectory(scratchClasses);
+
+        String log = new JavacTask(tb)
+                .options()
+                .outdir(scratchClasses)
+                .files(findJavaFiles(scratch))
+                .run()
+                .writeAll()
+                .getOutput(Task.OutputKind.DIRECT);
+
+        if (!log.isEmpty()) {
+            throw new Exception("unexpected output: " + log);
+        }
+
+        Files.createDirectories(scratchClasses.getParent());
+        Files.deleteIfExists(jar);
+
+        new JarTask(tb, jar)
+          .baseDir(scratchClasses)
+          .files(Arrays.stream(tb.findFiles(".class", scratchClasses))
+                       .map(p -> scratchClasses.relativize(p).toString())
+                       .collect(Collectors.toList())
+                       .toArray(new String[0]))
+          .run();
+    }
+
 }