test/tools/javac/modules/EdgeCases.java
author Dusan Balek <dbalek@netbeans.org>
Mon, 31 Jul 2017 11:07:41 +0200
changeset 5955 f54cccaf6e6c
parent 5947 554b3c813685
permissions -rw-r--r--
Mergin jlahoda's fix of #8182450: javac aborts when generating ct.sym intermittently - Initialize the module system model even in presence of missing/broken module-infos; BadClassFiles should not immediatelly abort compilation anymore, but should be handled as if the classfile did not exist.
     1 /*
     2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  */
    23 
    24 /*
    25  * @test
    26  * @bug 8154283 8167320 8171098 8172809 8173068 8173117 8176045 8177311
    27  * @summary tests for multi-module mode compilation
    28  * @library /tools/lib
    29  * @modules
    30  *      jdk.compiler/com.sun.tools.javac.api
    31  *      jdk.compiler/com.sun.tools.javac.code
    32  *      jdk.compiler/com.sun.tools.javac.main
    33  *      jdk.compiler/com.sun.tools.javac.processing
    34  *      jdk.compiler/com.sun.tools.javac.util
    35  * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask ModuleTestBase
    36  * @run main EdgeCases
    37  */
    38 
    39 import java.io.BufferedWriter;
    40 import java.io.Writer;
    41 import java.nio.file.Files;
    42 import java.nio.file.Path;
    43 import java.nio.file.Paths;
    44 import java.util.Arrays;
    45 import java.util.HashSet;
    46 import java.util.List;
    47 import java.util.Objects;
    48 import java.util.Set;
    49 
    50 import javax.annotation.processing.AbstractProcessor;
    51 import javax.annotation.processing.RoundEnvironment;
    52 import javax.annotation.processing.SupportedAnnotationTypes;
    53 import javax.annotation.processing.SupportedOptions;
    54 import javax.lang.model.SourceVersion;
    55 import javax.lang.model.element.Element;
    56 import javax.lang.model.element.ModuleElement;
    57 import javax.lang.model.element.ModuleElement.RequiresDirective;
    58 import javax.lang.model.element.PackageElement;
    59 import javax.lang.model.element.TypeElement;
    60 import javax.lang.model.util.ElementFilter;
    61 import javax.lang.model.util.Elements;
    62 import javax.tools.JavaCompiler;
    63 import javax.tools.JavaFileObject;
    64 import javax.tools.StandardJavaFileManager;
    65 import javax.tools.ToolProvider;
    66 
    67 import com.sun.source.tree.CompilationUnitTree;
    68 //import com.sun.source.util.JavacTask; // conflicts with toolbox.JavacTask
    69 import com.sun.tools.javac.api.JavacTaskImpl;
    70 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
    71 import com.sun.tools.javac.code.Symtab;
    72 
    73 import toolbox.JarTask;
    74 import toolbox.JavacTask;
    75 import toolbox.Task;
    76 import toolbox.Task.Expect;
    77 import toolbox.Task.OutputKind;
    78 
    79 public class EdgeCases extends ModuleTestBase {
    80 
    81     public static void main(String... args) throws Exception {
    82         new EdgeCases().runTests();
    83     }
    84 
    85     @Test
    86     public void testAddExportUndefinedModule(Path base) throws Exception {
    87         Path src = base.resolve("src");
    88         tb.writeJavaFiles(src, "package test; import undefPackage.Any; public class Test {}");
    89         Path classes = base.resolve("classes");
    90         tb.createDirectories(classes);
    91 
    92         List<String> log = new JavacTask(tb)
    93                 .options("--add-exports", "undefModule/undefPackage=ALL-UNNAMED",
    94                          "-XDrawDiagnostics")
    95                 .outdir(classes)
    96                 .files(findJavaFiles(src))
    97                 .run(Task.Expect.FAIL)
    98                 .writeAll()
    99                 .getOutputLines(Task.OutputKind.DIRECT);
   100 
   101         List<String> expected = Arrays.asList("- compiler.warn.module.for.option.not.found: --add-exports, undefModule",
   102                                               "Test.java:1:34: compiler.err.doesnt.exist: undefPackage",
   103                                               "1 error", "1 warning");
   104 
   105         if (!expected.equals(log))
   106             throw new Exception("expected output not found: " + log);
   107     }
   108 
   109     @Test
   110     public void testModuleSymbolOutterMostClass(Path base) throws Exception {
   111         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
   112         try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
   113             Path moduleSrc = base.resolve("module-src");
   114             Path m1 = moduleSrc.resolve("m1x");
   115 
   116             tb.writeJavaFiles(m1, "module m1x { }");
   117 
   118             Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(findJavaFiles(moduleSrc));
   119             com.sun.source.util.JavacTask task =
   120                 (com.sun.source.util.JavacTask) compiler.getTask(null, fm, null, null, null, files);
   121 
   122             task.analyze();
   123 
   124             ModuleSymbol msym = (ModuleSymbol) task.getElements().getModuleElement("m1x");
   125 
   126             msym.outermostClass();
   127         }
   128     }
   129 
   130     @Test
   131     public void testParseEnterAnalyze(Path base) throws Exception {
   132         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
   133         try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
   134             Path moduleSrc = base.resolve("module-src");
   135             Path m1 = moduleSrc.resolve("m1x");
   136 
   137             tb.writeJavaFiles(m1, "module m1x { }",
   138                                   "package p;",
   139                                   "package p; class T { }");
   140 
   141             Path classes = base.resolve("classes");
   142             Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(findJavaFiles(moduleSrc));
   143             List<String> options = Arrays.asList("-d", classes.toString(), "-Xpkginfo:always");
   144             JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, fm, null, options, null, files);
   145 
   146             Iterable<? extends CompilationUnitTree> parsed = task.parse();
   147             Iterable<? extends Element> entered = task.enter(parsed);
   148             Iterable<? extends Element> analyzed = task.analyze(entered);
   149             Iterable<? extends JavaFileObject> generatedFiles = task.generate(analyzed);
   150 
   151             Set<String> generated = new HashSet<>();
   152 
   153             for (JavaFileObject jfo : generatedFiles) {
   154                 generated.add(jfo.getName());
   155             }
   156 
   157             Set<String> expected = new HashSet<>(
   158                     Arrays.asList(Paths.get("testParseEnterAnalyze", "classes", "p", "package-info.class").toString(),
   159                                   Paths.get("testParseEnterAnalyze", "classes", "module-info.class").toString(),
   160                                   Paths.get("testParseEnterAnalyze", "classes", "p", "T.class").toString())
   161             );
   162 
   163             if (!Objects.equals(expected, generated))
   164                 throw new AssertionError("Incorrect generated files: " + generated);
   165         }
   166     }
   167 
   168     @Test
   169     public void testModuleImplicitModuleBoundaries(Path base) throws Exception {
   170         Path src = base.resolve("src");
   171         Path src_m1 = src.resolve("m1x");
   172         tb.writeJavaFiles(src_m1,
   173                           "module m1x { exports api1; }",
   174                           "package api1; public class Api1 { public void call() { } }");
   175         Path src_m2 = src.resolve("m2x");
   176         tb.writeJavaFiles(src_m2,
   177                           "module m2x { requires m1x; exports api2; }",
   178                           "package api2; public class Api2 { public static api1.Api1 get() { return null; } }");
   179         Path src_m3 = src.resolve("m3x");
   180         tb.writeJavaFiles(src_m3,
   181                           "module m3x { requires m2x; }",
   182                           "package test; public class Test { { api2.Api2.get().call(); api2.Api2.get().toString(); } }");
   183         Path classes = base.resolve("classes");
   184         tb.createDirectories(classes);
   185 
   186         String log = new JavacTask(tb)
   187                 .options("-XDrawDiagnostics",
   188                          "--module-source-path", src.toString())
   189                 .outdir(classes)
   190                 .files(findJavaFiles(src))
   191                 .run(Task.Expect.FAIL)
   192                 .writeAll()
   193                 .getOutput(Task.OutputKind.DIRECT);
   194 
   195         if (!log.contains("Test.java:1:52: compiler.err.not.def.access.class.intf.cant.access.reason: call(), api1.Api1, api1, (compiler.misc.not.def.access.does.not.read: m3x, api1, m1x)") ||
   196             !log.contains("Test.java:1:76: compiler.err.not.def.access.class.intf.cant.access: toString(), java.lang.Object"))
   197             throw new Exception("expected output not found");
   198     }
   199 
   200     @Test
   201     public void testAssignClassToAutomaticModule(Path base) throws Exception {
   202         //check that if a ClassSymbol belongs to an automatic module, it is properly assigned and not
   203         //duplicated when being accessed through a classfile.
   204         Path automaticSrc = base.resolve("automaticSrc");
   205         tb.writeJavaFiles(automaticSrc, "package api1; public class Api1 {}");
   206         Path automaticClasses = base.resolve("automaticClasses");
   207         tb.createDirectories(automaticClasses);
   208 
   209         String automaticLog = new JavacTask(tb)
   210                                 .outdir(automaticClasses)
   211                                 .files(findJavaFiles(automaticSrc))
   212                                 .run()
   213                                 .writeAll()
   214                                 .getOutput(Task.OutputKind.DIRECT);
   215 
   216         if (!automaticLog.isEmpty())
   217             throw new Exception("expected output not found: " + automaticLog);
   218 
   219         Path modulePath = base.resolve("module-path");
   220 
   221         Files.createDirectories(modulePath);
   222 
   223         Path automaticJar = modulePath.resolve("a-1.0.jar");
   224 
   225         new JarTask(tb, automaticJar)
   226           .baseDir(automaticClasses)
   227           .files("api1/Api1.class")
   228           .run();
   229 
   230         Path src = base.resolve("src");
   231         Path src_m2 = src.resolve("m2x");
   232         tb.writeJavaFiles(src_m2,
   233                           "module m2x { requires a; exports api2; }",
   234                           "package api2; public class Api2 { public static api1.Api1 get() { return null; } }");
   235         Path src_m3 = src.resolve("m3x");
   236         tb.writeJavaFiles(src_m3,
   237                           "module m3x { requires a; requires m2x; }",
   238                           "package test; public class Test { { api2.Api2.get(); api1.Api1 a1; } }");
   239         Path classes = base.resolve("classes");
   240         tb.createDirectories(classes);
   241 
   242         new JavacTask(tb)
   243                 .options("--module-path", modulePath.toString(),
   244                          "--module-source-path", src.toString())
   245                 .outdir(classes)
   246                 .files(findJavaFiles(src_m2))
   247                 .run()
   248                 .writeAll();
   249 
   250         new JavacTask(tb)
   251                 .options("--module-path", modulePath.toString(),
   252                          "--module-source-path", src.toString())
   253                 .outdir(classes)
   254                 .files(findJavaFiles(src_m3))
   255                 .run()
   256                 .writeAll();
   257     }
   258 
   259     @Test
   260     public void testEmptyImplicitModuleInfo(Path base) throws Exception {
   261         Path src = base.resolve("src");
   262         Path src_m1 = src.resolve("m1x");
   263         Files.createDirectories(src_m1);
   264         try (Writer w = Files.newBufferedWriter(src_m1.resolve("module-info.java"))) {}
   265         tb.writeJavaFiles(src_m1,
   266                           "package test; public class Test {}");
   267         Path classes = base.resolve("classes");
   268         tb.createDirectories(classes);
   269 
   270         List<String> log = new JavacTask(tb)
   271                 .options("--source-path", src_m1.toString(),
   272                          "-XDrawDiagnostics")
   273                 .outdir(classes)
   274                 .files(findJavaFiles(src_m1.resolve("test")))
   275                 .run(Task.Expect.FAIL)
   276                 .writeAll()
   277                 .getOutputLines(OutputKind.DIRECT);
   278 
   279         List<String> expected = Arrays.asList(
   280                 "- compiler.err.cant.access: module-info, (compiler.misc.bad.source.file.header: module-info.java, (compiler.misc.file.does.not.contain.module))",
   281                 "1 error");
   282 
   283         if (!expected.equals(log)) {
   284             throw new AssertionError("Unexpected output: " + log);
   285         }
   286 
   287         tb.writeJavaFiles(src_m1,
   288                           "module m1x {}");
   289 
   290         new JavacTask(tb)
   291                 .options("--source-path", src_m1.toString())
   292                 .outdir(classes)
   293                 .files(findJavaFiles(src_m1.resolve("test")))
   294                 .run()
   295                 .writeAll();
   296 
   297     }
   298 
   299     @Test
   300     public void testClassPackageClash(Path base) throws Exception {
   301         Path src = base.resolve("src");
   302         Path src_m1 = src.resolve("m1x");
   303         tb.writeJavaFiles(src_m1,
   304                           "module m1x { exports test.m1x; }",
   305                           "package test.m1x;\n" +
   306                           "public class Test {}\n");
   307         Path src_m2 = src.resolve("m2x");
   308         tb.writeJavaFiles(src_m2,
   309                           "module m2x { requires m1x; }",
   310                           "package test;\n" +
   311                           "public class m1x {}\n");
   312         Path classes = base.resolve("classes");
   313         tb.createDirectories(classes);
   314 
   315         List<String> log = new JavacTask(tb)
   316                 .options("--module-source-path", src.toString(),
   317                          "-XDrawDiagnostics")
   318                 .outdir(classes)
   319                 .files(findJavaFiles(src))
   320                 .run(Task.Expect.FAIL)
   321                 .writeAll()
   322                 .getOutputLines(Task.OutputKind.DIRECT);
   323 
   324         List<String> expected = Arrays.asList(
   325             "m1x.java:2:8: compiler.err.clash.with.pkg.of.same.name: kindname.class, test.m1x",
   326             "1 error"
   327         );
   328 
   329         if (!expected.equals(log)) {
   330             throw new IllegalStateException(log.toString());
   331         }
   332     }
   333 
   334     @Test
   335     public void testImplicitJavaBase(Path base) throws Exception {
   336         Path src = base.resolve("src");
   337         Path src_java_base = src.resolve("java.base");
   338         Files.createDirectories(src_java_base);
   339         tb.writeJavaFiles(src_java_base, "module java.base { exports java.lang; }");
   340         tb.writeJavaFiles(src_java_base,
   341                           "package java.lang; public class Object {}");
   342         Path classes = base.resolve("classes");
   343         tb.createDirectories(classes);
   344 
   345         //module-info from source:
   346         new JavacTask(tb)
   347             .options("-sourcepath", src_java_base.toString())
   348             .outdir(classes)
   349             .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
   350             .run()
   351             .writeAll();
   352 
   353         //module-info from class:
   354         if (!Files.exists(classes.resolve("module-info.class"))) {
   355             throw new AssertionError("module-info.class not created!");
   356         }
   357 
   358         new JavacTask(tb)
   359             .outdir(classes)
   360             .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
   361             .run()
   362             .writeAll();
   363 
   364         //broken module-info.class:
   365         Files.newOutputStream(classes.resolve("module-info.class")).close();
   366 
   367         List<String> log = new JavacTask(tb)
   368             .options("-XDrawDiagnostics")
   369             .outdir(classes)
   370             .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
   371             .run(Expect.FAIL)
   372             .writeAll()
   373             .getOutputLines(OutputKind.DIRECT);
   374 
   375         List<String> expected = Arrays.asList(
   376                 "- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.illegal.start.of.class.file))",
   377                 "1 error");
   378 
   379         if (!expected.equals(log)) {
   380             throw new AssertionError("Unexpected output: " + log);
   381         }
   382 
   383         //broken module-info.java:
   384         Files.delete(classes.resolve("module-info.class"));
   385 
   386         try (Writer out = Files.newBufferedWriter(src_java_base.resolve("module-info.java"))) {
   387             out.write("class Broken {}");
   388         }
   389 
   390         log = new JavacTask(tb)
   391             .options("-sourcepath", src_java_base.toString(),
   392                                 "-XDrawDiagnostics")
   393             .outdir(classes)
   394             .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
   395             .run(Expect.FAIL)
   396             .writeAll()
   397             .getOutputLines(OutputKind.DIRECT);
   398 
   399         expected = Arrays.asList("X");
   400 
   401         if (expected.equals(log)) {
   402             throw new AssertionError("Unexpected output: " + log);
   403         }
   404     }
   405 
   406     @Test
   407     public void testModuleInfoNameMismatchSource(Path base) throws Exception {
   408         Path src = base.resolve("src");
   409         Path m1 = src.resolve("m1x");
   410         Files.createDirectories(m1);
   411         tb.writeJavaFiles(m1, "module other { }",
   412                               "package test; public class Test {}");
   413         Path classes = base.resolve("classes");
   414         tb.createDirectories(classes);
   415 
   416         List<String> log = new JavacTask(tb)
   417             .options("--module-source-path", src.toString(),
   418                      "-XDrawDiagnostics")
   419             .outdir(classes)
   420             .files(findJavaFiles(m1.resolve("test").resolve("Test.java")))
   421             .run(Expect.FAIL)
   422             .writeAll()
   423             .getOutputLines(OutputKind.DIRECT);
   424 
   425         List<String> expected = Arrays.asList(
   426                 "module-info.java:1:1: compiler.err.module.name.mismatch: other, m1x",
   427                 "- compiler.err.cant.access: m1x.module-info, (compiler.misc.cant.resolve.modules)",
   428                 "2 errors");
   429 
   430         if (!expected.equals(log)) {
   431             throw new AssertionError("Unexpected output: " + log);
   432         }
   433     }
   434 
   435     @Test
   436     public void testModuleInfoNameMismatchClass(Path base) throws Exception {
   437         Path src = base.resolve("src");
   438         Files.createDirectories(src);
   439         tb.writeJavaFiles(src, "module other { }",
   440                                "package test; public class Test {}");
   441         Path classes = base.resolve("classes");
   442         Path m1Classes = classes.resolve("m1x");
   443         tb.createDirectories(m1Classes);
   444 
   445         new JavacTask(tb)
   446             .outdir(m1Classes)
   447             .files(findJavaFiles(src))
   448             .run()
   449             .writeAll()
   450             .getOutputLines(OutputKind.DIRECT);
   451 
   452         Path src2 = base.resolve("src2");
   453         Files.createDirectories(src2);
   454         tb.writeJavaFiles(src2, "module use { requires m1x; }");
   455 
   456         Path classes2 = base.resolve("classes2");
   457         tb.createDirectories(classes2);
   458 
   459         List<String> log = new JavacTask(tb)
   460             .options("--module-path", classes.toString(),
   461                      "-XDrawDiagnostics")
   462             .outdir(classes2)
   463             .files(findJavaFiles(src2))
   464             .run(Expect.FAIL)
   465             .writeAll()
   466             .getOutputLines(OutputKind.DIRECT);
   467 
   468         List<String> expected = Arrays.asList(
   469                 "- compiler.err.cant.access: m1x.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.module.name.mismatch: other, m1x))",
   470                 "module-info.java:1:1: compiler.err.module.not.found: m1x",
   471                 "2 errors");
   472 
   473         if (!expected.equals(log)) {
   474             throw new AssertionError("Unexpected output: " + log);
   475         }
   476     }
   477 
   478     @Test
   479     public void testGetDirectivesComplete(Path base) throws Exception {
   480         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
   481         JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, null, null, null, null, null);
   482         Symtab syms = Symtab.instance(task.getContext());
   483 
   484         syms.java_base.getDirectives();
   485     }
   486 
   487     @Test
   488     public void testPackageInModuleInfo(Path base) throws Exception {
   489         Path src = base.resolve("src");
   490         Files.createDirectories(src);
   491         tb.writeJavaFiles(src, "package p; module foo { }");
   492         Path classes = base.resolve("classes");
   493         tb.createDirectories(classes);
   494 
   495         List<String> log = new JavacTask(tb)
   496             .options("-XDrawDiagnostics", "-XDshould-stop.ifError=FLOW")
   497             .outdir(classes)
   498             .files(findJavaFiles(src))
   499             .run(Expect.FAIL)
   500             .writeAll()
   501             .getOutputLines(OutputKind.DIRECT);
   502 
   503         List<String> expected = Arrays.asList(
   504                 "module-info.java:1:1: compiler.err.no.pkg.in.module-info.java",
   505                 "1 error");
   506 
   507         if (!expected.equals(log)) {
   508             throw new AssertionError("Unexpected output: " + log);
   509         }
   510     }
   511 
   512     @Test
   513     public void testInvisibleClassVisiblePackageClash(Path base) throws Exception {
   514         Path src = base.resolve("src");
   515         Path src_m1 = src.resolve("m1x");
   516         tb.writeJavaFiles(src_m1,
   517                           "module m1x { }",
   518                           "package m1x;\n" +
   519                           "import m1x.a.*; public class Test { A a; }\n",
   520                           "package m1x.a;\n" +
   521                           "public class A { }\n");
   522         Path src_m2 = src.resolve("m2x");
   523         tb.writeJavaFiles(src_m2,
   524                           "module m2x { }",
   525                           "package m1x;\n" +
   526                           "public class a { public static class A { } }\n");
   527         Path classes = base.resolve("classes");
   528         tb.createDirectories(classes);
   529 
   530         new JavacTask(tb)
   531             .options("--module-source-path", src.toString(),
   532                      "-XDrawDiagnostics")
   533             .outdir(classes)
   534             .files(findJavaFiles(src))
   535             .run()
   536             .writeAll();
   537     }
   538 
   539     @Test
   540     public void testStripUnknownRequired(Path base) throws Exception {
   541         Path src = base.resolve("src");
   542         Path src_m1 = src.resolve("m1x");
   543         tb.writeJavaFiles(src_m1,
   544                           "module m1x { }");
   545         Path src_m2 = src.resolve("m2x");
   546         tb.writeJavaFiles(src_m2,
   547                           "module m2x { }");
   548         Path src_m3 = src.resolve("m3x");
   549         tb.writeJavaFiles(src_m3,
   550                           "module m3x { }");
   551         Path src_m4 = src.resolve("m4x");
   552         tb.writeJavaFiles(src_m4,
   553                           "module m4x { }");
   554         Path src_test = src.resolve("test");
   555         tb.writeJavaFiles(src_test,
   556                           "module test { requires m1x; requires m2x; requires java.base; requires m3x; requires m4x; }");
   557         Path src_compile = src.resolve("compile");
   558         tb.writeJavaFiles(src_compile,
   559                           "module compile { exports p to test; }",
   560                           "package p; public class Test { }");
   561         Path classes = base.resolve("classes");
   562         tb.createDirectories(classes);
   563 
   564         List<String> log = new JavacTask(tb)
   565                 .options("-processor", ListRequires.class.getName(),
   566                          "--module-source-path", src.toString(),
   567                          "--limit-modules", "compile",
   568                          "-XDaccessInternalAPI=true")
   569                 .outdir(classes)
   570                 .files(findJavaFiles(src_compile))
   571                 .run(Expect.FAIL)
   572                 .writeAll()
   573                 .getOutputLines(Task.OutputKind.STDOUT);
   574 
   575         List<String> expected = Arrays.asList(
   576                 "from directives:",
   577                 "java.base",
   578                 "from requires:",
   579                 "java.base"
   580         );
   581         if (!Objects.equals(log, expected))
   582             throw new AssertionError("Unexpected output: " + log);
   583     }
   584 
   585     @SupportedAnnotationTypes("*")
   586     @SupportedOptions("expectedEnclosedElements")
   587     public static final class ListRequires extends AbstractProcessor {
   588 
   589         private int round;
   590 
   591         @Override
   592         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
   593             if (round++ == 0) {
   594                 ModuleElement compileE = processingEnv.getElementUtils().getModuleElement("compile");
   595                 ModuleElement testE = ElementFilter.exportsIn(compileE.getDirectives()).get(0).getTargetModules().get(0);
   596 
   597                 System.out.println("from directives:");
   598                 for (RequiresDirective rd : ElementFilter.requiresIn(testE.getDirectives())) {
   599                     System.out.println(rd.getDependency().getSimpleName());
   600                 }
   601 
   602                 System.out.println("from requires:");
   603                 for (RequiresDirective rd : ((ModuleSymbol) testE).requires) {
   604                     System.out.println(rd.getDependency().getSimpleName());
   605                 }
   606             }
   607 
   608             return false;
   609         }
   610 
   611         @Override
   612         public SourceVersion getSupportedSourceVersion() {
   613             return SourceVersion.latest();
   614         }
   615 
   616     }
   617 
   618     @Test
   619     public void testOnDemandCompletionModuleInfoJava(Path base) throws Exception {
   620         Path src = base.resolve("src");
   621         Path src_m1 = src.resolve("m1x");
   622         tb.writeJavaFiles(src_m1,
   623                           "@Deprecated module m1x { }");
   624         Path src_m2 = src.resolve("m2x");
   625         tb.writeJavaFiles(src_m2,
   626                           "module m2x { requires m1x; }");
   627         Path src_m3 = src.resolve("m3x");
   628         tb.writeJavaFiles(src_m3,
   629                           "module m3x { requires m2x; requires m1x; }");
   630         Path classes = base.resolve("classes");
   631         tb.createDirectories(classes);
   632 
   633         List<String> log;
   634         List<String> expected;
   635 
   636         log = new JavacTask(tb)
   637                 .options("--module-source-path", src.toString())
   638                 .outdir(classes)
   639                 .files(findJavaFiles(src_m1))
   640                 .run()
   641                 .writeAll()
   642                 .getOutputLines(Task.OutputKind.DIRECT);
   643 
   644         expected = Arrays.asList("");
   645 
   646         if (!expected.equals(log)) {
   647             throw new IllegalStateException(log.toString());
   648         }
   649 
   650         log = new JavacTask(tb)
   651                 .options("--module-source-path", src.toString(),
   652                          "-XDrawDiagnostics",
   653                          "-Xlint:deprecation")
   654                 .outdir(classes)
   655                 .files(findJavaFiles(src_m3))
   656                 .run()
   657                 .writeAll()
   658                 .getOutputLines(Task.OutputKind.DIRECT);
   659 
   660         expected = Arrays.asList(
   661                 "module-info.java:1:23: compiler.warn.has.been.deprecated.module: m1x",
   662                 "module-info.java:1:37: compiler.warn.has.been.deprecated.module: m1x",
   663                 "2 warnings"
   664         );
   665 
   666         if (!expected.equals(log)) {
   667             throw new IllegalStateException(log.toString());
   668         }
   669     }
   670 
   671     @Test
   672     public void testUnnamedPackage(Path base) throws Exception {
   673         List<String> out;
   674         List<String> expected;
   675 
   676         //-source 8:
   677         Path src8 = base.resolve("src8");
   678         Files.createDirectories(src8);
   679         tb.writeJavaFiles(src8,
   680                           "package test; public class Test {}");
   681         Path classes = base.resolve("classes");
   682         tb.createDirectories(classes);
   683 
   684         out = new JavacTask(tb)
   685                 .options("--source-path", src8.toString(),
   686                          "-processor", UnnamedPackageProcessor.class.getName(),
   687                          "-source", "8")
   688                 .outdir(classes)
   689                 .files(findJavaFiles(src8))
   690                 .run()
   691                 .writeAll()
   692                 .getOutputLines(OutputKind.STDOUT);
   693 
   694         expected = Arrays.asList("noModule");
   695 
   696         if (!expected.equals(out)) {
   697             throw new AssertionError("Unexpected output: " + out);
   698         }
   699 
   700         //-source 9, unnamed:
   701         Path srcUnnamed = base.resolve("srcUnnamed");
   702         Files.createDirectories(srcUnnamed);
   703         tb.writeJavaFiles(srcUnnamed,
   704                           "public class Test {}");
   705         Path classesUnnamed = base.resolve("classesUnnamed");
   706         tb.createDirectories(classesUnnamed);
   707 
   708         out = new JavacTask(tb)
   709                 .options("--source-path", srcUnnamed.toString(),
   710                          "-processor", UnnamedPackageProcessor.class.getName())
   711                 .outdir(classesUnnamed)
   712                 .files(findJavaFiles(srcUnnamed))
   713                 .run()
   714                 .writeAll()
   715                 .getOutputLines(OutputKind.STDOUT);
   716 
   717         expected = Arrays.asList("unnamedModule");
   718 
   719         if (!expected.equals(out)) {
   720             throw new AssertionError("Unexpected output: " + out);
   721         }
   722 
   723         //-source 9, named:
   724         Path srcNamed = base.resolve("srcNamed");
   725         Files.createDirectories(srcNamed);
   726         tb.writeJavaFiles(srcNamed,
   727                           "module m {}",
   728                           "public class Test {}");
   729         Path classesNamed = base.resolve("classesNamed");
   730         tb.createDirectories(classesNamed);
   731 
   732         out = new JavacTask(tb)
   733                 .options("--source-path", srcNamed.toString(),
   734                          "-classpath", "",
   735                          "-processorpath", System.getProperty("test.class.path"),
   736                          "-processor", UnnamedPackageProcessor.class.getName())
   737                 .outdir(classesNamed)
   738                 .files(findJavaFiles(srcNamed))
   739                 .run()
   740                 .writeAll()
   741                 .getOutputLines(OutputKind.STDOUT);
   742 
   743         expected = Arrays.asList("m");
   744 
   745         if (!expected.equals(out)) {
   746             throw new AssertionError("Unexpected output: " + out);
   747         }
   748 
   749         //-source 9, conflict:
   750         Path srcNamed2 = base.resolve("srcNamed2");
   751         Path srcNamed2m1 = srcNamed2.resolve("m1x");
   752         Files.createDirectories(srcNamed2m1);
   753         tb.writeJavaFiles(srcNamed2m1,
   754                           "module m1x {}",
   755                           "public class Test {}");
   756         Path srcNamed2m2 = srcNamed2.resolve("m2x");
   757         Files.createDirectories(srcNamed2m2);
   758         tb.writeJavaFiles(srcNamed2m2,
   759                           "module m2x {}",
   760                           "public class Test {}");
   761         Path classesNamed2 = base.resolve("classesNamed2");
   762         tb.createDirectories(classesNamed2);
   763 
   764         out = new JavacTask(tb)
   765                 .options("--module-source-path", srcNamed2.toString(),
   766                          "-classpath", "",
   767                          "-processorpath", System.getProperty("test.class.path"),
   768                          "-processor", UnnamedPackageProcessor.class.getName(),
   769                          "-XDshould-stop.ifError=FLOW")
   770                 .outdir(classesNamed2)
   771                 .files(findJavaFiles(srcNamed2))
   772                 .run(Expect.FAIL)
   773                 .writeAll()
   774                 .getOutputLines(OutputKind.STDOUT);
   775 
   776         expected = Arrays.asList("null",
   777                                  "m1x: true",
   778                                  "m2x: true");
   779 
   780         if (!expected.equals(out)) {
   781             throw new AssertionError("Unexpected output: " + out);
   782         }
   783     }
   784 
   785     @SupportedAnnotationTypes("*")
   786     public static final class UnnamedPackageProcessor extends AbstractProcessor {
   787 
   788         int round = 0;
   789 
   790         @Override
   791         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
   792             if (round++ != 0)
   793                 return false;
   794 
   795             Elements elements = processingEnv.getElementUtils();
   796             PackageElement pe = elements.getPackageElement("");
   797 
   798             if (pe == null) {
   799                 System.out.println("null");
   800             } else {
   801                 ModuleElement mod = (ModuleElement) pe.getEnclosingElement();
   802                 if (mod == null) {
   803                     System.out.println("noModule");
   804                 } else if (mod.isUnnamed()) {
   805                     System.out.println("unnamedModule");
   806                 } else {
   807                     System.out.println(mod);
   808                 }
   809             }
   810 
   811             ModuleElement m1x = elements.getModuleElement("m1x");
   812             ModuleElement m2x = elements.getModuleElement("m2x");
   813 
   814             if (m1x != null && m2x != null) {
   815                 System.out.println("m1x: " + (elements.getPackageElement(m1x, "") != null));
   816                 System.out.println("m2x: " + (elements.getPackageElement(m2x, "") != null));
   817             }
   818 
   819             return false;
   820         }
   821 
   822     }
   823 
   824     @Test
   825     public void testEmptyInExportedPackage(Path base) throws Exception {
   826         Path src = base.resolve("src");
   827         Path m = src.resolve("m");
   828         tb.writeJavaFiles(m,
   829                           "module m { exports api; }");
   830         Path apiFile = m.resolve("api").resolve("Api.java");
   831         Files.createDirectories(apiFile.getParent());
   832         try (BufferedWriter w = Files.newBufferedWriter(apiFile)) {
   833             w.write("//no package decl");
   834         }
   835         Path classes = base.resolve("classes");
   836         tb.createDirectories(classes);
   837 
   838         List<String> log;
   839         List<String> expected =
   840                 Arrays.asList("module-info.java:1:20: compiler.err.package.empty.or.not.found: api",
   841                               "1 error");
   842 
   843         System.err.println("file explicitly specified:");
   844 
   845         log = new JavacTask(tb)
   846             .options("-XDrawDiagnostics",
   847                      "--module-source-path", src.toString())
   848             .outdir(classes)
   849             .files(findJavaFiles(src))
   850             .run(Task.Expect.FAIL)
   851             .writeAll()
   852             .getOutputLines(Task.OutputKind.DIRECT);
   853 
   854         if (!expected.equals(log))
   855             throw new Exception("expected output not found: " + log);
   856 
   857         System.err.println("file not specified:");
   858 
   859         tb.cleanDirectory(classes);
   860 
   861         log = new JavacTask(tb)
   862             .options("-XDrawDiagnostics",
   863                      "--module-source-path", src.toString())
   864             .outdir(classes)
   865             .files(findJavaFiles(m.resolve("module-info.java")))
   866             .run(Task.Expect.FAIL)
   867             .writeAll()
   868             .getOutputLines(Task.OutputKind.DIRECT);
   869 
   870         if (!expected.equals(log))
   871             throw new Exception("expected output not found: " + log);
   872     }
   873 
   874     @Test
   875     public void testJustPackageInExportedPackage(Path base) throws Exception {
   876         Path src = base.resolve("src");
   877         Path m = src.resolve("m");
   878         tb.writeJavaFiles(m,
   879                           "module m { exports api; }");
   880         Path apiFile = m.resolve("api").resolve("Api.java");
   881         Files.createDirectories(apiFile.getParent());
   882         try (BufferedWriter w = Files.newBufferedWriter(apiFile)) {
   883             w.write("package api;");
   884         }
   885         Path classes = base.resolve("classes");
   886         tb.createDirectories(classes);
   887 
   888         System.err.println("file explicitly specified:");
   889 
   890         new JavacTask(tb)
   891             .options("-XDrawDiagnostics",
   892                      "--module-source-path", src.toString())
   893             .outdir(classes)
   894             .files(findJavaFiles(src))
   895             .run()
   896             .writeAll();
   897 
   898         System.err.println("file not specified:");
   899 
   900         tb.cleanDirectory(classes);
   901 
   902         new JavacTask(tb)
   903             .options("-XDrawDiagnostics",
   904                      "--module-source-path", src.toString())
   905             .outdir(classes)
   906             .files(findJavaFiles(m.resolve("module-info.java")))
   907             .run()
   908             .writeAll();
   909     }
   910 
   911     @Test
   912     public void testWrongPackageInExportedPackage(Path base) throws Exception {
   913         Path src = base.resolve("src");
   914         Path m = src.resolve("m");
   915         tb.writeJavaFiles(m,
   916                           "module m { exports api; }");
   917         Path apiFile = m.resolve("api").resolve("Api.java");
   918         Files.createDirectories(apiFile.getParent());
   919         try (BufferedWriter w = Files.newBufferedWriter(apiFile)) {
   920             w.write("package impl; public class Api { }");
   921         }
   922         Path classes = base.resolve("classes");
   923         tb.createDirectories(classes);
   924 
   925         List<String> log;
   926 
   927         List<String> expected =
   928                 Arrays.asList("module-info.java:1:20: compiler.err.package.empty.or.not.found: api",
   929                               "1 error");
   930 
   931         System.err.println("file explicitly specified:");
   932 
   933         log = new JavacTask(tb)
   934                 .options("-XDrawDiagnostics",
   935                          "--module-source-path", src.toString())
   936                 .outdir(classes)
   937                 .files(findJavaFiles(src))
   938                 .run(Task.Expect.FAIL)
   939                 .writeAll()
   940                 .getOutputLines(Task.OutputKind.DIRECT);
   941 
   942         if (!expected.equals(log))
   943             throw new Exception("expected output not found: " + log);
   944 
   945         System.err.println("file not specified:");
   946 
   947         tb.cleanDirectory(classes);
   948 
   949         log = new JavacTask(tb)
   950                 .options("-XDrawDiagnostics",
   951                          "--module-source-path", src.toString())
   952                 .outdir(classes)
   953                 .files(findJavaFiles(m.resolve("module-info.java")))
   954                 .run(Task.Expect.FAIL)
   955                 .writeAll()
   956                 .getOutputLines(Task.OutputKind.DIRECT);
   957 
   958         if (!expected.equals(log))
   959             throw new Exception("expected output not found: " + log);
   960     }
   961 
   962     @Test
   963     public void testDependOnUnnamedAccessibility(Path base) throws Exception {
   964         Path unnamedSrc = base.resolve("unnamed-src");
   965         tb.writeJavaFiles(unnamedSrc,
   966                           "package p1; public class First { public static p2.Second get() { return null; } }",
   967                           "package p2; public class Second { public void test() { } }");
   968         Path unnamedClasses = base.resolve("unnamed-classes");
   969         tb.createDirectories(unnamedClasses);
   970 
   971         System.err.println("compiling unnamed sources:");
   972 
   973         new JavacTask(tb)
   974                 .outdir(unnamedClasses)
   975                 .files(findJavaFiles(unnamedSrc))
   976                 .run()
   977                 .writeAll();
   978 
   979         //test sources:
   980         Path src = base.resolve("src");
   981         Path m = src.resolve("m");
   982         tb.writeJavaFiles(m,
   983                           "module m { }",
   984                           "package p; public class Test { { p1.First.get().test(); } }");
   985         Path classes = base.resolve("classes");
   986         tb.createDirectories(classes);
   987 
   988         System.err.println("compiling test module:");
   989 
   990         new JavacTask(tb)
   991             .options("-classpath", unnamedClasses.toString(),
   992                      "--add-reads", "m=ALL-UNNAMED")
   993             .outdir(classes)
   994             .files(findJavaFiles(src))
   995             .run()
   996             .writeAll();
   997     }
   998 
   999 }