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 * @bug 8154283 8167320 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 * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask ModuleTestBase 34 * @run main EdgeCases 35 */ 36 37 import java.io.Writer; 38 import java.nio.file.Files; 39 import java.nio.file.Path; 40 import java.nio.file.Paths; 41 import java.util.Arrays; 42 import java.util.HashSet; 43 import java.util.List; 44 import java.util.Objects; 45 import java.util.Set; 46 47 import javax.lang.model.element.Element; 48 import javax.tools.JavaCompiler; 49 import javax.tools.JavaFileObject; 50 import javax.tools.StandardJavaFileManager; 51 import javax.tools.ToolProvider; 52 53 import com.sun.source.tree.CompilationUnitTree; 54 //import com.sun.source.util.JavacTask; // conflicts with toolbox.JavacTask 55 import com.sun.tools.javac.api.JavacTaskImpl; 56 import com.sun.tools.javac.code.Symbol.ModuleSymbol; 57 import com.sun.tools.javac.code.Symtab; 58 59 import toolbox.JarTask; 60 import toolbox.JavacTask; 61 import toolbox.Task; 62 import toolbox.Task.Expect; 63 import toolbox.Task.OutputKind; 64 65 public class EdgeCases extends ModuleTestBase { 66 67 public static void main(String... args) throws Exception { 68 new EdgeCases().runTests(); 69 } 70 71 @Test 72 public void testAddExportUndefinedModule(Path base) throws Exception { 73 Path src = base.resolve("src"); 74 tb.writeJavaFiles(src, "package test; import undefPackage.Any; public class Test {}"); 75 Path classes = base.resolve("classes"); 76 tb.createDirectories(classes); 77 78 List<String> log = new JavacTask(tb) 79 .options("--add-exports", "undefModule/undefPackage=ALL-UNNAMED", 80 "-XDrawDiagnostics") 81 .outdir(classes) 82 .files(findJavaFiles(src)) 83 .run(Task.Expect.FAIL) 84 .writeAll() 85 .getOutputLines(Task.OutputKind.DIRECT); 86 87 List<String> expected = Arrays.asList("- compiler.warn.module.for.option.not.found: --add-exports, undefModule", 88 "Test.java:1:34: compiler.err.doesnt.exist: undefPackage", 89 "1 error", "1 warning"); 90 91 if (!expected.equals(log)) 92 throw new Exception("expected output not found: " + log); 93 } 94 95 @Test 96 public void testModuleSymbolOutterMostClass(Path base) throws Exception { 97 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 98 try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) { 99 Path moduleSrc = base.resolve("module-src"); 100 Path m1 = moduleSrc.resolve("m1x"); 101 102 tb.writeJavaFiles(m1, "module m1x { }"); 103 104 Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(findJavaFiles(moduleSrc)); 105 com.sun.source.util.JavacTask task = 106 (com.sun.source.util.JavacTask) compiler.getTask(null, fm, null, null, null, files); 107 108 task.analyze(); 109 110 ModuleSymbol msym = (ModuleSymbol) task.getElements().getModuleElement("m1x"); 111 112 msym.outermostClass(); 113 } 114 } 115 116 @Test 117 public void testParseEnterAnalyze(Path base) throws Exception { 118 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 119 try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) { 120 Path moduleSrc = base.resolve("module-src"); 121 Path m1 = moduleSrc.resolve("m1x"); 122 123 tb.writeJavaFiles(m1, "module m1x { }", 124 "package p;", 125 "package p; class T { }"); 126 127 Path classes = base.resolve("classes"); 128 Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(findJavaFiles(moduleSrc)); 129 List<String> options = Arrays.asList("-d", classes.toString(), "-Xpkginfo:always"); 130 JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, fm, null, options, null, files); 131 132 Iterable<? extends CompilationUnitTree> parsed = task.parse(); 133 Iterable<? extends Element> entered = task.enter(parsed); 134 Iterable<? extends Element> analyzed = task.analyze(entered); 135 Iterable<? extends JavaFileObject> generatedFiles = task.generate(analyzed); 136 137 Set<String> generated = new HashSet<>(); 138 139 for (JavaFileObject jfo : generatedFiles) { 140 generated.add(jfo.getName()); 141 } 142 143 Set<String> expected = new HashSet<>( 144 Arrays.asList(Paths.get("testParseEnterAnalyze", "classes", "p", "package-info.class").toString(), 145 Paths.get("testParseEnterAnalyze", "classes", "module-info.class").toString(), 146 Paths.get("testParseEnterAnalyze", "classes", "p", "T.class").toString()) 147 ); 148 149 if (!Objects.equals(expected, generated)) 150 throw new AssertionError("Incorrect generated files: " + generated); 151 } 152 } 153 154 @Test 155 public void testModuleImplicitModuleBoundaries(Path base) throws Exception { 156 Path src = base.resolve("src"); 157 Path src_m1 = src.resolve("m1x"); 158 tb.writeJavaFiles(src_m1, 159 "module m1x { exports api1; }", 160 "package api1; public class Api1 { public void call() { } }"); 161 Path src_m2 = src.resolve("m2x"); 162 tb.writeJavaFiles(src_m2, 163 "module m2x { requires m1x; exports api2; }", 164 "package api2; public class Api2 { public static api1.Api1 get() { return null; } }"); 165 Path src_m3 = src.resolve("m3x"); 166 tb.writeJavaFiles(src_m3, 167 "module m3x { requires m2x; }", 168 "package test; public class Test { { api2.Api2.get().call(); api2.Api2.get().toString(); } }"); 169 Path classes = base.resolve("classes"); 170 tb.createDirectories(classes); 171 172 String log = new JavacTask(tb) 173 .options("-XDrawDiagnostics", 174 "--module-source-path", src.toString()) 175 .outdir(classes) 176 .files(findJavaFiles(src)) 177 .run(Task.Expect.FAIL) 178 .writeAll() 179 .getOutput(Task.OutputKind.DIRECT); 180 181 if (!log.contains("Test.java:1:52: compiler.err.not.def.access.class.intf.cant.access: call(), api1.Api1") || 182 !log.contains("Test.java:1:76: compiler.err.not.def.access.class.intf.cant.access: toString(), java.lang.Object")) 183 throw new Exception("expected output not found"); 184 } 185 186 @Test 187 public void testAssignClassToAutomaticModule(Path base) throws Exception { 188 //check that if a ClassSymbol belongs to an automatic module, it is properly assigned and not 189 //duplicated when being accessed through a classfile. 190 Path automaticSrc = base.resolve("automaticSrc"); 191 tb.writeJavaFiles(automaticSrc, "package api1; public class Api1 {}"); 192 Path automaticClasses = base.resolve("automaticClasses"); 193 tb.createDirectories(automaticClasses); 194 195 String automaticLog = new JavacTask(tb) 196 .outdir(automaticClasses) 197 .files(findJavaFiles(automaticSrc)) 198 .run() 199 .writeAll() 200 .getOutput(Task.OutputKind.DIRECT); 201 202 if (!automaticLog.isEmpty()) 203 throw new Exception("expected output not found: " + automaticLog); 204 205 Path modulePath = base.resolve("module-path"); 206 207 Files.createDirectories(modulePath); 208 209 Path automaticJar = modulePath.resolve("a-1.0.jar"); 210 211 new JarTask(tb, automaticJar) 212 .baseDir(automaticClasses) 213 .files("api1/Api1.class") 214 .run(); 215 216 Path src = base.resolve("src"); 217 Path src_m2 = src.resolve("m2x"); 218 tb.writeJavaFiles(src_m2, 219 "module m2x { requires a; exports api2; }", 220 "package api2; public class Api2 { public static api1.Api1 get() { return null; } }"); 221 Path src_m3 = src.resolve("m3x"); 222 tb.writeJavaFiles(src_m3, 223 "module m3x { requires a; requires m2x; }", 224 "package test; public class Test { { api2.Api2.get(); api1.Api1 a1; } }"); 225 Path classes = base.resolve("classes"); 226 tb.createDirectories(classes); 227 228 new JavacTask(tb) 229 .options("--module-path", modulePath.toString(), 230 "--module-source-path", src.toString()) 231 .outdir(classes) 232 .files(findJavaFiles(src_m2)) 233 .run() 234 .writeAll(); 235 236 new JavacTask(tb) 237 .options("--module-path", modulePath.toString(), 238 "--module-source-path", src.toString()) 239 .outdir(classes) 240 .files(findJavaFiles(src_m3)) 241 .run() 242 .writeAll(); 243 } 244 245 @Test 246 public void testEmptyImplicitModuleInfo(Path base) throws Exception { 247 Path src = base.resolve("src"); 248 Path src_m1 = src.resolve("m1x"); 249 Files.createDirectories(src_m1); 250 try (Writer w = Files.newBufferedWriter(src_m1.resolve("module-info.java"))) {} 251 tb.writeJavaFiles(src_m1, 252 "package test; public class Test {}"); 253 Path classes = base.resolve("classes"); 254 tb.createDirectories(classes); 255 256 new JavacTask(tb) 257 .options("--source-path", src_m1.toString(), 258 "-XDrawDiagnostics") 259 .outdir(classes) 260 .files(findJavaFiles(src_m1.resolve("test"))) 261 .run(Task.Expect.FAIL) 262 .writeAll(); 263 264 tb.writeJavaFiles(src_m1, 265 "module m1x {}"); 266 267 new JavacTask(tb) 268 .options("--source-path", src_m1.toString()) 269 .outdir(classes) 270 .files(findJavaFiles(src_m1.resolve("test"))) 271 .run() 272 .writeAll(); 273 274 } 275 276 @Test 277 public void testClassPackageClash(Path base) throws Exception { 278 Path src = base.resolve("src"); 279 Path src_m1 = src.resolve("m1x"); 280 tb.writeJavaFiles(src_m1, 281 "module m1x { exports test.m1x; }", 282 "package test.m1x;\n" + 283 "public class Test {}\n"); 284 Path src_m2 = src.resolve("m2x"); 285 tb.writeJavaFiles(src_m2, 286 "module m2x { requires m1x; }", 287 "package test;\n" + 288 "public class m1x {}\n"); 289 Path classes = base.resolve("classes"); 290 tb.createDirectories(classes); 291 292 List<String> log = new JavacTask(tb) 293 .options("--module-source-path", src.toString(), 294 "-XDrawDiagnostics") 295 .outdir(classes) 296 .files(findJavaFiles(src)) 297 .run(Task.Expect.FAIL) 298 .writeAll() 299 .getOutputLines(Task.OutputKind.DIRECT); 300 301 List<String> expected = Arrays.asList( 302 "m1x.java:2:8: compiler.err.clash.with.pkg.of.same.name: kindname.class, test.m1x", 303 "1 error" 304 ); 305 306 if (!expected.equals(log)) { 307 throw new IllegalStateException(log.toString()); 308 } 309 } 310 311 @Test 312 public void testImplicitJavaBase(Path base) throws Exception { 313 Path src = base.resolve("src"); 314 Path src_java_base = src.resolve("java.base"); 315 Files.createDirectories(src_java_base); 316 tb.writeJavaFiles(src_java_base, "module java.base { exports java.lang; }"); 317 tb.writeJavaFiles(src_java_base, 318 "package java.lang; public class Object {}"); 319 Path classes = base.resolve("classes"); 320 tb.createDirectories(classes); 321 322 //module-info from source: 323 new JavacTask(tb) 324 .options("-sourcepath", src_java_base.toString()) 325 .outdir(classes) 326 .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java"))) 327 .run() 328 .writeAll(); 329 330 //module-info from class: 331 if (!Files.exists(classes.resolve("module-info.class"))) { 332 throw new AssertionError("module-info.class not created!"); 333 } 334 335 new JavacTask(tb) 336 .outdir(classes) 337 .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java"))) 338 .run() 339 .writeAll(); 340 341 //broken module-info.class: 342 Files.newOutputStream(classes.resolve("module-info.class")).close(); 343 344 List<String> log = new JavacTask(tb) 345 .options("-XDrawDiagnostics") 346 .outdir(classes) 347 .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java"))) 348 .run(Expect.FAIL) 349 .writeAll() 350 .getOutputLines(OutputKind.DIRECT); 351 352 List<String> expected = Arrays.asList( 353 "- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.illegal.start.of.class.file))", 354 "1 error"); 355 356 if (!expected.equals(log)) { 357 throw new AssertionError("Unexpected output: " + log); 358 } 359 360 //broken module-info.java: 361 Files.delete(classes.resolve("module-info.class")); 362 363 try (Writer out = Files.newBufferedWriter(src_java_base.resolve("module-info.java"))) { 364 out.write("class Broken {}"); 365 } 366 367 log = new JavacTask(tb) 368 .options("-sourcepath", src_java_base.toString(), 369 "-XDrawDiagnostics") 370 .outdir(classes) 371 .files(findJavaFiles(src_java_base.resolve("java").resolve("lang").resolve("Object.java"))) 372 .run(Expect.FAIL) 373 .writeAll() 374 .getOutputLines(OutputKind.DIRECT); 375 376 expected = Arrays.asList("X"); 377 378 if (expected.equals(log)) { 379 throw new AssertionError("Unexpected output: " + log); 380 } 381 } 382 383 @Test 384 public void testModuleInfoNameMismatchSource(Path base) throws Exception { 385 Path src = base.resolve("src"); 386 Path m1 = src.resolve("m1x"); 387 Files.createDirectories(m1); 388 tb.writeJavaFiles(m1, "module other { }", 389 "package test; public class Test {}"); 390 Path classes = base.resolve("classes"); 391 tb.createDirectories(classes); 392 393 List<String> log = new JavacTask(tb) 394 .options("--module-source-path", src.toString(), 395 "-XDrawDiagnostics") 396 .outdir(classes) 397 .files(findJavaFiles(m1.resolve("test").resolve("Test.java"))) 398 .run(Expect.FAIL) 399 .writeAll() 400 .getOutputLines(OutputKind.DIRECT); 401 402 List<String> expected = Arrays.asList( 403 "module-info.java:1:1: compiler.err.module.name.mismatch: other, m1x", 404 "- compiler.err.cant.access: m1x.module-info, (compiler.misc.cant.resolve.modules)", 405 "2 errors"); 406 407 if (!expected.equals(log)) { 408 throw new AssertionError("Unexpected output: " + log); 409 } 410 } 411 412 @Test 413 public void testModuleInfoNameMismatchClass(Path base) throws Exception { 414 Path src = base.resolve("src"); 415 Files.createDirectories(src); 416 tb.writeJavaFiles(src, "module other { }", 417 "package test; public class Test {}"); 418 Path classes = base.resolve("classes"); 419 Path m1Classes = classes.resolve("m1x"); 420 tb.createDirectories(m1Classes); 421 422 new JavacTask(tb) 423 .outdir(m1Classes) 424 .files(findJavaFiles(src)) 425 .run() 426 .writeAll() 427 .getOutputLines(OutputKind.DIRECT); 428 429 Path src2 = base.resolve("src2"); 430 Files.createDirectories(src2); 431 tb.writeJavaFiles(src2, "module use { requires m1x; }"); 432 433 Path classes2 = base.resolve("classes2"); 434 tb.createDirectories(classes2); 435 436 List<String> log = new JavacTask(tb) 437 .options("--module-path", classes.toString(), 438 "-XDrawDiagnostics") 439 .outdir(classes2) 440 .files(findJavaFiles(src2)) 441 .run(Expect.FAIL) 442 .writeAll() 443 .getOutputLines(OutputKind.DIRECT); 444 445 List<String> expected = Arrays.asList( 446 "- compiler.err.cant.access: m1x.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.module.name.mismatch: other, m1x))", 447 "1 error"); 448 449 if (!expected.equals(log)) { 450 throw new AssertionError("Unexpected output: " + log); 451 } 452 } 453 454 @Test 455 public void testGetDirectivesComplete(Path base) throws Exception { 456 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 457 JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, null, null, null, null, null); 458 Symtab syms = Symtab.instance(task.getContext()); 459 460 syms.java_base.getDirectives(); 461 } 462 463 @Test 464 public void testPackageInModuleInfo(Path base) throws Exception { 465 Path src = base.resolve("src"); 466 Files.createDirectories(src); 467 tb.writeJavaFiles(src, "package p; module foo { }"); 468 Path classes = base.resolve("classes"); 469 tb.createDirectories(classes); 470 471 List<String> log = new JavacTask(tb) 472 .options("-XDrawDiagnostics", "-XDshould-stop.ifError=FLOW") 473 .outdir(classes) 474 .files(findJavaFiles(src)) 475 .run(Expect.FAIL) 476 .writeAll() 477 .getOutputLines(OutputKind.DIRECT); 478 479 List<String> expected = Arrays.asList( 480 "module-info.java:1:1: compiler.err.no.pkg.in.module-info.java", 481 "1 error"); 482 483 if (!expected.equals(log)) { 484 throw new AssertionError("Unexpected output: " + log); 485 } 486 } 487 }