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