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 tests for multi-module mode compilation
  27  * @library /tools/lib
  28  * @modules
  29  *      jdk.compiler/com.sun.tools.javac.api
  30  *      jdk.compiler/com.sun.tools.javac.code
  31  *      jdk.compiler/com.sun.tools.javac.main
  32  *      jdk.compiler/com.sun.tools.javac.processing
  33  * @build toolbox.ToolBox toolbox.JavacTask toolbox.ModuleBuilder ModuleTestBase
  34  * @run main XModuleTest
  35  */
  36 
  37 import java.nio.file.Path;
  38 import java.util.Arrays;
  39 import java.util.List;
  40 import java.util.Set;
  41 
  42 import javax.annotation.processing.AbstractProcessor;
  43 import javax.annotation.processing.RoundEnvironment;
  44 import javax.annotation.processing.SupportedAnnotationTypes;
  45 import javax.lang.model.SourceVersion;
  46 import javax.lang.model.element.ModuleElement;
  47 import javax.lang.model.element.TypeElement;
  48 import javax.lang.model.util.Elements;
  49 
  50 import com.sun.tools.javac.code.Symtab;
  51 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
  52 import toolbox.JavacTask;
  53 import toolbox.ModuleBuilder;
  54 import toolbox.Task;
  55 import toolbox.Task.Expect;
  56 
  57 public class XModuleTest extends ModuleTestBase {
  58 
  59     public static void main(String... args) throws Exception {
  60         new XModuleTest().runTests();
  61     }
  62 
  63     @Test
  64     public void testCorrectXModule(Path base) throws Exception {
  65         //note: avoiding use of java.base, as that gets special handling on some places:
  66         Path src = base.resolve("src");
  67         tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element { }");
  68         Path classes = base.resolve("classes");
  69         tb.createDirectories(classes);
  70 
  71         String log = new JavacTask(tb)
  72                 .options("-Xmodule:java.compiler")
  73                 .outdir(classes)
  74                 .files(findJavaFiles(src))
  75                 .run()
  76                 .writeAll()
  77                 .getOutput(Task.OutputKind.DIRECT);
  78 
  79         if (!log.isEmpty())
  80             throw new Exception("expected output not found: " + log);
  81     }
  82 
  83     @Test
  84     public void testSourcePath(Path base) throws Exception {
  85         //note: avoiding use of java.base, as that gets special handling on some places:
  86         Path src = base.resolve("src");
  87         tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element, Other { }", "package javax.lang.model.element; interface Other { }");
  88         Path classes = base.resolve("classes");
  89         tb.createDirectories(classes);
  90 
  91         String log = new JavacTask(tb)
  92                 .options("-Xmodule:java.compiler", "-sourcepath", src.toString())
  93                 .outdir(classes)
  94                 .files(src.resolve("javax/lang/model/element/Extra.java"))
  95                 .run()
  96                 .writeAll()
  97                 .getOutput(Task.OutputKind.DIRECT);
  98 
  99         if (!log.isEmpty())
 100             throw new Exception("expected output not found: " + log);
 101     }
 102 
 103     @Test
 104     public void testClassPath(Path base) throws Exception {
 105         Path cpSrc = base.resolve("cpSrc");
 106         tb.writeJavaFiles(cpSrc, "package p; public interface Other { }");
 107         Path cpClasses = base.resolve("cpClasses");
 108         tb.createDirectories(cpClasses);
 109 
 110         String cpLog = new JavacTask(tb)
 111                 .outdir(cpClasses)
 112                 .files(findJavaFiles(cpSrc))
 113                 .run()
 114                 .writeAll()
 115                 .getOutput(Task.OutputKind.DIRECT);
 116 
 117         if (!cpLog.isEmpty())
 118             throw new Exception("expected output not found: " + cpLog);
 119 
 120         Path src = base.resolve("src");
 121         //note: avoiding use of java.base, as that gets special handling on some places:
 122         tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element, p.Other { }");
 123         Path classes = base.resolve("classes");
 124         tb.createDirectories(classes);
 125 
 126         List<String> log = new JavacTask(tb)
 127                 .options("-Xmodule:java.compiler",
 128                          "--class-path", cpClasses.toString(),
 129                          "-XDrawDiagnostics")
 130                 .outdir(classes)
 131                 .files(src.resolve("javax/lang/model/element/Extra.java"))
 132                 .run(Expect.FAIL)
 133                 .writeAll()
 134                 .getOutputLines(Task.OutputKind.DIRECT);
 135 
 136         List<String> expectedOut = Arrays.asList(
 137                 "Extra.java:1:76: compiler.err.doesnt.exist: p",
 138                 "1 error"
 139         );
 140 
 141         if (!expectedOut.equals(log))
 142             throw new Exception("expected output not found: " + log);
 143     }
 144 
 145     @Test
 146     public void testNoModuleInfoOnSourcePath(Path base) throws Exception {
 147         //note: avoiding use of java.base, as that gets special handling on some places:
 148         Path src = base.resolve("src");
 149         tb.writeJavaFiles(src,
 150                           "module java.compiler {}",
 151                           "package javax.lang.model.element; public interface Extra { }");
 152         Path classes = base.resolve("classes");
 153         tb.createDirectories(classes);
 154 
 155         List<String> log = new JavacTask(tb)
 156                 .options("-XDrawDiagnostics", "-Xmodule:java.compiler")
 157                 .outdir(classes)
 158                 .files(findJavaFiles(src))
 159                 .run(Task.Expect.FAIL)
 160                 .writeAll()
 161                 .getOutputLines(Task.OutputKind.DIRECT);
 162 
 163         List<String> expected = Arrays.asList("Extra.java:1:1: compiler.err.module-info.with.xmodule.sourcepath",
 164                                               "1 error");
 165 
 166         if (!expected.equals(log))
 167             throw new Exception("expected output not found: " + log);
 168     }
 169 
 170     @Test
 171     public void testNoModuleInfoInClassOutput(Path base) throws Exception {
 172         //note: avoiding use of java.base, as that gets special handling on some places:
 173         Path srcMod = base.resolve("src-mod");
 174         tb.writeJavaFiles(srcMod,
 175                           "module mod {}");
 176         Path classes = base.resolve("classes");
 177         tb.createDirectories(classes);
 178 
 179         String logMod = new JavacTask(tb)
 180                 .options()
 181                 .outdir(classes)
 182                 .files(findJavaFiles(srcMod))
 183                 .run()
 184                 .writeAll()
 185                 .getOutput(Task.OutputKind.DIRECT);
 186 
 187         if (!logMod.isEmpty())
 188             throw new Exception("unexpected output found: " + logMod);
 189 
 190         Path src = base.resolve("src");
 191         tb.writeJavaFiles(src,
 192                           "package javax.lang.model.element; public interface Extra { }");
 193         tb.createDirectories(classes);
 194 
 195         List<String> log = new JavacTask(tb)
 196                 .options("-XDrawDiagnostics", "-Xmodule:java.compiler")
 197                 .outdir(classes)
 198                 .files(findJavaFiles(src))
 199                 .run(Task.Expect.FAIL)
 200                 .writeAll()
 201                 .getOutputLines(Task.OutputKind.DIRECT);
 202 
 203         List<String> expected = Arrays.asList("Extra.java:1:1: compiler.err.module-info.with.xmodule.classpath",
 204                                               "1 error");
 205 
 206         if (!expected.equals(log))
 207             throw new Exception("expected output not found: " + log);
 208     }
 209 
 210     @Test
 211     public void testModuleSourcePathXModule(Path base) throws Exception {
 212         //note: avoiding use of java.base, as that gets special handling on some places:
 213         Path src = base.resolve("src");
 214         tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element { }");
 215         Path classes = base.resolve("classes");
 216         tb.createDirectories(classes);
 217 
 218         List<String> log = new JavacTask(tb)
 219                 .options("-XDrawDiagnostics", "-Xmodule:java.compiler", "--module-source-path", src.toString())
 220                 .outdir(classes)
 221                 .files(findJavaFiles(src))
 222                 .run(Task.Expect.FAIL)
 223                 .writeAll()
 224                 .getOutputLines(Task.OutputKind.DIRECT);
 225 
 226         List<String> expected = Arrays.asList("- compiler.err.xmodule.no.module.sourcepath");
 227 
 228         if (!expected.equals(log))
 229             throw new Exception("expected output not found: " + log);
 230     }
 231 
 232     @Test
 233     public void testXModuleTooMany(Path base) throws Exception {
 234         //note: avoiding use of java.base, as that gets special handling on some places:
 235         Path src = base.resolve("src");
 236         tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element { }");
 237         Path classes = base.resolve("classes");
 238         tb.createDirectories(classes);
 239 
 240         List<String> log = new JavacTask(tb, Task.Mode.CMDLINE)
 241                 .options("-XDrawDiagnostics", "-Xmodule:java.compiler", "-Xmodule:java.compiler")
 242                 .outdir(classes)
 243                 .files(findJavaFiles(src))
 244                 .run(Task.Expect.FAIL)
 245                 .writeAll()
 246                 .getOutputLines(Task.OutputKind.DIRECT);
 247 
 248         List<String> expected = Arrays.asList("javac: option -Xmodule: can only be specified once",
 249                                               "Usage: javac <options> <source files>",
 250                                               "use --help for a list of possible options");
 251 
 252         if (!expected.equals(log))
 253             throw new Exception("expected output not found: " + log);
 254     }
 255 
 256     @Test
 257     public void testWithModulePath(Path base) throws Exception {
 258         Path modSrc = base.resolve("modSrc");
 259         Path modules = base.resolve("modules");
 260         new ModuleBuilder(tb, "m1")
 261                 .classes("package pkg1; public interface E { }")
 262                 .build(modSrc, modules);
 263 
 264         Path src = base.resolve("src");
 265         tb.writeJavaFiles(src, "package p; interface A extends pkg1.E { }");
 266 
 267         new JavacTask(tb, Task.Mode.CMDLINE)
 268                 .options("--module-path", modules.toString(),
 269                         "-Xmodule:m1")
 270                 .files(findJavaFiles(src))
 271                 .run()
 272                 .writeAll();
 273 
 274         //checks module bounds still exist
 275         new ModuleBuilder(tb, "m2")
 276                 .classes("package pkg2; public interface D { }")
 277                 .build(modSrc, modules);
 278 
 279         Path src2 = base.resolve("src2");
 280         tb.writeJavaFiles(src2, "package p; interface A extends pkg2.D { }");
 281 
 282         List<String> log = new JavacTask(tb, Task.Mode.CMDLINE)
 283                 .options("-XDrawDiagnostics",
 284                         "--module-path", modules.toString(),
 285                         "-Xmodule:m1")
 286                 .files(findJavaFiles(src2))
 287                 .run(Task.Expect.FAIL)
 288                 .writeAll()
 289                 .getOutputLines(Task.OutputKind.DIRECT);
 290 
 291         List<String> expected = Arrays.asList("A.java:1:32: compiler.err.package.not.visible: pkg2, (compiler.misc.not.def.access.does.not.read: m1, pkg2, m2)",
 292                 "1 error");
 293 
 294         if (!expected.equals(log))
 295             throw new Exception("expected output not found: " + log);
 296     }
 297 
 298     @Test
 299     public void testWithUpgradeModulePath(Path base) throws Exception {
 300         Path modSrc = base.resolve("modSrc");
 301         Path modules = base.resolve("modules");
 302         new ModuleBuilder(tb, "m1")
 303                 .classes("package pkg1; public interface E { }")
 304                 .build(modSrc, modules);
 305 
 306         Path upgrSrc = base.resolve("upgradeSrc");
 307         Path upgrade = base.resolve("upgrade");
 308         new ModuleBuilder(tb, "m1")
 309                 .classes("package pkg1; public interface D { }")
 310                 .build(upgrSrc, upgrade);
 311 
 312         Path src = base.resolve("src");
 313         tb.writeJavaFiles(src, "package p; interface A extends pkg1.D { }");
 314 
 315         new JavacTask(tb, Task.Mode.CMDLINE)
 316                 .options("--module-path", modules.toString(),
 317                         "--upgrade-module-path", upgrade.toString(),
 318                         "-Xmodule:m1")
 319                 .files(findJavaFiles(src))
 320                 .run()
 321                 .writeAll();
 322     }
 323 
 324     @Test
 325     public void testUnnamedIsolation(Path base) throws Exception {
 326         //note: avoiding use of java.base, as that gets special handling on some places:
 327         Path sourcePath = base.resolve("source-path");
 328         tb.writeJavaFiles(sourcePath, "package src; public class Src {}");
 329 
 330         Path classPathSrc = base.resolve("class-path-src");
 331         tb.writeJavaFiles(classPathSrc, "package cp; public class CP { }");
 332         Path classPath = base.resolve("classPath");
 333         tb.createDirectories(classPath);
 334 
 335         String cpLog = new JavacTask(tb)
 336                 .outdir(classPath)
 337                 .files(findJavaFiles(classPathSrc))
 338                 .run()
 339                 .writeAll()
 340                 .getOutput(Task.OutputKind.DIRECT);
 341 
 342         if (!cpLog.isEmpty())
 343             throw new Exception("expected output not found: " + cpLog);
 344 
 345         Path modulePathSrc = base.resolve("module-path-src");
 346         tb.writeJavaFiles(modulePathSrc,
 347                           "module m {}",
 348                           "package m; public class M {}");
 349         Path modulePath = base.resolve("modulePath");
 350         tb.createDirectories(modulePath.resolve("m"));
 351 
 352         String modLog = new JavacTask(tb)
 353                 .outdir(modulePath.resolve("m"))
 354                 .files(findJavaFiles(modulePathSrc))
 355                 .run()
 356                 .writeAll()
 357                 .getOutput(Task.OutputKind.DIRECT);
 358 
 359         if (!modLog.isEmpty())
 360             throw new Exception("expected output not found: " + modLog);
 361 
 362         Path src = base.resolve("src");
 363         tb.writeJavaFiles(src, "package m; public class Extra { }");
 364         Path classes = base.resolve("classes");
 365         tb.createDirectories(classes);
 366 
 367         String log = new JavacTask(tb)
 368                 .options("-Xmodule:m",
 369                          "--class-path", classPath.toString(),
 370                          "--source-path", sourcePath.toString(),
 371                          "--module-path", modulePath.toString(),
 372                          "--processor-path", System.getProperty("test.classes"),
 373                          "-XDaccessInternalAPI=true",
 374                          "-processor", CheckModuleContentProcessing.class.getName())
 375                 .outdir(classes)
 376                 .files(findJavaFiles(sourcePath))
 377                 .run()
 378                 .writeAll()
 379                 .getOutput(Task.OutputKind.DIRECT);
 380 
 381         if (!log.isEmpty())
 382             throw new Exception("expected output not found: " + log);
 383     }
 384 
 385     @SupportedAnnotationTypes("*")
 386     public static final class CheckModuleContentProcessing extends AbstractProcessor {
 387 
 388         @Override
 389         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
 390             Symtab syms = Symtab.instance(((JavacProcessingEnvironment) processingEnv).getContext());
 391             Elements elements = processingEnv.getElementUtils();
 392             ModuleElement unnamedModule = syms.unnamedModule;
 393             ModuleElement mModule = elements.getModuleElement("m");
 394 
 395             assertNonNull("mModule found", mModule);
 396             assertNonNull("src.Src from m", elements.getTypeElement(mModule, "src.Src"));
 397             assertNull("cp.CP not from m", elements.getTypeElement(mModule, "cp.CP"));
 398             assertNull("src.Src not from unnamed", elements.getTypeElement(unnamedModule, "src.Src"));
 399             assertNonNull("cp.CP from unnamed", elements.getTypeElement(unnamedModule, "cp.CP"));
 400 
 401             return false;
 402         }
 403 
 404         @Override
 405         public SourceVersion getSupportedSourceVersion() {
 406             return SourceVersion.latest();
 407         }
 408 
 409         private static void assertNonNull(String msg, Object val) {
 410             if (val == null) {
 411                 throw new AssertionError(msg);
 412             }
 413         }
 414 
 415         private static void assertNull(String msg, Object val) {
 416             if (val != null) {
 417                 throw new AssertionError(msg);
 418             }
 419         }
 420     }
 421 
 422 }