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