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 * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask ModuleTestBase 33 * @run main EdgeCases 34 */ 35 36 import java.io.Writer; 37 import java.nio.file.Files; 38 import java.nio.file.Path; 39 import java.nio.file.Paths; 40 import java.util.Arrays; 41 import java.util.HashSet; 42 import java.util.List; 43 import java.util.Objects; 44 import java.util.Set; 45 46 import javax.lang.model.element.Element; 47 import javax.tools.JavaCompiler; 48 import javax.tools.JavaFileObject; 49 import javax.tools.StandardJavaFileManager; 50 import javax.tools.ToolProvider; 51 52 import com.sun.source.tree.CompilationUnitTree; 53 //import com.sun.source.util.JavacTask; // conflicts with toolbox.JavacTask 54 import com.sun.tools.javac.api.JavacTaskImpl; 55 import com.sun.tools.javac.code.Symbol.ModuleSymbol; 56 57 import toolbox.JarTask; 58 import toolbox.JavacTask; 59 import toolbox.Task; 60 import toolbox.ToolBox; 61 62 public class EdgeCases extends ModuleTestBase { 63 64 public static void main(String... args) throws Exception { 65 new EdgeCases().runTests(); 66 } 67 68 @Test 69 void testAddExportUndefinedModule(Path base) throws Exception { 70 Path src = base.resolve("src"); 71 tb.writeJavaFiles(src, "package test; import undef.Any; public class Test {}"); 72 Path classes = base.resolve("classes"); 73 tb.createDirectories(classes); 74 75 List<String> log = new JavacTask(tb) 76 .options("-XaddExports:undef/undef=ALL-UNNAMED", "-XDrawDiagnostics") 77 .outdir(classes) 78 .files(findJavaFiles(src)) 79 .run(Task.Expect.FAIL) 80 .writeAll() 81 .getOutputLines(Task.OutputKind.DIRECT); 82 83 List<String> expected = Arrays.asList("- compiler.err.cant.find.module: undef", 84 "Test.java:1:27: compiler.err.doesnt.exist: undef", 85 "2 errors"); 86 87 if (!expected.equals(log)) 88 throw new Exception("expected output not found: " + log); 89 } 90 91 @Test 92 void testModuleSymbolOutterMostClass(Path base) throws Exception { 93 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 94 try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) { 95 Path moduleSrc = base.resolve("module-src"); 96 Path m1 = moduleSrc.resolve("m1"); 97 98 tb.writeJavaFiles(m1, "module m1 { }"); 99 100 Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(findJavaFiles(moduleSrc)); 101 com.sun.source.util.JavacTask task = 102 (com.sun.source.util.JavacTask) compiler.getTask(null, fm, null, null, null, files); 103 104 task.analyze(); 105 106 ModuleSymbol msym = (ModuleSymbol) task.getElements().getModuleElement("m1"); 107 108 msym.outermostClass(); 109 } 110 } 111 112 @Test 113 void testParseEnterAnalyze(Path base) throws Exception { 114 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 115 try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) { 116 Path moduleSrc = base.resolve("module-src"); 117 Path m1 = moduleSrc.resolve("m1"); 118 119 tb.writeJavaFiles(m1, "module m1 { }", 120 "package p;", 121 "package p; class T { }"); 122 123 Path classes = base.resolve("classes"); 124 Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(findJavaFiles(moduleSrc)); 125 List<String> options = Arrays.asList("-d", classes.toString(), "-Xpkginfo:always"); 126 JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, fm, null, options, null, files); 127 128 Iterable<? extends CompilationUnitTree> parsed = task.parse(); 129 Iterable<? extends Element> entered = task.enter(parsed); 130 Iterable<? extends Element> analyzed = task.analyze(entered); 131 Iterable<? extends JavaFileObject> generatedFiles = task.generate(analyzed); 132 133 Set<String> generated = new HashSet<>(); 134 135 for (JavaFileObject jfo : generatedFiles) { 136 generated.add(jfo.getName()); 137 } 138 139 Set<String> expected = new HashSet<>( 140 Arrays.asList(Paths.get("testParseEnterAnalyze", "classes", "p", "package-info.class").toString(), 141 Paths.get("testParseEnterAnalyze", "classes", "module-info.class").toString(), 142 Paths.get("testParseEnterAnalyze", "classes", "p", "T.class").toString()) 143 ); 144 145 if (!Objects.equals(expected, generated)) 146 throw new AssertionError("Incorrect generated files: " + generated); 147 } 148 } 149 150 @Test 151 void testModuleImplicitModuleBoundaries(Path base) throws Exception { 152 Path src = base.resolve("src"); 153 Path src_m1 = src.resolve("m1"); 154 tb.writeJavaFiles(src_m1, 155 "module m1 { exports api1; }", 156 "package api1; public class Api1 { public void call() { } }"); 157 Path src_m2 = src.resolve("m2"); 158 tb.writeJavaFiles(src_m2, 159 "module m2 { requires m1; exports api2; }", 160 "package api2; public class Api2 { public static api1.Api1 get() { return null; } }"); 161 Path src_m3 = src.resolve("m3"); 162 tb.writeJavaFiles(src_m3, 163 "module m3 { requires m2; }", 164 "package test; public class Test { { api2.Api2.get().call(); api2.Api2.get().toString(); } }"); 165 Path classes = base.resolve("classes"); 166 tb.createDirectories(classes); 167 168 String log = new JavacTask(tb) 169 .options("-XDrawDiagnostics", 170 "-modulesourcepath", src.toString()) 171 .outdir(classes) 172 .files(findJavaFiles(src)) 173 .run(Task.Expect.FAIL) 174 .writeAll() 175 .getOutput(Task.OutputKind.DIRECT); 176 177 if (!log.contains("Test.java:1:52: compiler.err.not.def.access.class.intf.cant.access: call(), api1.Api1") || 178 !log.contains("Test.java:1:76: compiler.err.not.def.access.class.intf.cant.access: toString(), java.lang.Object")) 179 throw new Exception("expected output not found"); 180 } 181 182 @Test 183 void testAssignClassToAutomaticModule(Path base) throws Exception { 184 //check that if a ClassSymbol belongs to an automatic module, it is properly assigned and not 185 //duplicated when being accessed through a classfile. 186 Path automaticSrc = base.resolve("automaticSrc"); 187 tb.writeJavaFiles(automaticSrc, "package api1; public class Api1 {}"); 188 Path automaticClasses = base.resolve("automaticClasses"); 189 tb.createDirectories(automaticClasses); 190 191 String automaticLog = new JavacTask(tb) 192 .outdir(automaticClasses) 193 .files(findJavaFiles(automaticSrc)) 194 .run() 195 .writeAll() 196 .getOutput(Task.OutputKind.DIRECT); 197 198 if (!automaticLog.isEmpty()) 199 throw new Exception("expected output not found: " + automaticLog); 200 201 Path modulePath = base.resolve("module-path"); 202 203 Files.createDirectories(modulePath); 204 205 Path automaticJar = modulePath.resolve("m1-1.0.jar"); 206 207 new JarTask(tb, automaticJar) 208 .baseDir(automaticClasses) 209 .files("api1/Api1.class") 210 .run(); 211 212 Path src = base.resolve("src"); 213 Path src_m2 = src.resolve("m2"); 214 tb.writeJavaFiles(src_m2, 215 "module m2 { requires m1; exports api2; }", 216 "package api2; public class Api2 { public static api1.Api1 get() { return null; } }"); 217 Path src_m3 = src.resolve("m3"); 218 tb.writeJavaFiles(src_m3, 219 "module m3 { requires m1; requires m2; }", 220 "package test; public class Test { { api2.Api2.get(); api1.Api1 a1; } }"); 221 Path classes = base.resolve("classes"); 222 tb.createDirectories(classes); 223 224 new JavacTask(tb) 225 .options("-modulepath", modulePath.toString(), 226 "-modulesourcepath", src.toString()) 227 .outdir(classes) 228 .files(findJavaFiles(src_m2)) 229 .run() 230 .writeAll(); 231 232 new JavacTask(tb) 233 .options("-modulepath", modulePath.toString(), 234 "-modulesourcepath", src.toString()) 235 .outdir(classes) 236 .files(findJavaFiles(src_m3)) 237 .run() 238 .writeAll(); 239 } 240 241 @Test 242 void testEmptyImplicitModuleInfo(Path base) throws Exception { 243 Path src = base.resolve("src"); 244 Path src_m1 = src.resolve("m1"); 245 Files.createDirectories(src_m1); 246 try (Writer w = Files.newBufferedWriter(src_m1.resolve("module-info.java"))) {} 247 tb.writeJavaFiles(src_m1, 248 "package test; public class Test {}"); 249 Path classes = base.resolve("classes"); 250 tb.createDirectories(classes); 251 252 new JavacTask(tb) 253 .options("-sourcepath", src_m1.toString(), 254 "-XDrawDiagnostics") 255 .outdir(classes) 256 .files(findJavaFiles(src_m1.resolve("test"))) 257 .run(Task.Expect.FAIL) 258 .writeAll(); 259 260 tb.writeJavaFiles(src_m1, 261 "module m1 {}"); 262 263 new JavacTask(tb) 264 .options("-sourcepath", src_m1.toString()) 265 .outdir(classes) 266 .files(findJavaFiles(src_m1.resolve("test"))) 267 .run() 268 .writeAll(); 269 270 } 271 272 }