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