EdgeCases.java revision 3923:923a093b4bd8
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
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
39import java.io.Writer;
40import java.nio.file.Files;
41import java.nio.file.Path;
42import java.nio.file.Paths;
43import java.util.Arrays;
44import java.util.HashSet;
45import java.util.List;
46import java.util.Objects;
47import java.util.Set;
48
49import javax.annotation.processing.AbstractProcessor;
50import javax.annotation.processing.RoundEnvironment;
51import javax.annotation.processing.SupportedAnnotationTypes;
52import javax.annotation.processing.SupportedOptions;
53import javax.lang.model.SourceVersion;
54import javax.lang.model.element.Element;
55import javax.lang.model.element.ModuleElement;
56import javax.lang.model.element.ModuleElement.RequiresDirective;
57import javax.lang.model.element.PackageElement;
58import javax.lang.model.element.TypeElement;
59import javax.lang.model.util.ElementFilter;
60import javax.lang.model.util.Elements;
61import javax.tools.JavaCompiler;
62import javax.tools.JavaFileObject;
63import javax.tools.StandardJavaFileManager;
64import javax.tools.ToolProvider;
65
66import com.sun.source.tree.CompilationUnitTree;
67//import com.sun.source.util.JavacTask; // conflicts with toolbox.JavacTask
68import com.sun.tools.javac.api.JavacTaskImpl;
69import com.sun.tools.javac.code.Symbol.ModuleSymbol;
70import com.sun.tools.javac.code.Symbol.PackageSymbol;
71import com.sun.tools.javac.code.Symtab;
72import com.sun.tools.javac.processing.JavacProcessingEnvironment;
73import com.sun.tools.javac.util.Context;
74
75import toolbox.JarTask;
76import toolbox.JavacTask;
77import toolbox.Task;
78import toolbox.Task.Expect;
79import toolbox.Task.OutputKind;
80
81public class EdgeCases extends ModuleTestBase {
82
83    public static void main(String... args) throws Exception {
84        new EdgeCases().runTests();
85    }
86
87    @Test
88    public void testAddExportUndefinedModule(Path base) throws Exception {
89        Path src = base.resolve("src");
90        tb.writeJavaFiles(src, "package test; import undefPackage.Any; public class Test {}");
91        Path classes = base.resolve("classes");
92        tb.createDirectories(classes);
93
94        List<String> log = new JavacTask(tb)
95                .options("--add-exports", "undefModule/undefPackage=ALL-UNNAMED",
96                         "-XDrawDiagnostics")
97                .outdir(classes)
98                .files(findJavaFiles(src))
99                .run(Task.Expect.FAIL)
100                .writeAll()
101                .getOutputLines(Task.OutputKind.DIRECT);
102
103        List<String> expected = Arrays.asList("- compiler.warn.module.for.option.not.found: --add-exports, undefModule",
104                                              "Test.java:1:34: compiler.err.doesnt.exist: undefPackage",
105                                              "1 error", "1 warning");
106
107        if (!expected.equals(log))
108            throw new Exception("expected output not found: " + log);
109    }
110
111    @Test
112    public void testModuleSymbolOutterMostClass(Path base) throws Exception {
113        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
114        try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
115            Path moduleSrc = base.resolve("module-src");
116            Path m1 = moduleSrc.resolve("m1x");
117
118            tb.writeJavaFiles(m1, "module m1x { }");
119
120            Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(findJavaFiles(moduleSrc));
121            com.sun.source.util.JavacTask task =
122                (com.sun.source.util.JavacTask) compiler.getTask(null, fm, null, null, null, files);
123
124            task.analyze();
125
126            ModuleSymbol msym = (ModuleSymbol) task.getElements().getModuleElement("m1x");
127
128            msym.outermostClass();
129        }
130    }
131
132    @Test
133    public void testParseEnterAnalyze(Path base) throws Exception {
134        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
135        try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
136            Path moduleSrc = base.resolve("module-src");
137            Path m1 = moduleSrc.resolve("m1x");
138
139            tb.writeJavaFiles(m1, "module m1x { }",
140                                  "package p;",
141                                  "package p; class T { }");
142
143            Path classes = base.resolve("classes");
144            Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(findJavaFiles(moduleSrc));
145            List<String> options = Arrays.asList("-d", classes.toString(), "-Xpkginfo:always");
146            JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, fm, null, options, null, files);
147
148            Iterable<? extends CompilationUnitTree> parsed = task.parse();
149            Iterable<? extends Element> entered = task.enter(parsed);
150            Iterable<? extends Element> analyzed = task.analyze(entered);
151            Iterable<? extends JavaFileObject> generatedFiles = task.generate(analyzed);
152
153            Set<String> generated = new HashSet<>();
154
155            for (JavaFileObject jfo : generatedFiles) {
156                generated.add(jfo.getName());
157            }
158
159            Set<String> expected = new HashSet<>(
160                    Arrays.asList(Paths.get("testParseEnterAnalyze", "classes", "p", "package-info.class").toString(),
161                                  Paths.get("testParseEnterAnalyze", "classes", "module-info.class").toString(),
162                                  Paths.get("testParseEnterAnalyze", "classes", "p", "T.class").toString())
163            );
164
165            if (!Objects.equals(expected, generated))
166                throw new AssertionError("Incorrect generated files: " + generated);
167        }
168    }
169
170    @Test
171    public void testModuleImplicitModuleBoundaries(Path base) throws Exception {
172        Path src = base.resolve("src");
173        Path src_m1 = src.resolve("m1x");
174        tb.writeJavaFiles(src_m1,
175                          "module m1x { exports api1; }",
176                          "package api1; public class Api1 { public void call() { } }");
177        Path src_m2 = src.resolve("m2x");
178        tb.writeJavaFiles(src_m2,
179                          "module m2x { requires m1x; exports api2; }",
180                          "package api2; public class Api2 { public static api1.Api1 get() { return null; } }");
181        Path src_m3 = src.resolve("m3x");
182        tb.writeJavaFiles(src_m3,
183                          "module m3x { requires m2x; }",
184                          "package test; public class Test { { api2.Api2.get().call(); api2.Api2.get().toString(); } }");
185        Path classes = base.resolve("classes");
186        tb.createDirectories(classes);
187
188        String log = new JavacTask(tb)
189                .options("-XDrawDiagnostics",
190                         "--module-source-path", src.toString())
191                .outdir(classes)
192                .files(findJavaFiles(src))
193                .run(Task.Expect.FAIL)
194                .writeAll()
195                .getOutput(Task.OutputKind.DIRECT);
196
197        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)") ||
198            !log.contains("Test.java:1:76: compiler.err.not.def.access.class.intf.cant.access: toString(), java.lang.Object"))
199            throw new Exception("expected output not found");
200    }
201
202    @Test
203    public void testAssignClassToAutomaticModule(Path base) throws Exception {
204        //check that if a ClassSymbol belongs to an automatic module, it is properly assigned and not
205        //duplicated when being accessed through a classfile.
206        Path automaticSrc = base.resolve("automaticSrc");
207        tb.writeJavaFiles(automaticSrc, "package api1; public class Api1 {}");
208        Path automaticClasses = base.resolve("automaticClasses");
209        tb.createDirectories(automaticClasses);
210
211        String automaticLog = new JavacTask(tb)
212                                .outdir(automaticClasses)
213                                .files(findJavaFiles(automaticSrc))
214                                .run()
215                                .writeAll()
216                                .getOutput(Task.OutputKind.DIRECT);
217
218        if (!automaticLog.isEmpty())
219            throw new Exception("expected output not found: " + automaticLog);
220
221        Path modulePath = base.resolve("module-path");
222
223        Files.createDirectories(modulePath);
224
225        Path automaticJar = modulePath.resolve("a-1.0.jar");
226
227        new JarTask(tb, automaticJar)
228          .baseDir(automaticClasses)
229          .files("api1/Api1.class")
230          .run();
231
232        Path src = base.resolve("src");
233        Path src_m2 = src.resolve("m2x");
234        tb.writeJavaFiles(src_m2,
235                          "module m2x { requires a; exports api2; }",
236                          "package api2; public class Api2 { public static api1.Api1 get() { return null; } }");
237        Path src_m3 = src.resolve("m3x");
238        tb.writeJavaFiles(src_m3,
239                          "module m3x { requires a; requires m2x; }",
240                          "package test; public class Test { { api2.Api2.get(); api1.Api1 a1; } }");
241        Path classes = base.resolve("classes");
242        tb.createDirectories(classes);
243
244        new JavacTask(tb)
245                .options("--module-path", modulePath.toString(),
246                         "--module-source-path", src.toString())
247                .outdir(classes)
248                .files(findJavaFiles(src_m2))
249                .run()
250                .writeAll();
251
252        new JavacTask(tb)
253                .options("--module-path", modulePath.toString(),
254                         "--module-source-path", src.toString())
255                .outdir(classes)
256                .files(findJavaFiles(src_m3))
257                .run()
258                .writeAll();
259    }
260
261    @Test
262    public void testEmptyImplicitModuleInfo(Path base) throws Exception {
263        Path src = base.resolve("src");
264        Path src_m1 = src.resolve("m1x");
265        Files.createDirectories(src_m1);
266        try (Writer w = Files.newBufferedWriter(src_m1.resolve("module-info.java"))) {}
267        tb.writeJavaFiles(src_m1,
268                          "package test; public class Test {}");
269        Path classes = base.resolve("classes");
270        tb.createDirectories(classes);
271
272        new JavacTask(tb)
273                .options("--source-path", src_m1.toString(),
274                         "-XDrawDiagnostics")
275                .outdir(classes)
276                .files(findJavaFiles(src_m1.resolve("test")))
277                .run(Task.Expect.FAIL)
278                .writeAll();
279
280        tb.writeJavaFiles(src_m1,
281                          "module m1x {}");
282
283        new JavacTask(tb)
284                .options("--source-path", src_m1.toString())
285                .outdir(classes)
286                .files(findJavaFiles(src_m1.resolve("test")))
287                .run()
288                .writeAll();
289
290    }
291
292    @Test
293    public void testClassPackageClash(Path base) throws Exception {
294        Path src = base.resolve("src");
295        Path src_m1 = src.resolve("m1x");
296        tb.writeJavaFiles(src_m1,
297                          "module m1x { exports test.m1x; }",
298                          "package test.m1x;\n" +
299                          "public class Test {}\n");
300        Path src_m2 = src.resolve("m2x");
301        tb.writeJavaFiles(src_m2,
302                          "module m2x { requires m1x; }",
303                          "package test;\n" +
304                          "public class m1x {}\n");
305        Path classes = base.resolve("classes");
306        tb.createDirectories(classes);
307
308        List<String> log = new JavacTask(tb)
309                .options("--module-source-path", src.toString(),
310                         "-XDrawDiagnostics")
311                .outdir(classes)
312                .files(findJavaFiles(src))
313                .run(Task.Expect.FAIL)
314                .writeAll()
315                .getOutputLines(Task.OutputKind.DIRECT);
316
317        List<String> expected = Arrays.asList(
318            "m1x.java:2:8: compiler.err.clash.with.pkg.of.same.name: kindname.class, test.m1x",
319            "1 error"
320        );
321
322        if (!expected.equals(log)) {
323            throw new IllegalStateException(log.toString());
324        }
325    }
326
327    @Test
328    public void testImplicitJavaBase(Path base) throws Exception {
329        Path src = base.resolve("src");
330        Path src_java_base = src.resolve("java.base");
331        Files.createDirectories(src_java_base);
332        tb.writeJavaFiles(src_java_base, "module java.base { exports java.lang; }");
333        tb.writeJavaFiles(src_java_base,
334                          "package java.lang; public class Object {}");
335        Path classes = base.resolve("classes");
336        tb.createDirectories(classes);
337
338        //module-info from source:
339        new JavacTask(tb)
340            .options("-sourcepath", src_java_base.toString())
341            .outdir(classes)
342            .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
343            .run()
344            .writeAll();
345
346        //module-info from class:
347        if (!Files.exists(classes.resolve("module-info.class"))) {
348            throw new AssertionError("module-info.class not created!");
349        }
350
351        new JavacTask(tb)
352            .outdir(classes)
353            .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
354            .run()
355            .writeAll();
356
357        //broken module-info.class:
358        Files.newOutputStream(classes.resolve("module-info.class")).close();
359
360        List<String> log = new JavacTask(tb)
361            .options("-XDrawDiagnostics")
362            .outdir(classes)
363            .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
364            .run(Expect.FAIL)
365            .writeAll()
366            .getOutputLines(OutputKind.DIRECT);
367
368        List<String> expected = Arrays.asList(
369                "- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.illegal.start.of.class.file))",
370                "1 error");
371
372        if (!expected.equals(log)) {
373            throw new AssertionError("Unexpected output: " + log);
374        }
375
376        //broken module-info.java:
377        Files.delete(classes.resolve("module-info.class"));
378
379        try (Writer out = Files.newBufferedWriter(src_java_base.resolve("module-info.java"))) {
380            out.write("class Broken {}");
381        }
382
383        log = new JavacTask(tb)
384            .options("-sourcepath", src_java_base.toString(),
385                                "-XDrawDiagnostics")
386            .outdir(classes)
387            .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java")))
388            .run(Expect.FAIL)
389            .writeAll()
390            .getOutputLines(OutputKind.DIRECT);
391
392        expected = Arrays.asList("X");
393
394        if (expected.equals(log)) {
395            throw new AssertionError("Unexpected output: " + log);
396        }
397    }
398
399    @Test
400    public void testModuleInfoNameMismatchSource(Path base) throws Exception {
401        Path src = base.resolve("src");
402        Path m1 = src.resolve("m1x");
403        Files.createDirectories(m1);
404        tb.writeJavaFiles(m1, "module other { }",
405                              "package test; public class Test {}");
406        Path classes = base.resolve("classes");
407        tb.createDirectories(classes);
408
409        List<String> log = new JavacTask(tb)
410            .options("--module-source-path", src.toString(),
411                     "-XDrawDiagnostics")
412            .outdir(classes)
413            .files(findJavaFiles(m1.resolve("test").resolve("Test.java")))
414            .run(Expect.FAIL)
415            .writeAll()
416            .getOutputLines(OutputKind.DIRECT);
417
418        List<String> expected = Arrays.asList(
419                "module-info.java:1:1: compiler.err.module.name.mismatch: other, m1x",
420                "- compiler.err.cant.access: m1x.module-info, (compiler.misc.cant.resolve.modules)",
421                "2 errors");
422
423        if (!expected.equals(log)) {
424            throw new AssertionError("Unexpected output: " + log);
425        }
426    }
427
428    @Test
429    public void testModuleInfoNameMismatchClass(Path base) throws Exception {
430        Path src = base.resolve("src");
431        Files.createDirectories(src);
432        tb.writeJavaFiles(src, "module other { }",
433                               "package test; public class Test {}");
434        Path classes = base.resolve("classes");
435        Path m1Classes = classes.resolve("m1x");
436        tb.createDirectories(m1Classes);
437
438        new JavacTask(tb)
439            .outdir(m1Classes)
440            .files(findJavaFiles(src))
441            .run()
442            .writeAll()
443            .getOutputLines(OutputKind.DIRECT);
444
445        Path src2 = base.resolve("src2");
446        Files.createDirectories(src2);
447        tb.writeJavaFiles(src2, "module use { requires m1x; }");
448
449        Path classes2 = base.resolve("classes2");
450        tb.createDirectories(classes2);
451
452        List<String> log = new JavacTask(tb)
453            .options("--module-path", classes.toString(),
454                     "-XDrawDiagnostics")
455            .outdir(classes2)
456            .files(findJavaFiles(src2))
457            .run(Expect.FAIL)
458            .writeAll()
459            .getOutputLines(OutputKind.DIRECT);
460
461        List<String> expected = Arrays.asList(
462                "- compiler.err.cant.access: m1x.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.module.name.mismatch: other, m1x))",
463                "1 error");
464
465        if (!expected.equals(log)) {
466            throw new AssertionError("Unexpected output: " + log);
467        }
468    }
469
470    @Test
471    public void testGetDirectivesComplete(Path base) throws Exception {
472        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
473        JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, null, null, null, null, null);
474        Symtab syms = Symtab.instance(task.getContext());
475
476        syms.java_base.getDirectives();
477    }
478
479    @Test
480    public void testPackageInModuleInfo(Path base) throws Exception {
481        Path src = base.resolve("src");
482        Files.createDirectories(src);
483        tb.writeJavaFiles(src, "package p; module foo { }");
484        Path classes = base.resolve("classes");
485        tb.createDirectories(classes);
486
487        List<String> log = new JavacTask(tb)
488            .options("-XDrawDiagnostics", "-XDshould-stop.ifError=FLOW")
489            .outdir(classes)
490            .files(findJavaFiles(src))
491            .run(Expect.FAIL)
492            .writeAll()
493            .getOutputLines(OutputKind.DIRECT);
494
495        List<String> expected = Arrays.asList(
496                "module-info.java:1:1: compiler.err.no.pkg.in.module-info.java",
497                "1 error");
498
499        if (!expected.equals(log)) {
500            throw new AssertionError("Unexpected output: " + log);
501        }
502    }
503
504    @Test
505    public void testInvisibleClassVisiblePackageClash(Path base) throws Exception {
506        Path src = base.resolve("src");
507        Path src_m1 = src.resolve("m1x");
508        tb.writeJavaFiles(src_m1,
509                          "module m1x { }",
510                          "package m1x;\n" +
511                          "import m1x.a.*; public class Test { A a; }\n",
512                          "package m1x.a;\n" +
513                          "public class A { }\n");
514        Path src_m2 = src.resolve("m2x");
515        tb.writeJavaFiles(src_m2,
516                          "module m2x { }",
517                          "package m1x;\n" +
518                          "public class a { public static class A { } }\n");
519        Path classes = base.resolve("classes");
520        tb.createDirectories(classes);
521
522        new JavacTask(tb)
523            .options("--module-source-path", src.toString(),
524                     "-XDrawDiagnostics")
525            .outdir(classes)
526            .files(findJavaFiles(src))
527            .run()
528            .writeAll();
529    }
530
531    @Test
532    public void testStripUnknownRequired(Path base) throws Exception {
533        Path src = base.resolve("src");
534        Path src_m1 = src.resolve("m1x");
535        tb.writeJavaFiles(src_m1,
536                          "module m1x { }");
537        Path src_m2 = src.resolve("m2x");
538        tb.writeJavaFiles(src_m2,
539                          "module m2x { }");
540        Path src_m3 = src.resolve("m3x");
541        tb.writeJavaFiles(src_m3,
542                          "module m3x { }");
543        Path src_m4 = src.resolve("m4x");
544        tb.writeJavaFiles(src_m4,
545                          "module m4x { }");
546        Path src_test = src.resolve("test");
547        tb.writeJavaFiles(src_test,
548                          "module test { requires m1x; requires m2x; requires java.base; requires m3x; requires m4x; }");
549        Path src_compile = src.resolve("compile");
550        tb.writeJavaFiles(src_compile,
551                          "module compile { exports p to test; }",
552                          "package p; public class Test { }");
553        Path classes = base.resolve("classes");
554        tb.createDirectories(classes);
555
556        List<String> log = new JavacTask(tb)
557                .options("-processor", ListRequires.class.getName(),
558                         "--module-source-path", src.toString(),
559                         "--limit-modules", "compile",
560                         "-XDaccessInternalAPI=true")
561                .outdir(classes)
562                .files(findJavaFiles(src_compile))
563                .run(Expect.FAIL)
564                .writeAll()
565                .getOutputLines(Task.OutputKind.STDOUT);
566
567        List<String> expected = Arrays.asList(
568                "from directives:",
569                "java.base",
570                "from requires:",
571                "java.base"
572        );
573        if (!Objects.equals(log, expected))
574            throw new AssertionError("Unexpected output: " + log);
575    }
576
577    @SupportedAnnotationTypes("*")
578    @SupportedOptions("expectedEnclosedElements")
579    public static final class ListRequires extends AbstractProcessor {
580
581        private int round;
582
583        @Override
584        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
585            if (round++ == 0) {
586                ModuleElement compileE = processingEnv.getElementUtils().getModuleElement("compile");
587                ModuleElement testE = ElementFilter.exportsIn(compileE.getDirectives()).get(0).getTargetModules().get(0);
588
589                System.out.println("from directives:");
590                for (RequiresDirective rd : ElementFilter.requiresIn(testE.getDirectives())) {
591                    System.out.println(rd.getDependency().getSimpleName());
592                }
593
594                System.out.println("from requires:");
595                for (RequiresDirective rd : ((ModuleSymbol) testE).requires) {
596                    System.out.println(rd.getDependency().getSimpleName());
597                }
598            }
599
600            return false;
601        }
602
603        @Override
604        public SourceVersion getSupportedSourceVersion() {
605            return SourceVersion.latest();
606        }
607
608    }
609
610    @Test
611    public void testOnDemandCompletionModuleInfoJava(Path base) throws Exception {
612        Path src = base.resolve("src");
613        Path src_m1 = src.resolve("m1x");
614        tb.writeJavaFiles(src_m1,
615                          "@Deprecated module m1x { }");
616        Path src_m2 = src.resolve("m2x");
617        tb.writeJavaFiles(src_m2,
618                          "module m2x { requires m1x; }");
619        Path src_m3 = src.resolve("m3x");
620        tb.writeJavaFiles(src_m3,
621                          "module m3x { requires m2x; requires m1x; }");
622        Path classes = base.resolve("classes");
623        tb.createDirectories(classes);
624
625        List<String> log;
626        List<String> expected;
627
628        log = new JavacTask(tb)
629                .options("--module-source-path", src.toString())
630                .outdir(classes)
631                .files(findJavaFiles(src_m1))
632                .run()
633                .writeAll()
634                .getOutputLines(Task.OutputKind.DIRECT);
635
636        expected = Arrays.asList("");
637
638        if (!expected.equals(log)) {
639            throw new IllegalStateException(log.toString());
640        }
641
642        log = new JavacTask(tb)
643                .options("--module-source-path", src.toString(),
644                         "-XDrawDiagnostics",
645                         "-Xlint:deprecation")
646                .outdir(classes)
647                .files(findJavaFiles(src_m3))
648                .run()
649                .writeAll()
650                .getOutputLines(Task.OutputKind.DIRECT);
651
652        expected = Arrays.asList(
653                "module-info.java:1:23: compiler.warn.has.been.deprecated.module: m1x",
654                "module-info.java:1:37: compiler.warn.has.been.deprecated.module: m1x",
655                "2 warnings"
656        );
657
658        if (!expected.equals(log)) {
659            throw new IllegalStateException(log.toString());
660        }
661    }
662
663    @Test
664    public void testUnnamedPackage(Path base) throws Exception {
665        List<String> out;
666        List<String> expected;
667
668        //-source 8:
669        Path src8 = base.resolve("src8");
670        Files.createDirectories(src8);
671        tb.writeJavaFiles(src8,
672                          "package test; public class Test {}");
673        Path classes = base.resolve("classes");
674        tb.createDirectories(classes);
675
676        out = new JavacTask(tb)
677                .options("--source-path", src8.toString(),
678                         "-processor", UnnamedPackageProcessor.class.getName(),
679                         "-source", "8")
680                .outdir(classes)
681                .files(findJavaFiles(src8))
682                .run()
683                .writeAll()
684                .getOutputLines(OutputKind.STDOUT);
685
686        expected = Arrays.asList("noModule");
687
688        if (!expected.equals(out)) {
689            throw new AssertionError("Unexpected output: " + out);
690        }
691
692        //-source 9, unnamed:
693        Path srcUnnamed = base.resolve("srcUnnamed");
694        Files.createDirectories(srcUnnamed);
695        tb.writeJavaFiles(srcUnnamed,
696                          "public class Test {}");
697        Path classesUnnamed = base.resolve("classesUnnamed");
698        tb.createDirectories(classesUnnamed);
699
700        out = new JavacTask(tb)
701                .options("--source-path", srcUnnamed.toString(),
702                         "-processor", UnnamedPackageProcessor.class.getName())
703                .outdir(classesUnnamed)
704                .files(findJavaFiles(srcUnnamed))
705                .run()
706                .writeAll()
707                .getOutputLines(OutputKind.STDOUT);
708
709        expected = Arrays.asList("unnamedModule");
710
711        if (!expected.equals(out)) {
712            throw new AssertionError("Unexpected output: " + out);
713        }
714
715        //-source 9, named:
716        Path srcNamed = base.resolve("srcNamed");
717        Files.createDirectories(srcNamed);
718        tb.writeJavaFiles(srcNamed,
719                          "module m {}",
720                          "public class Test {}");
721        Path classesNamed = base.resolve("classesNamed");
722        tb.createDirectories(classesNamed);
723
724        out = new JavacTask(tb)
725                .options("--source-path", srcNamed.toString(),
726                         "-classpath", "",
727                         "-processorpath", System.getProperty("test.class.path"),
728                         "-processor", UnnamedPackageProcessor.class.getName())
729                .outdir(classesNamed)
730                .files(findJavaFiles(srcNamed))
731                .run()
732                .writeAll()
733                .getOutputLines(OutputKind.STDOUT);
734
735        expected = Arrays.asList("m");
736
737        if (!expected.equals(out)) {
738            throw new AssertionError("Unexpected output: " + out);
739        }
740
741        //-source 9, conflict:
742        Path srcNamed2 = base.resolve("srcNamed2");
743        Path srcNamed2m1 = srcNamed2.resolve("m1x");
744        Files.createDirectories(srcNamed2m1);
745        tb.writeJavaFiles(srcNamed2m1,
746                          "module m1x {}",
747                          "public class Test {}");
748        Path srcNamed2m2 = srcNamed2.resolve("m2x");
749        Files.createDirectories(srcNamed2m2);
750        tb.writeJavaFiles(srcNamed2m2,
751                          "module m2x {}",
752                          "public class Test {}");
753        Path classesNamed2 = base.resolve("classesNamed2");
754        tb.createDirectories(classesNamed2);
755
756        out = new JavacTask(tb)
757                .options("--module-source-path", srcNamed2.toString(),
758                         "-classpath", "",
759                         "-processorpath", System.getProperty("test.class.path"),
760                         "-processor", UnnamedPackageProcessor.class.getName(),
761                         "-XDshould-stop.ifError=FLOW")
762                .outdir(classesNamed2)
763                .files(findJavaFiles(srcNamed2))
764                .run(Expect.FAIL)
765                .writeAll()
766                .getOutputLines(OutputKind.STDOUT);
767
768        expected = Arrays.asList("null",
769                                 "m1x: true",
770                                 "m2x: true");
771
772        if (!expected.equals(out)) {
773            throw new AssertionError("Unexpected output: " + out);
774        }
775    }
776
777    @SupportedAnnotationTypes("*")
778    public static final class UnnamedPackageProcessor extends AbstractProcessor {
779
780        int round = 0;
781
782        @Override
783        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
784            if (round++ != 0)
785                return false;
786
787            Elements elements = processingEnv.getElementUtils();
788            PackageElement pe = elements.getPackageElement("");
789
790            if (pe == null) {
791                System.out.println("null");
792            } else {
793                ModuleElement mod = (ModuleElement) pe.getEnclosingElement();
794                if (mod == null) {
795                    System.out.println("noModule");
796                } else if (mod.isUnnamed()) {
797                    System.out.println("unnamedModule");
798                } else {
799                    System.out.println(mod);
800                }
801            }
802
803            ModuleElement m1x = elements.getModuleElement("m1x");
804            ModuleElement m2x = elements.getModuleElement("m2x");
805
806            if (m1x != null && m2x != null) {
807                System.out.println("m1x: " + (elements.getPackageElement(m1x, "") != null));
808                System.out.println("m2x: " + (elements.getPackageElement(m2x, "") != null));
809            }
810
811            return false;
812        }
813
814    }
815}
816