1 /*
2  * Copyright (c) 2015, 2018, 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  * @summary Test the --add-reads option
27  * @library /tools/lib
28  * @modules jdk.compiler/com.sun.tools.javac.api
29  *          jdk.compiler/com.sun.tools.javac.main
30  *          jdk.jdeps/com.sun.tools.javap
31  *          java.desktop
32  * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.JavapTask ModuleTestBase
33  * @run main AddReadsTest
34  */
35 
36 import java.nio.file.Files;
37 import java.nio.file.Path;
38 import java.util.Set;
39 
40 import javax.annotation.processing.AbstractProcessor;
41 import javax.annotation.processing.RoundEnvironment;
42 import javax.annotation.processing.SupportedAnnotationTypes;
43 import javax.lang.model.SourceVersion;
44 import javax.lang.model.element.ModuleElement;
45 import javax.lang.model.element.ModuleElement.RequiresDirective;
46 import javax.lang.model.element.TypeElement;
47 import javax.lang.model.util.ElementFilter;
48 
49 import toolbox.JarTask;
50 import toolbox.JavacTask;
51 import toolbox.JavapTask;
52 import toolbox.Task;
53 
54 public class AddReadsTest extends ModuleTestBase {
55 
main(String... args)56     public static void main(String... args) throws Exception {
57         new AddReadsTest().runTests();
58     }
59 
60     @Test
testAddReads(Path base)61     public void testAddReads(Path base) throws Exception {
62         Path src = base.resolve("src");
63         Path src_m1 = src.resolve("m1x");
64         tb.writeJavaFiles(src_m1,
65                           "module m1x { exports api; }",
66                           "package api; public class Api { }");
67         Path src_m2 = src.resolve("m2x");
68         tb.writeJavaFiles(src_m2,
69                           "module m2x { }",
70                           "package test; public class Test extends api.Api { }");
71         Path classes = base.resolve("classes");
72         tb.createDirectories(classes);
73 
74         String log = new JavacTask(tb)
75                 .options("-XDrawDiagnostics",
76                          "--module-source-path", src.toString())
77                 .outdir(classes)
78                 .files(findJavaFiles(src))
79                 .run(Task.Expect.FAIL)
80                 .writeAll()
81                 .getOutput(Task.OutputKind.DIRECT);
82 
83         checkOutputContains(log,
84             "Test.java:1:41: compiler.err.package.not.visible: api, (compiler.misc.not.def.access.does.not.read: m2x, api, m1x)");
85 
86         //test add dependencies:
87         new JavacTask(tb)
88                 .options("--add-reads", "m2x=m1x",
89                          "--module-source-path", src.toString(),
90                          "-processor", VerifyRequires.class.getName())
91                 .outdir(classes)
92                 .files(findJavaFiles(src))
93                 .run()
94                 .writeAll();
95 
96         String decompiled = new JavapTask(tb)
97                 .options("-verbose",
98                         classes.resolve("m2x").resolve("module-info.class").toString())
99                 .run()
100                 .getOutput(Task.OutputKind.DIRECT);
101 
102         if (decompiled.contains("m1x")) {
103             throw new Exception("Incorrectly refers to m1x module.");
104         }
105 
106         //cyclic dependencies OK when created through addReads:
107         new JavacTask(tb)
108                 .options("--add-reads", "m2x=m1x",
109                          "--add-reads", "m1x=m2x",
110                          "--module-source-path", src.toString())
111                 .outdir(classes)
112                 .files(findJavaFiles(src))
113                 .run()
114                 .writeAll();
115 
116         tb.writeJavaFiles(src_m2,
117                           "module m2x { requires m1x; }");
118 
119         new JavacTask(tb)
120                 .options("--add-reads", "m1x=m2x",
121                          "--module-source-path", src.toString())
122                 .outdir(classes)
123                 .files(findJavaFiles(src))
124                 .run()
125                 .writeAll();
126     }
127 
128     @SupportedAnnotationTypes("*")
129     public static final class VerifyRequires extends AbstractProcessor {
130 
131         @Override
process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)132         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
133             ModuleElement m2Module = processingEnv.getElementUtils().getModuleElement("m2x");
134             if (m2Module == null) {
135                 throw new AssertionError("Cannot find the m2x module!");
136             }
137             boolean foundM1 = false;
138             for (RequiresDirective rd : ElementFilter.requiresIn(m2Module.getDirectives())) {
139                 foundM1 |= rd.getDependency().getSimpleName().contentEquals("m1x");
140             }
141             if (!foundM1) {
142                 throw new AssertionError("Cannot find the dependency on m1x module!");
143             }
144             return false;
145         }
146 
147         @Override
getSupportedSourceVersion()148         public SourceVersion getSupportedSourceVersion() {
149             return SourceVersion.latest();
150         }
151 
152     }
153 
154     @Test
testAddReadsUnnamedModule(Path base)155     public void testAddReadsUnnamedModule(Path base) throws Exception {
156         Path jar = prepareTestJar(base);
157 
158         Path moduleSrc = base.resolve("module-src");
159         Path m1 = moduleSrc.resolve("m1x");
160 
161         Path classes = base.resolve("classes");
162 
163         Files.createDirectories(classes);
164 
165         tb.writeJavaFiles(m1,
166                           "module m1x { }",
167                           "package impl; public class Impl { api.Api api; }");
168 
169         new JavacTask(tb)
170           .options("--class-path", jar.toString(),
171                    "--add-reads", "m1x=ALL-UNNAMED",
172                    "-XDrawDiagnostics")
173           .outdir(classes)
174           .files(findJavaFiles(moduleSrc))
175           .run()
176           .writeAll();
177     }
178 
179     @Test
testAddReadsUnnamedModulePackageConflict(Path base)180     public void testAddReadsUnnamedModulePackageConflict(Path base) throws Exception {
181         Path jar = prepareTestJar(base);
182 
183         Path moduleSrc = base.resolve("module-src");
184         Path m1 = moduleSrc.resolve("m1x");
185 
186         Path classes = base.resolve("classes");
187 
188         Files.createDirectories(classes);
189 
190         tb.writeJavaFiles(m1,
191                           "module m1x { }",
192                           "package api; public class Api { public static void test() { } }",
193                           "package impl; public class Impl { { api.Api.test(); } }");
194 
195         new JavacTask(tb)
196           .options("--class-path", jar.toString(),
197                    "--module-source-path", moduleSrc.toString(),
198                    "--add-reads", "m1x=ALL-UNNAMED",
199                    "-XDrawDiagnostics")
200           .outdir(classes)
201           .files(m1.resolve("impl").resolve("Impl.java"))
202           .run()
203           .writeAll();
204     }
205 
206     @Test
testAddReadsUnnamedToJavaBase(Path base)207     public void testAddReadsUnnamedToJavaBase(Path base) throws Exception {
208         Path jar = prepareTestJar(base);
209         Path src = base.resolve("src");
210         Path classes = base.resolve("classes");
211 
212         Files.createDirectories(classes);
213 
214         tb.writeJavaFiles(src,
215                           "package impl; public class Impl { api.Api a; }");
216 
217         new JavacTask(tb)
218           .options("--class-path", jar.toString(),
219                    "--add-reads", "java.base=ALL-UNNAMED",
220                    "--patch-module", "java.base=" + src)
221           .outdir(classes)
222           .files(src.resolve("impl").resolve("Impl.java"))
223           .run()
224           .writeAll();
225     }
226 
227     @Test
testAddReadsToJavaBase(Path base)228     public void testAddReadsToJavaBase(Path base) throws Exception {
229         Path src = base.resolve("src");
230         Path classes = base.resolve("classes");
231 
232         Files.createDirectories(classes);
233 
234         tb.writeJavaFiles(src,
235                           "package impl; public class Impl { javax.swing.JButton b; }");
236 
237         new JavacTask(tb)
238           .options("--add-modules", "java.desktop",
239                    "--add-reads", "java.base=java.desktop",
240                    "--patch-module", "java.base=" + src)
241           .outdir(classes)
242           .files(findJavaFiles(src))
243           .run()
244           .writeAll();
245     }
246 
prepareTestJar(Path base)247     private Path prepareTestJar(Path base) throws Exception {
248         Path legacySrc = base.resolve("legacy-src");
249         tb.writeJavaFiles(legacySrc,
250                           "package api; public abstract class Api {}");
251         Path legacyClasses = base.resolve("legacy-classes");
252         Files.createDirectories(legacyClasses);
253 
254         String log = new JavacTask(tb)
255                 .options()
256                 .outdir(legacyClasses)
257                 .files(findJavaFiles(legacySrc))
258                 .run()
259                 .writeAll()
260                 .getOutput(Task.OutputKind.DIRECT);
261 
262         if (!log.isEmpty()) {
263             throw new Exception("unexpected output: " + log);
264         }
265 
266         Path lib = base.resolve("lib");
267 
268         Files.createDirectories(lib);
269 
270         Path jar = lib.resolve("test-api-1.0.jar");
271 
272         new JarTask(tb, jar)
273           .baseDir(legacyClasses)
274           .files("api/Api.class")
275           .run();
276 
277         return jar;
278     }
279 
280     @Test
testX(Path base)281     public void testX(Path base) throws Exception {
282         Path src = base.resolve("src");
283         Path src_m1 = src.resolve("m1x");
284         tb.writeJavaFiles(src_m1,
285                           "module m1x { provides java.lang.Runnable with impl.Impl; }",
286                           "package impl; public class Impl implements Runnable { public void run() { } }");
287         Path classes = base.resolve("classes");
288         tb.createDirectories(classes);
289 
290         new JavacTask(tb)
291                 .options("--module-source-path", src.toString())
292                 .outdir(classes)
293                 .files(findJavaFiles(src))
294                 .run()
295                 .writeAll();
296 
297         Path unnamedSrc = base.resolve("unnamed-src");
298         Path unnamedClasses = base.resolve("unnamed-classes");
299 
300         Files.createDirectories(unnamedClasses);
301 
302         tb.writeJavaFiles(unnamedSrc,
303                           "package impl; public class Impl { }");
304 
305         new JavacTask(tb)
306           .options("--add-reads", "m1x=ALL-UNNAMED",
307                    "--patch-module", "m1x=" + unnamedSrc,
308                    "--module-path", classes.toString())
309           .outdir(unnamedClasses)
310           .files(findJavaFiles(unnamedSrc))
311           .run()
312           .writeAll();
313     }
314 
315     @Test
testAddSelf(Path base)316     public void testAddSelf(Path base) throws Exception {
317         Path src = base.resolve("src");
318         Path src_m1 = src.resolve("m1x");
319         tb.writeJavaFiles(src_m1,
320                           "module m1x { exports p1; }",
321                           "package p1; public class C1 { }");
322         Path classes = base.resolve("classes");
323         tb.createDirectories(classes);
324 
325         new JavacTask(tb)
326                 .options("--module-source-path", src.toString(),
327                          "--add-reads", "m1x=m1x")
328                 .outdir(classes)
329                 .files(findJavaFiles(src))
330                 .run()
331                 .writeAll();
332     }
333 
334     @Test
testEmpty(Path base)335     public void testEmpty(Path base) throws Exception {
336         Path src = base.resolve("src");
337         tb.writeJavaFiles(src, "class Dummy { }");
338         Path classes = base.resolve("classes");
339         tb.createDirectories(classes);
340 
341         testEmpty(src, classes, "--add-reads", "");
342         testEmpty(src, classes, "--add-reads=");
343     }
344 
testEmpty(Path src, Path classes, String... options)345     private void testEmpty(Path src, Path classes, String... options) throws Exception {
346         String log = new JavacTask(tb, Task.Mode.CMDLINE)
347                 .options(options)
348                 .outdir(classes)
349                 .files(findJavaFiles(src))
350                 .run(Task.Expect.FAIL)
351                 .writeAll()
352                 .getOutput(Task.OutputKind.DIRECT);
353 
354         checkOutputContains(log,
355             "error: no value for --add-reads option");
356     }
357 
358     @Test
testEmptyItem(Path base)359     public void testEmptyItem(Path base) throws Exception {
360         Path src = base.resolve("src");
361         Path src_m1 = src.resolve("m1x");
362         tb.writeJavaFiles(src_m1,
363                           "module m1x { exports p1; }",
364                           "package p1; public class C1 { }");
365         Path src_m2 = src.resolve("m2x");
366         tb.writeJavaFiles(src_m2,
367                           "module m2x { }",
368                           "package p2; class C2 { }");
369         Path src_m3 = src.resolve("m3x");
370         tb.writeJavaFiles(src_m3,
371                           "module m3x { }",
372                           "package p3; class C3 { p1.C1 c1; }");
373         Path classes = base.resolve("classes");
374         tb.createDirectories(classes);
375 
376         testEmptyItem(src, classes, "m3x=,m1x");
377         testEmptyItem(src, classes, "m3x=m1x,,m2x");
378         testEmptyItem(src, classes, "m3x=m1x,");
379     }
380 
testEmptyItem(Path src, Path classes, String option)381     private void testEmptyItem(Path src, Path classes, String option) throws Exception {
382         new JavacTask(tb)
383                 .options("--module-source-path", src.toString(),
384                          "--add-reads", option)
385                 .outdir(classes)
386                 .files(findJavaFiles(src))
387                 .run()
388                 .writeAll();
389     }
390 
391     @Test
testEmptyList(Path base)392     public void testEmptyList(Path base) throws Exception {
393         Path src = base.resolve("src");
394         Path src_m1 = src.resolve("m1x");
395         tb.writeJavaFiles(src_m1,
396                           "module m1x { exports p1; }",
397                           "package p1; public class C1 { }");
398         Path src_m2 = src.resolve("m2x");
399         tb.writeJavaFiles(src_m2,
400                           "module m2x { }",
401                           "package p2; class C2 { }");
402         Path src_m3 = src.resolve("m3x");
403         tb.writeJavaFiles(src_m3,
404                           "module m3x { }",
405                           "package p3; class C3 { p1.C1 c1; }");
406         Path classes = base.resolve("classes");
407         tb.createDirectories(classes);
408 
409         testEmptyList(src, classes, "m3x=");
410         testEmptyList(src, classes, "m3x=,");
411     }
412 
testEmptyList(Path src, Path classes, String option)413     private void testEmptyList(Path src, Path classes, String option) throws Exception {
414         String log = new JavacTask(tb, Task.Mode.CMDLINE)
415                 .options("--module-source-path", src.toString(),
416                          "--add-reads", option)
417                 .outdir(classes)
418                 .files(findJavaFiles(src))
419                 .run(Task.Expect.FAIL)
420                 .writeAll()
421                 .getOutput(Task.OutputKind.DIRECT);
422 
423         checkOutputContains(log,
424             "error: bad value for --add-reads option: '" + option + "'");
425     }
426 
427     @Test
testMultipleAddReads_DifferentModules(Path base)428     public void testMultipleAddReads_DifferentModules(Path base) throws Exception {
429         Path src = base.resolve("src");
430         Path src_m1 = src.resolve("m1x");
431         tb.writeJavaFiles(src_m1,
432                           "module m1x { exports p1; }",
433                           "package p1; public class C1 { }");
434         Path src_m2 = src.resolve("m2x");
435         tb.writeJavaFiles(src_m2,
436                           "module m2x { }",
437                           "package p2; class C2 { p1.C1 c1; }");
438         Path src_m3 = src.resolve("m3x");
439         tb.writeJavaFiles(src_m3,
440                           "module m3x { }",
441                           "package p3; class C3 { p1.C1 c1; }");
442         Path classes = base.resolve("classes");
443         tb.createDirectories(classes);
444 
445         new JavacTask(tb)
446                 .options("--module-source-path", src.toString(),
447                          "--add-reads", "m2x=m1x",
448                          "--add-reads", "m3x=m1x")
449                 .outdir(classes)
450                 .files(findJavaFiles(src))
451                 .run()
452                 .writeAll();
453     }
454 
455     @Test
testMultipleAddReads_SameModule(Path base)456     public void testMultipleAddReads_SameModule(Path base) throws Exception {
457         Path src = base.resolve("src");
458         Path src_m1 = src.resolve("m1x");
459         tb.writeJavaFiles(src_m1,
460                           "module m1x { exports p1; }",
461                           "package p1; public class C1 { }");
462         Path src_m2 = src.resolve("m2x");
463         tb.writeJavaFiles(src_m2,
464                           "module m2x { exports p2; }",
465                           "package p2; public class C2 { }");
466         Path src_m3 = src.resolve("m3x");
467         tb.writeJavaFiles(src_m3,
468                           "module m3x { }",
469                           "package p3; class C3 { p1.C1 c1; p2.C2 c2; }");
470         Path classes = base.resolve("classes");
471         tb.createDirectories(classes);
472 
473         new JavacTask(tb)
474                 .options("--module-source-path", src.toString(),
475                          "--add-reads", "m3x=m1x",
476                          "--add-reads", "m3x=m2x")
477                 .outdir(classes)
478                 .files(findJavaFiles(src))
479                 .run()
480                 .writeAll();
481     }
482 
483     @Test
testDuplicateAddReads_SameOption(Path base)484     public void testDuplicateAddReads_SameOption(Path base) throws Exception {
485         Path src = base.resolve("src");
486         Path src_m1 = src.resolve("m1x");
487         tb.writeJavaFiles(src_m1,
488                           "module m1x { exports p1; }",
489                           "package p1; public class C1 { }");
490         Path src_m2 = src.resolve("m2x");
491         tb.writeJavaFiles(src_m2,
492                           "module m2x { exports p2; }",
493                           "package p2; class C2 { p1.C1 c1; }");
494         Path classes = base.resolve("classes");
495         tb.createDirectories(classes);
496 
497         new JavacTask(tb)
498                 .options("--module-source-path", src.toString(),
499                          "--add-reads", "m2x=m1x,m1x")
500                 .outdir(classes)
501                 .files(findJavaFiles(src))
502                 .run()
503                 .writeAll();
504     }
505 
506     @Test
testDuplicateAddReads_MultipleOptions(Path base)507     public void testDuplicateAddReads_MultipleOptions(Path base) throws Exception {
508         Path src = base.resolve("src");
509         Path src_m1 = src.resolve("m1x");
510         tb.writeJavaFiles(src_m1,
511                           "module m1x { exports p1; }",
512                           "package p1; public class C1 { }");
513         Path src_m2 = src.resolve("m2x");
514         tb.writeJavaFiles(src_m2,
515                           "module m2x { }",
516                           "package p2; class C2 { p1.C1 c1; }");
517         Path classes = base.resolve("classes");
518         tb.createDirectories(classes);
519 
520         new JavacTask(tb)
521                 .options("--module-source-path", src.toString(),
522                          "--add-reads", "m2x=m1x",
523                          "--add-reads", "m2x=m1x")
524                 .outdir(classes)
525                 .files(findJavaFiles(src))
526                 .run()
527                 .writeAll();
528     }
529 
530     @Test
testRepeatedAddReads(Path base)531     public void testRepeatedAddReads(Path base) throws Exception {
532         Path src = base.resolve("src");
533         Path src_m1 = src.resolve("m1x");
534         tb.writeJavaFiles(src_m1,
535                           "module m1x { exports p1; }",
536                           "package p1; public class C1 { }");
537         Path src_m2 = src.resolve("m2x");
538         tb.writeJavaFiles(src_m2,
539                           "module m2x { exports p2; }",
540                           "package p2; public class C2 { }");
541         Path src_m3 = src.resolve("m3x");
542         tb.writeJavaFiles(src_m3,
543                           "module m3x { }",
544                           "package p3; class C3 { p1.C1 c1; p2.C2 c2; }");
545         Path classes = base.resolve("classes");
546         tb.createDirectories(classes);
547 
548         new JavacTask(tb)
549                 .options("--module-source-path", src.toString(),
550                          "--add-reads", "m3x=m1x",
551                          "--add-reads", "m3x=m2x")
552                 .outdir(classes)
553                 .files(findJavaFiles(src))
554                 .run()
555                 .writeAll();
556     }
557 
558     @Test
testNoEquals(Path base)559     public void testNoEquals(Path base) throws Exception {
560         Path src = base.resolve("src");
561         tb.writeJavaFiles(src, "class Dummy { }");
562         Path classes = base.resolve("classes");
563         tb.createDirectories(classes);
564 
565         String log = new JavacTask(tb, Task.Mode.CMDLINE)
566                 .options("-XDrawDiagnostics",
567                          "--add-reads", "m1x:m2x")
568                 .outdir(classes)
569                 .files(findJavaFiles(src))
570                 .run(Task.Expect.FAIL)
571                 .writeAll()
572                 .getOutput(Task.OutputKind.DIRECT);
573 
574         checkOutputContains(log,
575             "error: bad value for --add-reads option: 'm1x:m2x'");
576     }
577 
578     @Test
testBadSourceName(Path base)579     public void testBadSourceName(Path base) throws Exception {
580         Path src = base.resolve("src");
581         tb.writeJavaFiles(src, "class Dummy { }");
582         Path classes = base.resolve("classes");
583         tb.createDirectories(classes);
584 
585         String log = new JavacTask(tb)
586                 .options("-XDrawDiagnostics",
587                          "--add-reads", "bad*Source=m2x")
588                 .outdir(classes)
589                 .files(findJavaFiles(src))
590                 .run()
591                 .writeAll()
592                 .getOutput(Task.OutputKind.DIRECT);
593 
594         checkOutputContains(log,
595             "- compiler.warn.bad.name.for.option: --add-reads, bad*Source");
596     }
597 
598     @Test
testBadTargetName(Path base)599     public void testBadTargetName(Path base) throws Exception {
600         Path src = base.resolve("src");
601         Path src_m1 = src.resolve("m1x");
602         tb.writeJavaFiles(src_m1,
603                           "module m1x { }",
604                           "package p1; class C1 { }");
605         Path classes = base.resolve("classes");
606         tb.createDirectories(classes);
607 
608         String log = new JavacTask(tb)
609                 .options("-XDrawDiagnostics",
610                          "--add-reads", "m1x=badTarget!")
611                 .outdir(classes)
612                 .files(findJavaFiles(src))
613                 .run()
614                 .writeAll()
615                 .getOutput(Task.OutputKind.DIRECT);
616 
617         checkOutputContains(log,
618             "- compiler.warn.bad.name.for.option: --add-reads, badTarget!");
619     }
620 
621     @Test
testSourceNameNotFound(Path base)622     public void testSourceNameNotFound(Path base) throws Exception {
623         Path src = base.resolve("src");
624         Path src_m1 = src.resolve("m1x");
625         tb.writeJavaFiles(src_m1,
626                           "module m1x { exports p1; }",
627                           "package p1; public class C1 { }");
628         Path classes = base.resolve("classes");
629         tb.createDirectories(classes);
630 
631         String log = new JavacTask(tb)
632                 .options("-XDrawDiagnostics",
633                          "--add-reads", "missingSource=m")
634                 .outdir(classes)
635                 .files(findJavaFiles(src))
636                 .run()
637                 .writeAll()
638                 .getOutput(Task.OutputKind.DIRECT);
639 
640         checkOutputContains(log,
641             "- compiler.warn.module.for.option.not.found: --add-reads, missingSource");
642     }
643 
644     @Test
testTargetNameNotFound(Path base)645     public void testTargetNameNotFound(Path base) throws Exception {
646         Path src = base.resolve("src");
647         Path src_m1 = src.resolve("m1x");
648         tb.writeJavaFiles(src_m1,
649                           "module m1x { exports p1; }",
650                           "package p1; public class C1 { }");
651         Path classes = base.resolve("classes");
652         tb.createDirectories(classes);
653 
654         String log = new JavacTask(tb)
655                 .options("-XDrawDiagnostics",
656                          "--add-reads", "m1x=missingTarget")
657                 .outdir(classes)
658                 .files(findJavaFiles(src))
659                 .run()
660                 .writeAll()
661                 .getOutput(Task.OutputKind.DIRECT);
662 
663         checkOutputContains(log,
664             "- compiler.warn.module.for.option.not.found: --add-reads, missingTarget");
665     }
666 }
667