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