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