1 /* 2 * Copyright (c) 2014, 2019, 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 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", "13", "14", "15", "16"); 73 74 public static final String LATEST_MAJOR_VERSION = "60.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 THIRTEEN(false, "57.0", "13", Versions::checksrc113), 84 FOURTEEN(false, "58.0", "14", Versions::checksrc114), 85 FIFTEEN(false, "59.0", "15", Versions::checksrc115), 86 SIXTEEN(false, "60.0", "16", Versions::checksrc116); 87 88 private final boolean dotOne; 89 private final String classFileVer; 90 private final String target; 91 private final BiConsumer<Versions, String[]> checker; 92 93 private SourceTarget(boolean dotOne, String classFileVer, String target, 94 BiConsumer<Versions, String[]> checker) { 95 this.dotOne = dotOne; 96 this.classFileVer = classFileVer; 97 this.target = target; 98 this.checker = checker; 99 } 100 101 public void checksrc(Versions version, String... args) { 102 checker.accept(version, args); 103 } 104 105 public boolean dotOne() { 106 return dotOne; 107 } 108 109 public String classFileVer() { 110 return classFileVer; 111 } 112 113 public String target() { 114 return target; 115 } 116 } 117 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, "-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, classFileVer, target, target); 137 for (int j = i; j > 0; j--) { 138 String source = sourceTargets[j].target(); 139 check_source_target(dotOne, 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, "-source " + st.target()); 149 st.checksrc(this, "-source " + st.target(), "-target " + st.target()); 150 151 if (st.dotOne()) { 152 st.checksrc(this, "-source 1." + st.target()); 153 st.checksrc(this, "-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, "-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("-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("-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 189 protected void printargs(String fname,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 197 protected void check_source_target(boolean dotOne, String... args) { 198 printargs("check_source_target", args); 199 check_target(dotOne, args[0], args[1], args[2]); 200 if (dotOne) { 201 check_target(dotOne, args[0], "1." + args[1], args[2]); 202 } 203 } 204 205 protected void check_target(boolean dotOne, String... args) { 206 check(args[0], "-source " + args[1], "-target " + args[2]); 207 if (dotOne) { 208 check(args[0], "-source " + args[1], "-target 1." + args[2]); 209 } 210 } 211 212 protected void check(String major, String... args) { 213 printargs("check", args); 214 List<String> jcargs = new ArrayList<>(); 215 jcargs.add("-Xlint:-options"); 216 217 // add in args conforming to List requrements of JavaCompiler 218 for (String onearg : args) { 219 String[] fields = onearg.split(" "); 220 for (String onefield : fields) { 221 jcargs.add(onefield); 222 } 223 } 224 225 boolean creturn = compile("Base.java", jcargs); 226 if (!creturn) { 227 // compilation errors note and return.. assume no class file 228 System.err.println("check: Compilation Failed"); 229 System.err.println("\t classVersion:\t" + major); 230 System.err.println("\t arguments:\t" + jcargs); 231 failedCases++; 232 233 } else if (!checkClassFileVersion("Base.class", major)) { 234 failedCases++; 235 } 236 } 237 238 protected void checksrc17(String... args) { 239 printargs("checksrc17", args); 240 int asize = args.length; 241 String[] newargs = new String[asize+1]; 242 System.arraycopy(args, 0, newargs,0 , asize); 243 newargs[asize] = "New17.java"; 244 pass(newargs); 245 newargs[asize] = "New18.java"; 246 fail(newargs); 247 } 248 249 protected void checksrc18(String... args) { 250 printargs("checksrc18", args); 251 int asize = args.length; 252 String[] newargs = new String[asize+1]; 253 System.arraycopy(args, 0, newargs,0 , asize); 254 newargs[asize] = "New17.java"; 255 pass(newargs); 256 newargs[asize] = "New18.java"; 257 pass(newargs); 258 newargs[asize] = "New110.java"; 259 fail(newargs); 260 } 261 262 protected void checksrc19(String... args) { 263 printargs("checksrc19", args); 264 checksrc18(args); 265 } 266 267 protected void checksrc110(String... args) { 268 printargs("checksrc110", args); 269 int asize = args.length; 270 String[] newargs = new String[asize+1]; 271 System.arraycopy(args, 0, newargs,0 , asize); 272 newargs[asize] = "New17.java"; 273 pass(newargs); 274 newargs[asize] = "New18.java"; 275 pass(newargs); 276 newargs[asize] = "New110.java"; 277 pass(newargs); 278 } 279 280 protected void checksrc111(String... args) { 281 printargs("checksrc111", 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 pass(newargs); 291 newargs[asize] = "New111.java"; 292 pass(newargs); 293 } 294 295 protected void checksrc112(String... args) { 296 printargs("checksrc112", args); 297 checksrc111(args); 298 } 299 300 protected void checksrc113(String... args) { 301 printargs("checksrc113", args); 302 checksrc111(args); 303 } 304 305 protected void checksrc114(String... args) { 306 printargs("checksrc114", args); 307 checksrc111(args); 308 } 309 310 protected void checksrc115(String... args) { 311 printargs("checksrc115", args); 312 checksrc111(args); 313 } 314 315 // TODO: update with text blocks 316 protected void checksrc116(String... args) { 317 printargs("checksrc116", args); 318 checksrc111(args); 319 } 320 321 protected void pass(String... args) { 322 printargs("pass", args); 323 324 List<String> jcargs = new ArrayList<String>(); 325 jcargs.add("-Xlint:-options"); 326 327 // add in args conforming to List requrements of JavaCompiler 328 for (String onearg : args) { 329 String[] fields = onearg.split(" "); 330 for (String onefield : fields) { 331 jcargs.add(onefield); 332 } 333 } 334 335 // empty list is error 336 if (jcargs.isEmpty()) { 337 System.err.println("error: test error in pass() - No arguments"); 338 System.err.println("\t arguments:\t" + jcargs); 339 failedCases++; 340 return; 341 } 342 343 // the last argument is the filename *.java 344 String filename = jcargs.get(jcargs.size() - 1); 345 jcargs.remove(jcargs.size() - 1); 346 347 boolean creturn = compile(filename, jcargs); 348 // expect a compilation failure, failure if otherwise 349 if (!creturn) { 350 System.err.println("pass: Compilation erroneously failed"); 351 System.err.println("\t arguments:\t" + jcargs); 352 System.err.println("\t file :\t" + filename); 353 failedCases++; 354 355 } 356 357 } 358 359 protected void fail(String... args) { 360 printargs("fail", args); 361 362 List<String> jcargs = new ArrayList<String>(); 363 jcargs.add("-Xlint:-options"); 364 365 // add in args conforming to List requrements of JavaCompiler 366 for (String onearg : args) { 367 String[] fields = onearg.split(" "); 368 for (String onefield : fields) { 369 jcargs.add(onefield); 370 } 371 } 372 373 // empty list is error 374 if (jcargs.isEmpty()) { 375 System.err.println("error: test error in fail()- No arguments"); 376 System.err.println("\t arguments:\t" + jcargs); 377 failedCases++; 378 return; 379 } 380 381 // the last argument is the filename *.java 382 String filename = jcargs.get(jcargs.size() - 1); 383 jcargs.remove(jcargs.size() - 1); 384 385 boolean creturn = compile(filename, jcargs); 386 // expect a compilation failure, failure if otherwise 387 if (creturn) { 388 System.err.println("fail: Compilation erroneously succeeded"); 389 System.err.println("\t arguments:\t" + jcargs); 390 System.err.println("\t file :\t" + filename); 391 failedCases++; 392 } 393 } 394 395 protected boolean compile(String sourceFile, List<String>options) { 396 JavaCompiler.CompilationTask jctask; 397 try (StandardJavaFileManager fm = javacompiler.getStandardFileManager(null, null, null)) { 398 Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(sourceFile); 399 400 jctask = javacompiler.getTask( 401 null, // Writer 402 fm, // JavaFileManager 403 null, // DiagnosticListener 404 options, // Iterable<String> 405 null, // Iterable<String> classes 406 files); // Iterable<? extends JavaFileObject> 407 408 try { 409 return jctask.call(); 410 } catch (IllegalStateException e) { 411 System.err.println(e); 412 return false; 413 } 414 } catch (IOException e) { 415 throw new Error(e); 416 } 417 } 418 419 protected void writeSourceFile(String fileName, String body) throws IOException{ 420 try (Writer fw = new FileWriter(fileName)) { 421 fw.write(body); 422 } 423 } 424 425 protected void genSourceFiles() throws IOException{ 426 /* Create a file that executes with all supported versions. */ 427 writeSourceFile("Base.java","public class Base { }\n"); 428 429 /* 430 * Create a file with a new feature in 1.7, not in 1.6 : "<>" 431 */ 432 writeSourceFile("New17.java", 433 "import java.util.List;\n" + 434 "import java.util.ArrayList;\n" + 435 "class New17 { List<String> s = new ArrayList<>(); }\n" 436 ); 437 438 /* 439 * Create a file with a new feature in 1.8, not in 1.7 : lambda 440 */ 441 writeSourceFile("New18.java", 442 "public class New18 { \n" + 443 " void m() { \n" + 444 " new Thread(() -> { }); \n" + 445 " } \n" + 446 "} \n" 447 ); 448 449 /* 450 * Create a file with a new feature in 1.10, not in 1.9 : var 451 */ 452 writeSourceFile("New110.java", 453 "public class New110 { \n" + 454 " void m() { \n" + 455 " var tmp = new Thread(() -> { }); \n" + 456 " } \n" + 457 "} \n" 458 ); 459 460 /* 461 * Create a file with a new feature in 11, not in 10 : var for lambda parameters 462 */ 463 writeSourceFile("New111.java", 464 "public class New111 { \n" + 465 " static java.util.function.Function<String,String> f = (var x) -> x.substring(0);\n" + 466 " void m(String name) { \n" + 467 " var tmp = new Thread(() -> { }, f.apply(name)); \n" + 468 " } \n" + 469 "} \n" 470 ); 471 } 472 473 protected boolean checkClassFileVersion 474 (String filename,String classVersionNumber) { 475 ByteBuffer bb = ByteBuffer.allocate(1024); 476 try (FileChannel fc = new FileInputStream(filename).getChannel()) { 477 bb.clear(); 478 if (fc.read(bb) < 0) 479 throw new IOException("Could not read from file : " + filename); 480 bb.flip(); 481 int minor = bb.getShort(4); 482 int major = bb.getShort(6); 483 String fileVersion = major + "." + minor; 484 if (fileVersion.equals(classVersionNumber)) { 485 return true; 486 } else { 487 System.err.println("checkClassFileVersion : Failed"); 488 System.err.println("\tclassfile version mismatch"); 489 System.err.println("\texpected : " + classVersionNumber); 490 System.err.println("\tfound : " + fileVersion); 491 return false; 492 } 493 } 494 catch (IOException e) { 495 System.err.println("checkClassFileVersion : Failed"); 496 System.err.println("\terror :\t" + e.getMessage()); 497 System.err.println("\tfile:\tfilename"); 498 } 499 return false; 500 } 501 } 502