1 /* 2 * Copyright (c) 2014, 2018, 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 4981566 5028634 5094412 6304984 7025786 7025789 8001112 8028545 8000961 8030610 8028546 8188870 8173382 8173382 8193290 8205619 27 * @summary Check interpretation of -target and -source options 28 * @modules java.compiler 29 * jdk.compiler 30 * @run main Versions 31 */ 32 33 import java.io.*; 34 import java.nio.*; 35 import java.nio.channels.*; 36 37 import javax.tools.JavaCompiler; 38 import javax.tools.ToolProvider; 39 import javax.tools.JavaFileObject; 40 import javax.tools.StandardJavaFileManager; 41 import java.util.List; 42 import java.util.ArrayList; 43 import java.util.Arrays; 44 import java.util.Set; 45 import java.util.function.BiConsumer; 46 47 /* 48 * If not explicitly specified the latest source and latest target 49 * values are the defaults. If explicitly specified, the target value 50 * has to be greater than or equal to the source value. 51 */ 52 public class Versions { 53 54 protected JavaCompiler javacompiler; 55 protected int failedCases; 56 57 public Versions() throws IOException { 58 javacompiler = ToolProvider.getSystemJavaCompiler(); 59 genSourceFiles(); 60 failedCases = 0; 61 } 62 63 public static void main(String... args) throws IOException { 64 Versions versions = new Versions(); 65 versions.run(); 66 } 67 68 public static final Set<String> RETIRED_SOURCES = 69 Set.of("1.2", "1.3", "1.4", "1.5" /*, 1.6 */); 70 71 public static final Set<String> VALID_SOURCES = 72 Set.of("1.7", "1.8", "1.9", "1.10", "11", "12"); 73 74 public static final String LATEST_MAJOR_VERSION = "56.0"; 75 76 static enum SourceTarget { 77 SEVEN(true, "51.0", "7", Versions::checksrc17), 78 EIGHT(true, "52.0", "8", Versions::checksrc18), 79 NINE(true, "53.0", "9", Versions::checksrc19), 80 TEN(true, "54.0", "10", Versions::checksrc110), 81 ELEVEN(false, "55.0", "11", Versions::checksrc111), 82 TWELVE(false, "56.0", "12", Versions::checksrc112); 83 84 private final boolean dotOne; 85 private final String classFileVer; 86 private final String target; 87 private final BiConsumer<Versions, String[]> checker; 88 89 private SourceTarget(boolean dotOne, String classFileVer, String target, 90 BiConsumer<Versions, String[]> checker) { 91 this.dotOne = dotOne; 92 this.classFileVer = classFileVer; 93 this.target = target; 94 this.checker = checker; 95 } 96 97 public void checksrc(Versions version, String... args) { 98 checker.accept(version, args); 99 } 100 101 public boolean dotOne() { 102 return dotOne; 103 } 104 105 public String classFileVer() { 106 return classFileVer; 107 } 108 109 public String target() { 110 return target; 111 } 112 } 113 114 void run() { 115 String TC = ""; 116 System.out.println("Version.java: Starting"); 117 118 check(LATEST_MAJOR_VERSION); 119 for (String source : VALID_SOURCES) { 120 check(LATEST_MAJOR_VERSION, "-source " + source); 121 } 122 123 // Verify that a -source value less than a -target value is 124 // accepted and that the resulting class files are dependent 125 // on the target setting alone. 126 SourceTarget[] sourceTargets = SourceTarget.values(); 127 for (int i = 0; i < sourceTargets.length; i++) { 128 SourceTarget st = sourceTargets[i]; 129 String classFileVer = st.classFileVer(); 130 String target = st.target(); 131 boolean dotOne = st.dotOne(); 132 check_source_target(dotOne, classFileVer, target, target); 133 for (int j = i; j > 0; j--) { 134 String source = sourceTargets[j].target(); 135 check_source_target(dotOne, classFileVer, source, target); 136 } 137 } 138 139 // Verify acceptance of different combinations of -source N, 140 // -target M; N <= M 141 for (int i = 0; i < sourceTargets.length; i++) { 142 SourceTarget st = sourceTargets[i]; 143 144 st.checksrc(this, "-source " + st.target()); 145 st.checksrc(this, "-source " + st.target(), "-target " + st.target()); 146 147 if (st.dotOne()) { 148 st.checksrc(this, "-source 1." + st.target()); 149 st.checksrc(this, "-source 1." + st.target(), "-target 1." + st.target()); 150 } 151 152 if (i == sourceTargets.length) { 153 // Can use -target without -source setting only for 154 // most recent target since the most recent source is 155 // the default. 156 st.checksrc(this, "-target " + st.target()); 157 158 if (!st.classFileVer().equals(LATEST_MAJOR_VERSION)) { 159 throw new RuntimeException(st + 160 "does not have class file version" + 161 LATEST_MAJOR_VERSION); 162 } 163 } 164 } 165 166 // Verify that -source N -target (N-1) is rejected 167 for (int i = 1 /* Skip zeroth value */; i < sourceTargets.length; i++) { 168 fail("-source " + sourceTargets[i].target(), 169 "-target " + sourceTargets[i-1].target(), 170 "Base.java"); 171 } 172 173 // Previously supported source/target values 174 for (String source : RETIRED_SOURCES) { 175 fail("-source " + source, "-target " + source, "Base.java"); 176 } 177 178 if (failedCases > 0) { 179 System.err.println("failedCases = " + String.valueOf(failedCases)); 180 throw new Error("Test failed"); 181 } 182 183 } 184 185 protected void printargs(String fname,String... args) { 186 System.out.printf("test: %s", fname); 187 for (String onearg : args) { 188 System.out.printf(" %s", onearg); 189 } 190 System.out.printf("\n", fname); 191 } 192 193 protected void check_source_target(boolean dotOne, String... args) { 194 printargs("check_source_target", args); 195 check_target(dotOne, args[0], args[1], args[2]); 196 if (dotOne) { 197 check_target(dotOne, args[0], "1." + args[1], args[2]); 198 } 199 } 200 201 protected void check_target(boolean dotOne, String... args) { 202 check(args[0], "-source " + args[1], "-target " + args[2]); 203 if (dotOne) { 204 check(args[0], "-source " + args[1], "-target 1." + args[2]); 205 } 206 } 207 208 protected void check(String major, String... args) { 209 printargs("check", args); 210 List<String> jcargs = new ArrayList<>(); 211 jcargs.add("-Xlint:-options"); 212 213 // add in args conforming to List requrements of JavaCompiler 214 for (String onearg : args) { 215 String[] fields = onearg.split(" "); 216 for (String onefield : fields) { 217 jcargs.add(onefield); 218 } 219 } 220 221 boolean creturn = compile("Base.java", jcargs); 222 if (!creturn) { 223 // compilation errors note and return.. assume no class file 224 System.err.println("check: Compilation Failed"); 225 System.err.println("\t classVersion:\t" + major); 226 System.err.println("\t arguments:\t" + jcargs); 227 failedCases++; 228 229 } else if (!checkClassFileVersion("Base.class", major)) { 230 failedCases++; 231 } 232 } 233 234 protected void checksrc17(String... args) { 235 printargs("checksrc17", args); 236 int asize = args.length; 237 String[] newargs = new String[asize+1]; 238 System.arraycopy(args, 0, newargs,0 , asize); 239 newargs[asize] = "New17.java"; 240 pass(newargs); 241 newargs[asize] = "New18.java"; 242 fail(newargs); 243 } 244 245 protected void checksrc18(String... args) { 246 printargs("checksrc18", args); 247 int asize = args.length; 248 String[] newargs = new String[asize+1]; 249 System.arraycopy(args, 0, newargs,0 , asize); 250 newargs[asize] = "New17.java"; 251 pass(newargs); 252 newargs[asize] = "New18.java"; 253 pass(newargs); 254 newargs[asize] = "New110.java"; 255 fail(newargs); 256 } 257 258 protected void checksrc19(String... args) { 259 printargs("checksrc19", args); 260 checksrc18(args); 261 } 262 263 protected void checksrc110(String... args) { 264 printargs("checksrc110", args); 265 int asize = args.length; 266 String[] newargs = new String[asize+1]; 267 System.arraycopy(args, 0, newargs,0 , asize); 268 newargs[asize] = "New17.java"; 269 pass(newargs); 270 newargs[asize] = "New18.java"; 271 pass(newargs); 272 newargs[asize] = "New110.java"; 273 pass(newargs); 274 } 275 276 protected void checksrc111(String... args) { 277 printargs("checksrc111", args); 278 int asize = args.length; 279 String[] newargs = new String[asize+1]; 280 System.arraycopy(args, 0, newargs,0 , asize); 281 newargs[asize] = "New17.java"; 282 pass(newargs); 283 newargs[asize] = "New18.java"; 284 pass(newargs); 285 newargs[asize] = "New110.java"; 286 pass(newargs); 287 newargs[asize] = "New111.java"; 288 pass(newargs); 289 } 290 291 protected void checksrc112(String... args) { 292 printargs("checksrc112", args); 293 checksrc111(args); 294 } 295 296 protected void pass(String... args) { 297 printargs("pass", args); 298 299 List<String> jcargs = new ArrayList<String>(); 300 jcargs.add("-Xlint:-options"); 301 302 // add in args conforming to List requrements of JavaCompiler 303 for (String onearg : args) { 304 String[] fields = onearg.split(" "); 305 for (String onefield : fields) { 306 jcargs.add(onefield); 307 } 308 } 309 310 // empty list is error 311 if (jcargs.isEmpty()) { 312 System.err.println("error: test error in pass() - No arguments"); 313 System.err.println("\t arguments:\t" + jcargs); 314 failedCases++; 315 return; 316 } 317 318 // the last argument is the filename *.java 319 String filename = jcargs.get(jcargs.size() - 1); 320 jcargs.remove(jcargs.size() - 1); 321 322 boolean creturn = compile(filename, jcargs); 323 // expect a compilation failure, failure if otherwise 324 if (!creturn) { 325 System.err.println("pass: Compilation erroneously failed"); 326 System.err.println("\t arguments:\t" + jcargs); 327 System.err.println("\t file :\t" + filename); 328 failedCases++; 329 330 } 331 332 } 333 334 protected void fail(String... args) { 335 printargs("fail", args); 336 337 List<String> jcargs = new ArrayList<String>(); 338 jcargs.add("-Xlint:-options"); 339 340 // add in args conforming to List requrements of JavaCompiler 341 for (String onearg : args) { 342 String[] fields = onearg.split(" "); 343 for (String onefield : fields) { 344 jcargs.add(onefield); 345 } 346 } 347 348 // empty list is error 349 if (jcargs.isEmpty()) { 350 System.err.println("error: test error in fail()- No arguments"); 351 System.err.println("\t arguments:\t" + jcargs); 352 failedCases++; 353 return; 354 } 355 356 // the last argument is the filename *.java 357 String filename = jcargs.get(jcargs.size() - 1); 358 jcargs.remove(jcargs.size() - 1); 359 360 boolean creturn = compile(filename, jcargs); 361 // expect a compilation failure, failure if otherwise 362 if (creturn) { 363 System.err.println("fail: Compilation erroneously succeeded"); 364 System.err.println("\t arguments:\t" + jcargs); 365 System.err.println("\t file :\t" + filename); 366 failedCases++; 367 } 368 } 369 370 protected boolean compile(String sourceFile, List<String>options) { 371 JavaCompiler.CompilationTask jctask; 372 try (StandardJavaFileManager fm = javacompiler.getStandardFileManager(null, null, null)) { 373 Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(sourceFile); 374 375 jctask = javacompiler.getTask( 376 null, // Writer 377 fm, // JavaFileManager 378 null, // DiagnosticListener 379 options, // Iterable<String> 380 null, // Iterable<String> classes 381 files); // Iterable<? extends JavaFileObject> 382 383 try { 384 return jctask.call(); 385 } catch (IllegalStateException e) { 386 System.err.println(e); 387 return false; 388 } 389 } catch (IOException e) { 390 throw new Error(e); 391 } 392 } 393 394 protected void writeSourceFile(String fileName, String body) throws IOException{ 395 try (Writer fw = new FileWriter(fileName)) { 396 fw.write(body); 397 } 398 } 399 400 protected void genSourceFiles() throws IOException{ 401 /* Create a file that executes with all supported versions. */ 402 writeSourceFile("Base.java","public class Base { }\n"); 403 404 /* 405 * Create a file with a new feature in 1.7, not in 1.6 : "<>" 406 */ 407 writeSourceFile("New17.java", 408 "import java.util.List;\n" + 409 "import java.util.ArrayList;\n" + 410 "class New17 { List<String> s = new ArrayList<>(); }\n" 411 ); 412 413 /* 414 * Create a file with a new feature in 1.8, not in 1.7 : lambda 415 */ 416 writeSourceFile("New18.java", 417 "public class New18 { \n" + 418 " void m() { \n" + 419 " new Thread(() -> { }); \n" + 420 " } \n" + 421 "} \n" 422 ); 423 424 /* 425 * Create a file with a new feature in 1.10, not in 1.9 : var 426 */ 427 writeSourceFile("New110.java", 428 "public class New110 { \n" + 429 " void m() { \n" + 430 " var tmp = new Thread(() -> { }); \n" + 431 " } \n" + 432 "} \n" 433 ); 434 435 /* 436 * Create a file with a new feature in 11, not in 10 : var for lambda parameters 437 */ 438 writeSourceFile("New111.java", 439 "public class New111 { \n" + 440 " static java.util.function.Function<String,String> f = (var x) -> x.substring(0);\n" + 441 " void m(String name) { \n" + 442 " var tmp = new Thread(() -> { }, f.apply(name)); \n" + 443 " } \n" + 444 "} \n" 445 ); 446 } 447 448 protected boolean checkClassFileVersion 449 (String filename,String classVersionNumber) { 450 ByteBuffer bb = ByteBuffer.allocate(1024); 451 try (FileChannel fc = new FileInputStream(filename).getChannel()) { 452 bb.clear(); 453 if (fc.read(bb) < 0) 454 throw new IOException("Could not read from file : " + filename); 455 bb.flip(); 456 int minor = bb.getShort(4); 457 int major = bb.getShort(6); 458 String fileVersion = major + "." + minor; 459 if (fileVersion.equals(classVersionNumber)) { 460 return true; 461 } else { 462 System.err.println("checkClassFileVersion : Failed"); 463 System.err.println("\tclassfile version mismatch"); 464 System.err.println("\texpected : " + classVersionNumber); 465 System.err.println("\tfound : " + fileVersion); 466 return false; 467 } 468 } 469 catch (IOException e) { 470 System.err.println("checkClassFileVersion : Failed"); 471 System.err.println("\terror :\t" + e.getMessage()); 472 System.err.println("\tfile:\tfilename"); 473 } 474 return false; 475 } 476 } 477