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                 "1 error");
 471 
 472         if (!expected.equals(log)) {
 473             throw new AssertionError("Unexpected output: " + log);
 474         }
 475     }
 476 
 477     @Test
 478     public void testGetDirectivesComplete(Path base) throws Exception {
 479         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
 480         JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, null, null, null, null, null);
 481         Symtab syms = Symtab.instance(task.getContext());
 482 
 483         syms.java_base.getDirectives();
 484     }
 485 
 486     @Test
 487     public void testPackageInModuleInfo(Path base) throws Exception {
 488         Path src = base.resolve("src");
 489         Files.createDirectories(src);
 490         tb.writeJavaFiles(src, "package p; module foo { }");
 491         Path classes = base.resolve("classes");
 492         tb.createDirectories(classes);
 493 
 494         List<String> log = new JavacTask(tb)
 495             .options("-XDrawDiagnostics", "-XDshould-stop.ifError=FLOW")
 496             .outdir(classes)
 497             .files(findJavaFiles(src))
 498             .run(Expect.FAIL)
 499             .writeAll()
 500             .getOutputLines(OutputKind.DIRECT);
 501 
 502         List<String> expected = Arrays.asList(
 503                 "module-info.java:1:1: compiler.err.no.pkg.in.module-info.java",
 504                 "1 error");
 505 
 506         if (!expected.equals(log)) {
 507             throw new AssertionError("Unexpected output: " + log);
 508         }
 509     }
 510 
 511     @Test
 512     public void testInvisibleClassVisiblePackageClash(Path base) throws Exception {
 513         Path src = base.resolve("src");
 514         Path src_m1 = src.resolve("m1x");
 515         tb.writeJavaFiles(src_m1,
 516                           "module m1x { }",
 517                           "package m1x;\n" +
 518                           "import m1x.a.*; public class Test { A a; }\n",
 519                           "package m1x.a;\n" +
 520                           "public class A { }\n");
 521         Path src_m2 = src.resolve("m2x");
 522         tb.writeJavaFiles(src_m2,
 523                           "module m2x { }",
 524                           "package m1x;\n" +
 525                           "public class a { public static class A { } }\n");
 526         Path classes = base.resolve("classes");
 527         tb.createDirectories(classes);
 528 
 529         new JavacTask(tb)
 530             .options("--module-source-path", src.toString(),
 531                      "-XDrawDiagnostics")
 532             .outdir(classes)
 533             .files(findJavaFiles(src))
 534             .run()
 535             .writeAll();
 536     }
 537 
 538     @Test
 539     public void testStripUnknownRequired(Path base) throws Exception {
 540         Path src = base.resolve("src");
 541         Path src_m1 = src.resolve("m1x");
 542         tb.writeJavaFiles(src_m1,
 543                           "module m1x { }");
 544         Path src_m2 = src.resolve("m2x");
 545         tb.writeJavaFiles(src_m2,
 546                           "module m2x { }");
 547         Path src_m3 = src.resolve("m3x");
 548         tb.writeJavaFiles(src_m3,
 549                           "module m3x { }");
 550         Path src_m4 = src.resolve("m4x");
 551         tb.writeJavaFiles(src_m4,
 552                           "module m4x { }");
 553         Path src_test = src.resolve("test");
 554         tb.writeJavaFiles(src_test,
 555                           "module test { requires m1x; requires m2x; requires java.base; requires m3x; requires m4x; }");
 556         Path src_compile = src.resolve("compile");
 557         tb.writeJavaFiles(src_compile,
 558                           "module compile { exports p to test; }",
 559                           "package p; public class Test { }");
 560         Path classes = base.resolve("classes");
 561         tb.createDirectories(classes);
 562 
 563         List<String> log = new JavacTask(tb)
 564                 .options("-processor", ListRequires.class.getName(),
 565                          "--module-source-path", src.toString(),
 566                          "--limit-modules", "compile",
 567                          "-XDaccessInternalAPI=true")
 568                 .outdir(classes)
 569                 .files(findJavaFiles(src_compile))
 570                 .run(Expect.FAIL)
 571                 .writeAll()
 572                 .getOutputLines(Task.OutputKind.STDOUT);
 573 
 574         List<String> expected = Arrays.asList(
 575                 "from directives:",
 576                 "java.base",
 577                 "from requires:",
 578                 "java.base"
 579         );
 580         if (!Objects.equals(log, expected))
 581             throw new AssertionError("Unexpected output: " + log);
 582     }
 583 
 584     @SupportedAnnotationTypes("*")
 585     @SupportedOptions("expectedEnclosedElements")
 586     public static final class ListRequires extends AbstractProcessor {
 587 
 588         private int round;
 589 
 590         @Override
 591         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
 592             if (round++ == 0) {
 593                 ModuleElement compileE = processingEnv.getElementUtils().getModuleElement("compile");
 594                 ModuleElement testE = ElementFilter.exportsIn(compileE.getDirectives()).get(0).getTargetModules().get(0);
 595 
 596                 System.out.println("from directives:");
 597                 for (RequiresDirective rd : ElementFilter.requiresIn(testE.getDirectives())) {
 598                     System.out.println(rd.getDependency().getSimpleName());
 599                 }
 600 
 601                 System.out.println("from requires:");
 602                 for (RequiresDirective rd : ((ModuleSymbol) testE).requires) {
 603                     System.out.println(rd.getDependency().getSimpleName());
 604                 }
 605             }
 606 
 607             return false;
 608         }
 609 
 610         @Override
 611         public SourceVersion getSupportedSourceVersion() {
 612             return SourceVersion.latest();
 613         }
 614 
 615     }
 616 
 617     @Test
 618     public void testOnDemandCompletionModuleInfoJava(Path base) throws Exception {
 619         Path src = base.resolve("src");
 620         Path src_m1 = src.resolve("m1x");
 621         tb.writeJavaFiles(src_m1,
 622                           "@Deprecated module m1x { }");
 623         Path src_m2 = src.resolve("m2x");
 624         tb.writeJavaFiles(src_m2,
 625                           "module m2x { requires m1x; }");
 626         Path src_m3 = src.resolve("m3x");
 627         tb.writeJavaFiles(src_m3,
 628                           "module m3x { requires m2x; requires m1x; }");
 629         Path classes = base.resolve("classes");
 630         tb.createDirectories(classes);
 631 
 632         List<String> log;
 633         List<String> expected;
 634 
 635         log = new JavacTask(tb)
 636                 .options("--module-source-path", src.toString())
 637                 .outdir(classes)
 638                 .files(findJavaFiles(src_m1))
 639                 .run()
 640                 .writeAll()
 641                 .getOutputLines(Task.OutputKind.DIRECT);
 642 
 643         expected = Arrays.asList("");
 644 
 645         if (!expected.equals(log)) {
 646             throw new IllegalStateException(log.toString());
 647         }
 648 
 649         log = new JavacTask(tb)
 650                 .options("--module-source-path", src.toString(),
 651                          "-XDrawDiagnostics",
 652                          "-Xlint:deprecation")
 653                 .outdir(classes)
 654                 .files(findJavaFiles(src_m3))
 655                 .run()
 656                 .writeAll()
 657                 .getOutputLines(Task.OutputKind.DIRECT);
 658 
 659         expected = Arrays.asList(
 660                 "module-info.java:1:23: compiler.warn.has.been.deprecated.module: m1x",
 661                 "module-info.java:1:37: compiler.warn.has.been.deprecated.module: m1x",
 662                 "2 warnings"
 663         );
 664 
 665         if (!expected.equals(log)) {
 666             throw new IllegalStateException(log.toString());
 667         }
 668     }
 669 
 670     @Test
 671     public void testUnnamedPackage(Path base) throws Exception {
 672         List<String> out;
 673         List<String> expected;
 674 
 675         //-source 8:
 676         Path src8 = base.resolve("src8");
 677         Files.createDirectories(src8);
 678         tb.writeJavaFiles(src8,
 679                           "package test; public class Test {}");
 680         Path classes = base.resolve("classes");
 681         tb.createDirectories(classes);
 682 
 683         out = new JavacTask(tb)
 684                 .options("--source-path", src8.toString(),
 685                          "-processor", UnnamedPackageProcessor.class.getName(),
 686                          "-source", "8")
 687                 .outdir(classes)
 688                 .files(findJavaFiles(src8))
 689                 .run()
 690                 .writeAll()
 691                 .getOutputLines(OutputKind.STDOUT);
 692 
 693         expected = Arrays.asList("noModule");
 694 
 695         if (!expected.equals(out)) {
 696             throw new AssertionError("Unexpected output: " + out);
 697         }
 698 
 699         //-source 9, unnamed:
 700         Path srcUnnamed = base.resolve("srcUnnamed");
 701         Files.createDirectories(srcUnnamed);
 702         tb.writeJavaFiles(srcUnnamed,
 703                           "public class Test {}");
 704         Path classesUnnamed = base.resolve("classesUnnamed");
 705         tb.createDirectories(classesUnnamed);
 706 
 707         out = new JavacTask(tb)
 708                 .options("--source-path", srcUnnamed.toString(),
 709                          "-processor", UnnamedPackageProcessor.class.getName())
 710                 .outdir(classesUnnamed)
 711                 .files(findJavaFiles(srcUnnamed))
 712                 .run()
 713                 .writeAll()
 714                 .getOutputLines(OutputKind.STDOUT);
 715 
 716         expected = Arrays.asList("unnamedModule");
 717 
 718         if (!expected.equals(out)) {
 719             throw new AssertionError("Unexpected output: " + out);
 720         }
 721 
 722         //-source 9, named:
 723         Path srcNamed = base.resolve("srcNamed");
 724         Files.createDirectories(srcNamed);
 725         tb.writeJavaFiles(srcNamed,
 726                           "module m {}",
 727                           "public class Test {}");
 728         Path classesNamed = base.resolve("classesNamed");
 729         tb.createDirectories(classesNamed);
 730 
 731         out = new JavacTask(tb)
 732                 .options("--source-path", srcNamed.toString(),
 733                          "-classpath", "",
 734                          "-processorpath", System.getProperty("test.class.path"),
 735                          "-processor", UnnamedPackageProcessor.class.getName())
 736                 .outdir(classesNamed)
 737                 .files(findJavaFiles(srcNamed))
 738                 .run()
 739                 .writeAll()
 740                 .getOutputLines(OutputKind.STDOUT);
 741 
 742         expected = Arrays.asList("m");
 743 
 744         if (!expected.equals(out)) {
 745             throw new AssertionError("Unexpected output: " + out);
 746         }
 747 
 748         //-source 9, conflict:
 749         Path srcNamed2 = base.resolve("srcNamed2");
 750         Path srcNamed2m1 = srcNamed2.resolve("m1x");
 751         Files.createDirectories(srcNamed2m1);
 752         tb.writeJavaFiles(srcNamed2m1,
 753                           "module m1x {}",
 754                           "public class Test {}");
 755         Path srcNamed2m2 = srcNamed2.resolve("m2x");
 756         Files.createDirectories(srcNamed2m2);
 757         tb.writeJavaFiles(srcNamed2m2,
 758                           "module m2x {}",
 759                           "public class Test {}");
 760         Path classesNamed2 = base.resolve("classesNamed2");
 761         tb.createDirectories(classesNamed2);
 762 
 763         out = new JavacTask(tb)
 764                 .options("--module-source-path", srcNamed2.toString(),
 765                          "-classpath", "",
 766                          "-processorpath", System.getProperty("test.class.path"),
 767                          "-processor", UnnamedPackageProcessor.class.getName(),
 768                          "-XDshould-stop.ifError=FLOW")
 769                 .outdir(classesNamed2)
 770                 .files(findJavaFiles(srcNamed2))
 771                 .run(Expect.FAIL)
 772                 .writeAll()
 773                 .getOutputLines(OutputKind.STDOUT);
 774 
 775         expected = Arrays.asList("null",
 776                                  "m1x: true",
 777                                  "m2x: true");
 778 
 779         if (!expected.equals(out)) {
 780             throw new AssertionError("Unexpected output: " + out);
 781         }
 782     }
 783 
 784     @SupportedAnnotationTypes("*")
 785     public static final class UnnamedPackageProcessor extends AbstractProcessor {
 786 
 787         int round = 0;
 788 
 789         @Override
 790         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
 791             if (round++ != 0)
 792                 return false;
 793 
 794             Elements elements = processingEnv.getElementUtils();
 795             PackageElement pe = elements.getPackageElement("");
 796 
 797             if (pe == null) {
 798                 System.out.println("null");
 799             } else {
 800                 ModuleElement mod = (ModuleElement) pe.getEnclosingElement();
 801                 if (mod == null) {
 802                     System.out.println("noModule");
 803                 } else if (mod.isUnnamed()) {
 804                     System.out.println("unnamedModule");
 805                 } else {
 806                     System.out.println(mod);
 807                 }
 808             }
 809 
 810             ModuleElement m1x = elements.getModuleElement("m1x");
 811             ModuleElement m2x = elements.getModuleElement("m2x");
 812 
 813             if (m1x != null && m2x != null) {
 814                 System.out.println("m1x: " + (elements.getPackageElement(m1x, "") != null));
 815                 System.out.println("m2x: " + (elements.getPackageElement(m2x, "") != null));
 816             }
 817 
 818             return false;
 819         }
 820 
 821     }
 822 
 823     @Test
 824     public void testEmptyInExportedPackage(Path base) throws Exception {
 825         Path src = base.resolve("src");
 826         Path m = src.resolve("m");
 827         tb.writeJavaFiles(m,
 828                           "module m { exports api; }");
 829         Path apiFile = m.resolve("api").resolve("Api.java");
 830         Files.createDirectories(apiFile.getParent());
 831         try (BufferedWriter w = Files.newBufferedWriter(apiFile)) {
 832             w.write("//no package decl");
 833         }
 834         Path classes = base.resolve("classes");
 835         tb.createDirectories(classes);
 836 
 837         List<String> log;
 838         List<String> expected =
 839                 Arrays.asList("module-info.java:1:20: compiler.err.package.empty.or.not.found: api",
 840                               "1 error");
 841 
 842         System.err.println("file explicitly specified:");
 843 
 844         log = new JavacTask(tb)
 845             .options("-XDrawDiagnostics",
 846                      "--module-source-path", src.toString())
 847             .outdir(classes)
 848             .files(findJavaFiles(src))
 849             .run(Task.Expect.FAIL)
 850             .writeAll()
 851             .getOutputLines(Task.OutputKind.DIRECT);
 852 
 853         if (!expected.equals(log))
 854             throw new Exception("expected output not found: " + log);
 855 
 856         System.err.println("file not specified:");
 857 
 858         tb.cleanDirectory(classes);
 859 
 860         log = new JavacTask(tb)
 861             .options("-XDrawDiagnostics",
 862                      "--module-source-path", src.toString())
 863             .outdir(classes)
 864             .files(findJavaFiles(m.resolve("module-info.java")))
 865             .run(Task.Expect.FAIL)
 866             .writeAll()
 867             .getOutputLines(Task.OutputKind.DIRECT);
 868 
 869         if (!expected.equals(log))
 870             throw new Exception("expected output not found: " + log);
 871     }
 872 
 873     @Test
 874     public void testJustPackageInExportedPackage(Path base) throws Exception {
 875         Path src = base.resolve("src");
 876         Path m = src.resolve("m");
 877         tb.writeJavaFiles(m,
 878                           "module m { exports api; }");
 879         Path apiFile = m.resolve("api").resolve("Api.java");
 880         Files.createDirectories(apiFile.getParent());
 881         try (BufferedWriter w = Files.newBufferedWriter(apiFile)) {
 882             w.write("package api;");
 883         }
 884         Path classes = base.resolve("classes");
 885         tb.createDirectories(classes);
 886 
 887         System.err.println("file explicitly specified:");
 888 
 889         new JavacTask(tb)
 890             .options("-XDrawDiagnostics",
 891                      "--module-source-path", src.toString())
 892             .outdir(classes)
 893             .files(findJavaFiles(src))
 894             .run()
 895             .writeAll();
 896 
 897         System.err.println("file not specified:");
 898 
 899         tb.cleanDirectory(classes);
 900 
 901         new JavacTask(tb)
 902             .options("-XDrawDiagnostics",
 903                      "--module-source-path", src.toString())
 904             .outdir(classes)
 905             .files(findJavaFiles(m.resolve("module-info.java")))
 906             .run()
 907             .writeAll();
 908     }
 909 
 910     @Test
 911     public void testWrongPackageInExportedPackage(Path base) throws Exception {
 912         Path src = base.resolve("src");
 913         Path m = src.resolve("m");
 914         tb.writeJavaFiles(m,
 915                           "module m { exports api; }");
 916         Path apiFile = m.resolve("api").resolve("Api.java");
 917         Files.createDirectories(apiFile.getParent());
 918         try (BufferedWriter w = Files.newBufferedWriter(apiFile)) {
 919             w.write("package impl; public class Api { }");
 920         }
 921         Path classes = base.resolve("classes");
 922         tb.createDirectories(classes);
 923 
 924         List<String> log;
 925 
 926         List<String> expected =
 927                 Arrays.asList("module-info.java:1:20: compiler.err.package.empty.or.not.found: api",
 928                               "1 error");
 929 
 930         System.err.println("file explicitly specified:");
 931 
 932         log = new JavacTask(tb)
 933                 .options("-XDrawDiagnostics",
 934                          "--module-source-path", src.toString())
 935                 .outdir(classes)
 936                 .files(findJavaFiles(src))
 937                 .run(Task.Expect.FAIL)
 938                 .writeAll()
 939                 .getOutputLines(Task.OutputKind.DIRECT);
 940 
 941         if (!expected.equals(log))
 942             throw new Exception("expected output not found: " + log);
 943 
 944         System.err.println("file not specified:");
 945 
 946         tb.cleanDirectory(classes);
 947 
 948         log = new JavacTask(tb)
 949                 .options("-XDrawDiagnostics",
 950                          "--module-source-path", src.toString())
 951                 .outdir(classes)
 952                 .files(findJavaFiles(m.resolve("module-info.java")))
 953                 .run(Task.Expect.FAIL)
 954                 .writeAll()
 955                 .getOutputLines(Task.OutputKind.DIRECT);
 956 
 957         if (!expected.equals(log))
 958             throw new Exception("expected output not found: " + log);
 959     }
 960 
 961     @Test
 962     public void testDependOnUnnamedAccessibility(Path base) throws Exception {
 963         Path unnamedSrc = base.resolve("unnamed-src");
 964         tb.writeJavaFiles(unnamedSrc,
 965                           "package p1; public class First { public static p2.Second get() { return null; } }",
 966                           "package p2; public class Second { public void test() { } }");
 967         Path unnamedClasses = base.resolve("unnamed-classes");
 968         tb.createDirectories(unnamedClasses);
 969 
 970         System.err.println("compiling unnamed sources:");
 971 
 972         new JavacTask(tb)
 973                 .outdir(unnamedClasses)
 974                 .files(findJavaFiles(unnamedSrc))
 975                 .run()
 976                 .writeAll();
 977 
 978         //test sources:
 979         Path src = base.resolve("src");
 980         Path m = src.resolve("m");
 981         tb.writeJavaFiles(m,
 982                           "module m { }",
 983                           "package p; public class Test { { p1.First.get().test(); } }");
 984         Path classes = base.resolve("classes");
 985         tb.createDirectories(classes);
 986 
 987         System.err.println("compiling test module:");
 988 
 989         new JavacTask(tb)
 990             .options("-classpath", unnamedClasses.toString(),
 991                      "--add-reads", "m=ALL-UNNAMED")
 992             .outdir(classes)
 993             .files(findJavaFiles(src))
 994             .run()
 995             .writeAll();
 996     }
 997 
 998 }