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