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 }