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