1 /* 2 * Copyright (c) 2014, 2020, 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 8028563 8245147 8245586 8257453 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 import java.util.function.Consumer; 47 48 /* 49 * If not explicitly specified the latest source and latest target 50 * values are the defaults. If explicitly specified, the target value 51 * has to be greater than or equal to the source value. 52 */ 53 public class Versions { 54 55 protected JavaCompiler javacompiler; 56 protected int failedCases; 57 Versions()58 public Versions() throws IOException { 59 javacompiler = ToolProvider.getSystemJavaCompiler(); 60 genSourceFiles(); 61 failedCases = 0; 62 } 63 main(String... args)64 public static void main(String... args) throws IOException { 65 Versions versions = new Versions(); 66 versions.run(); 67 } 68 69 public static final Set<String> RETIRED_SOURCES = 70 Set.of("1.2", "1.3", "1.4", "1.5", "1.6"); 71 72 public static final Set<String> VALID_SOURCES = 73 Set.of("1.7", "1.8", "1.9", "1.10", "11", "12", "13", "14", "15", "16", "17"); 74 75 public static final String LATEST_MAJOR_VERSION = "61.0"; 76 77 static enum SourceTarget { 78 SEVEN(true, "51.0", "7", Versions::checksrc7), 79 EIGHT(true, "52.0", "8", Versions::checksrc8), 80 NINE(true, "53.0", "9", Versions::checksrc9), 81 TEN(true, "54.0", "10", Versions::checksrc10), 82 ELEVEN(false, "55.0", "11", Versions::checksrc11), 83 TWELVE(false, "56.0", "12", Versions::checksrc12), 84 THIRTEEN(false, "57.0", "13", Versions::checksrc13), 85 FOURTEEN(false, "58.0", "14", Versions::checksrc14), 86 FIFTEEN(false, "59.0", "15", Versions::checksrc15), 87 SIXTEEN(false, "60.0", "16", Versions::checksrc16), 88 SEVENTEEN(false, "61.0", "17", Versions::checksrc17); 89 90 private final boolean dotOne; 91 private final String classFileVer; 92 private final String target; 93 private final BiConsumer<Versions, List<String>> checker; 94 SourceTarget(boolean dotOne, String classFileVer, String target, BiConsumer<Versions, List<String>> checker)95 private SourceTarget(boolean dotOne, String classFileVer, String target, 96 BiConsumer<Versions, List<String>> checker) { 97 this.dotOne = dotOne; 98 this.classFileVer = classFileVer; 99 this.target = target; 100 this.checker = checker; 101 } 102 checksrc(Versions version, List<String> args)103 public void checksrc(Versions version, List<String> args) { 104 checker.accept(version, args); 105 } 106 dotOne()107 public boolean dotOne() { 108 return dotOne; 109 } 110 classFileVer()111 public String classFileVer() { 112 return classFileVer; 113 } 114 target()115 public String target() { 116 return target; 117 } 118 } 119 run()120 void run() { 121 String TC = ""; 122 System.out.println("Version.java: Starting"); 123 124 check(LATEST_MAJOR_VERSION); 125 for (String source : VALID_SOURCES) { 126 check(LATEST_MAJOR_VERSION, List.of("-source " + source)); 127 } 128 129 // Verify that a -source value less than a -target value is 130 // accepted and that the resulting class files are dependent 131 // on the target setting alone. 132 SourceTarget[] sourceTargets = SourceTarget.values(); 133 for (int i = 0; i < sourceTargets.length; i++) { 134 SourceTarget st = sourceTargets[i]; 135 String classFileVer = st.classFileVer(); 136 String target = st.target(); 137 boolean dotOne = st.dotOne(); 138 check_source_target(dotOne, List.of(classFileVer, target, target)); 139 for (int j = i - 1; j >= 0; j--) { 140 String source = sourceTargets[j].target(); 141 check_source_target(dotOne, List.of(classFileVer, source, target)); 142 } 143 } 144 145 // Verify acceptance of different combinations of -source N, 146 // -target M; N <= M 147 for (int i = 0; i < sourceTargets.length; i++) { 148 SourceTarget st = sourceTargets[i]; 149 150 st.checksrc(this, List.of("-source " + st.target())); 151 st.checksrc(this, List.of("-source " + st.target(), "-target " + st.target())); 152 153 if (st.dotOne()) { 154 st.checksrc(this, List.of("-source 1." + st.target())); 155 st.checksrc(this, List.of("-source 1." + st.target(), "-target 1." + st.target())); 156 } 157 158 if (i == sourceTargets.length - 1) { 159 // Can use -target without -source setting only for 160 // most recent target since the most recent source is 161 // the default. 162 st.checksrc(this, List.of("-target " + st.target())); 163 164 if (!st.classFileVer().equals(LATEST_MAJOR_VERSION)) { 165 throw new RuntimeException(st + 166 "does not have class file version" + 167 LATEST_MAJOR_VERSION); 168 } 169 } 170 } 171 172 // Verify that -source N -target (N-1) is rejected 173 for (int i = 1 /* Skip zeroth value */; i < sourceTargets.length; i++) { 174 fail(List.of("-source " + sourceTargets[i].target(), 175 "-target " + sourceTargets[i-1].target(), 176 "Base.java")); 177 } 178 179 // Previously supported source/target values 180 for (String source : RETIRED_SOURCES) { 181 fail(List.of("-source " + source, "-target " + source, "Base.java")); 182 } 183 184 if (failedCases > 0) { 185 System.err.println("failedCases = " + String.valueOf(failedCases)); 186 throw new Error("Test failed"); 187 } 188 189 } 190 printargs(String fname, List<String> args)191 protected void printargs(String fname, List<String> args) { 192 System.out.printf("test: %s", fname); 193 for (String onearg : args) { 194 System.out.printf(" %s", onearg); 195 } 196 System.out.printf("\n", fname); 197 } 198 check_source_target(boolean dotOne, List<String> args)199 protected void check_source_target(boolean dotOne, List<String> args) { 200 printargs("check_source_target", args); 201 check_target(dotOne, List.of(args.get(0), args.get(1), args.get(2))); 202 if (dotOne) { 203 check_target(dotOne, List.of(args.get(0), "1." + args.get(1), args.get(2))); 204 } 205 } 206 check_target(boolean dotOne, List<String> args)207 protected void check_target(boolean dotOne, List<String> args) { 208 check(args.get(0), List.of("-source " + args.get(1), "-target " + args.get(2))); 209 if (dotOne) { 210 check(args.get(0), List.of("-source " + args.get(1), "-target 1." + args.get(2))); 211 } 212 } 213 check(String major)214 protected void check(String major) { 215 check(major, List.of()); 216 } 217 check(String major, List<String> args)218 protected void check(String major, List<String> args) { 219 printargs("check", args); 220 List<String> jcargs = new ArrayList<>(); 221 jcargs.add("-Xlint:-options"); 222 223 // add in args conforming to List requrements of JavaCompiler 224 for (String onearg : args) { 225 String[] fields = onearg.split(" "); 226 for (String onefield : fields) { 227 jcargs.add(onefield); 228 } 229 } 230 231 boolean creturn = compile("Base.java", jcargs); 232 if (!creturn) { 233 // compilation errors note and return.. assume no class file 234 System.err.println("check: Compilation Failed"); 235 System.err.println("\t classVersion:\t" + major); 236 System.err.println("\t arguments:\t" + jcargs); 237 failedCases++; 238 239 } else if (!checkClassFileVersion("Base.class", major)) { 240 failedCases++; 241 } 242 } 243 checksrc7(List<String> args)244 protected void checksrc7(List<String> args) { 245 printargs("checksrc7", args); 246 expectedPass(args, List.of("New7.java")); 247 expectedFail(args, List.of("New8.java")); 248 } 249 checksrc8(List<String> args)250 protected void checksrc8(List<String> args) { 251 printargs("checksrc8", args); 252 expectedPass(args, List.of("New7.java", "New8.java")); 253 expectedFail(args, List.of("New10.java")); 254 } 255 checksrc9(List<String> args)256 protected void checksrc9(List<String> args) { 257 printargs("checksrc9", args); 258 expectedPass(args, List.of("New7.java", "New8.java")); 259 expectedFail(args, List.of("New10.java")); 260 } 261 checksrc10(List<String> args)262 protected void checksrc10(List<String> args) { 263 printargs("checksrc10", args); 264 expectedPass(args, List.of("New7.java", "New8.java", "New10.java")); 265 expectedFail(args, List.of("New11.java")); 266 } 267 checksrc11(List<String> args)268 protected void checksrc11(List<String> args) { 269 printargs("checksrc11", args); 270 expectedPass(args, List.of("New7.java", "New8.java", "New10.java", "New11.java")); 271 expectedFail(args, List.of("New14.java")); 272 } 273 checksrc12(List<String> args)274 protected void checksrc12(List<String> args) { 275 printargs("checksrc12", args); 276 expectedPass(args, List.of("New7.java", "New8.java", "New10.java", "New11.java")); 277 expectedFail(args, List.of("New14.java")); 278 } 279 checksrc13(List<String> args)280 protected void checksrc13(List<String> args) { 281 printargs("checksrc13", args); 282 expectedPass(args, List.of("New7.java", "New8.java", "New10.java", "New11.java")); 283 expectedFail(args, List.of("New14.java")); 284 } 285 checksrc14(List<String> args)286 protected void checksrc14(List<String> args) { 287 printargs("checksrc14", args); 288 expectedPass(args, List.of("New7.java", "New8.java", "New10.java", "New11.java", 289 "New14.java")); 290 expectedFail(args, List.of("New15.java")); 291 } 292 checksrc15(List<String> args)293 protected void checksrc15(List<String> args) { 294 printargs("checksrc15", args); 295 expectedPass(args, List.of("New7.java", "New8.java", "New10.java", "New11.java", 296 "New14.java", "New15.java")); 297 expectedFail(args, List.of("New16.java")); 298 } 299 checksrc16(List<String> args)300 protected void checksrc16(List<String> args) { 301 printargs("checksrc16", args); 302 expectedPass(args, List.of("New7.java", "New8.java", "New10.java", "New11.java", 303 "New14.java", "New15.java", "New16.java")); 304 // Add expectedFail after new language features added in a later release. 305 } 306 checksrc17(List<String> args)307 protected void checksrc17(List<String> args) { 308 printargs("checksrc17", args); 309 expectedPass(args, List.of("New7.java", "New8.java", "New10.java", "New11.java", 310 "New14.java", "New15.java", "New16.java")); 311 // Add expectedFail after new language features added in a later release. 312 } 313 expected(List<String> args, List<String> fileNames, Consumer<List<String>> passOrFail)314 protected void expected(List<String> args, List<String> fileNames, 315 Consumer<List<String>> passOrFail) { 316 ArrayList<String> fullArguments = new ArrayList<>(args); 317 // Issue compile with each filename in turn. 318 for(String fileName : fileNames) { 319 fullArguments.add(fileName); 320 passOrFail.accept(fullArguments); 321 fullArguments.remove(fullArguments.size() - 1); 322 } 323 } 324 expectedPass(List<String> args, List<String> fileNames)325 protected void expectedPass(List<String> args, List<String> fileNames) { 326 expected(args, fileNames, this::pass); 327 } 328 expectedFail(List<String> args, List<String> fileNames)329 protected void expectedFail(List<String> args, List<String> fileNames) { 330 expected(args, fileNames, this::fail); 331 } 332 pass(List<String> args)333 protected void pass(List<String> args) { 334 printargs("pass", args); 335 336 List<String> jcargs = new ArrayList<>(); 337 jcargs.add("-Xlint:-options"); 338 339 // add in args conforming to List requrements of JavaCompiler 340 for (String onearg : args) { 341 String[] fields = onearg.split(" "); 342 for (String onefield : fields) { 343 jcargs.add(onefield); 344 } 345 } 346 347 // empty list is error 348 if (jcargs.isEmpty()) { 349 System.err.println("error: test error in pass() - No arguments"); 350 System.err.println("\t arguments:\t" + jcargs); 351 failedCases++; 352 return; 353 } 354 355 // the last argument is the filename *.java 356 String filename = jcargs.get(jcargs.size() - 1); 357 jcargs.remove(jcargs.size() - 1); 358 359 boolean creturn = compile(filename, jcargs); 360 // expect a compilation failure, failure if otherwise 361 if (!creturn) { 362 System.err.println("pass: Compilation erroneously failed"); 363 System.err.println("\t arguments:\t" + jcargs); 364 System.err.println("\t file :\t" + filename); 365 failedCases++; 366 367 } 368 369 } 370 fail(List<String> args)371 protected void fail(List<String> args) { 372 printargs("fail", args); 373 374 List<String> jcargs = new ArrayList<>(); 375 jcargs.add("-Xlint:-options"); 376 377 // add in args conforming to List requrements of JavaCompiler 378 for (String onearg : args) { 379 String[] fields = onearg.split(" "); 380 for (String onefield : fields) { 381 jcargs.add(onefield); 382 } 383 } 384 385 // empty list is error 386 if (jcargs.isEmpty()) { 387 System.err.println("error: test error in fail()- No arguments"); 388 System.err.println("\t arguments:\t" + jcargs); 389 failedCases++; 390 return; 391 } 392 393 // the last argument is the filename *.java 394 String filename = jcargs.get(jcargs.size() - 1); 395 jcargs.remove(jcargs.size() - 1); 396 397 boolean creturn = compile(filename, jcargs); 398 // expect a compilation failure, failure if otherwise 399 if (creturn) { 400 System.err.println("fail: Compilation erroneously succeeded"); 401 System.err.println("\t arguments:\t" + jcargs); 402 System.err.println("\t file :\t" + filename); 403 failedCases++; 404 } 405 } 406 compile(String sourceFile, List<String> options)407 protected boolean compile(String sourceFile, List<String> options) { 408 JavaCompiler.CompilationTask jctask; 409 try (StandardJavaFileManager fm = javacompiler.getStandardFileManager(null, null, null)) { 410 Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(sourceFile); 411 412 jctask = javacompiler.getTask( 413 null, // Writer 414 fm, // JavaFileManager 415 null, // DiagnosticListener 416 options, // Iterable<String> 417 null, // Iterable<String> classes 418 files); // Iterable<? extends JavaFileObject> 419 420 try { 421 return jctask.call(); 422 } catch (IllegalStateException e) { 423 System.err.println(e); 424 return false; 425 } 426 } catch (IOException e) { 427 throw new Error(e); 428 } 429 } 430 writeSourceFile(String fileName, String body)431 protected void writeSourceFile(String fileName, String body) throws IOException{ 432 try (Writer fw = new FileWriter(fileName)) { 433 fw.write(body); 434 } 435 } 436 genSourceFiles()437 protected void genSourceFiles() throws IOException{ 438 /* Create a file that executes with all supported versions. */ 439 writeSourceFile("Base.java","public class Base { }\n"); 440 441 /* 442 * Create a file with a new feature in 7, not in 6 : "<>" 443 */ 444 writeSourceFile("New7.java", 445 """ 446 import java.util.List; 447 import java.util.ArrayList; 448 class New7 { List<String> s = new ArrayList<>(); } 449 """ 450 ); 451 452 /* 453 * Create a file with a new feature in 8, not in 7 : lambda 454 */ 455 writeSourceFile("New8.java", 456 """ 457 public class New8 { 458 void m() { 459 new Thread(() -> { }); 460 } 461 } 462 """ 463 ); 464 465 /* 466 * Create a file with a new feature in 10, not in 9 : var 467 */ 468 writeSourceFile("New10.java", 469 """ 470 public class New10 { 471 void m() { 472 var tmp = new Thread(() -> { }); 473 } 474 } 475 """ 476 ); 477 478 /* 479 * Create a file with a new feature in 11, not in 10 : var for lambda parameters 480 */ 481 writeSourceFile("New11.java", 482 """ 483 public class New11 { 484 static java.util.function.Function<String,String> f = (var x) -> x.substring(0); 485 void m(String name) { 486 var tmp = new Thread(() -> { }, f.apply(name)); 487 } 488 } 489 """ 490 ); 491 492 /* 493 * Create a file with a new feature in 14, not in 13 : switch expressions 494 */ 495 writeSourceFile("New14.java", 496 """ 497 public class New14 { 498 static { 499 int i = 5; 500 System.out.println( 501 switch(i) { 502 case 0 -> false; 503 default -> true; 504 } 505 ); 506 } 507 } 508 """ 509 ); 510 511 /* 512 * Create a file with a new feature in 15, not in 14 : text blocks 513 */ 514 writeSourceFile("New15.java", 515 """ 516 public class New15 { 517 public static final String s = 518 \"\"\" 519 Hello, World. 520 \"\"\" 521 ; 522 } 523 """ 524 ); 525 526 /* 527 * Create a file with a new feature in 16, not in 15 : records 528 */ 529 writeSourceFile("New16.java", 530 """ 531 public class New16 { 532 public record Record(double rpm) { 533 public static final Record LONG_PLAY = new Record(100.0/3.0); 534 } 535 } 536 """ 537 ); 538 } 539 checkClassFileVersion(String filename,String classVersionNumber)540 protected boolean checkClassFileVersion 541 (String filename,String classVersionNumber) { 542 ByteBuffer bb = ByteBuffer.allocate(1024); 543 try (FileChannel fc = new FileInputStream(filename).getChannel()) { 544 bb.clear(); 545 if (fc.read(bb) < 0) 546 throw new IOException("Could not read from file : " + filename); 547 bb.flip(); 548 int minor = bb.getShort(4); 549 int major = bb.getShort(6); 550 String fileVersion = major + "." + minor; 551 if (fileVersion.equals(classVersionNumber)) { 552 return true; 553 } else { 554 System.err.println("checkClassFileVersion : Failed"); 555 System.err.println("\tclassfile version mismatch"); 556 System.err.println("\texpected : " + classVersionNumber); 557 System.err.println("\tfound : " + fileVersion); 558 return false; 559 } 560 } 561 catch (IOException e) { 562 System.err.println("checkClassFileVersion : Failed"); 563 System.err.println("\terror :\t" + e.getMessage()); 564 System.err.println("\tfile:\tfilename"); 565 } 566 return false; 567 } 568 } 569 570