1 /* 2 * Copyright (c) 2005, 2017, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.lang.model; 27 28 import java.util.Collections; 29 import java.util.Set; 30 import java.util.HashSet; 31 32 /** 33 * Source versions of the Java™ programming language. 34 * 35 * See the appropriate edition of 36 * <cite>The Java™ Language Specification</cite> 37 * for information about a particular source version. 38 * 39 * <p>Note that additional source version constants will be added to 40 * model future releases of the language. 41 * 42 * @author Joseph D. Darcy 43 * @author Scott Seligman 44 * @author Peter von der Ahé 45 * @since 1.6 46 */ 47 public enum SourceVersion { 48 /* 49 * Summary of language evolution 50 * 1.1: nested classes 51 * 1.2: strictfp 52 * 1.3: no changes 53 * 1.4: assert 54 * 1.5: annotations, generics, autoboxing, var-args... 55 * 1.6: no changes 56 * 1.7: diamond syntax, try-with-resources, etc. 57 * 1.8: lambda expressions and default methods 58 * 9: modules, small cleanups to 1.7 and 1.8 changes 59 * 10: to-be-determined changes 60 */ 61 62 /** 63 * The original version. 64 * 65 * The language described in 66 * <cite>The Java™ Language Specification, First Edition</cite>. 67 */ 68 RELEASE_0, 69 70 /** 71 * The version recognized by the Java Platform 1.1. 72 * 73 * The language is {@code RELEASE_0} augmented with nested classes as described in the 1.1 update to 74 * <cite>The Java™ Language Specification, First Edition</cite>. 75 */ 76 RELEASE_1, 77 78 /** 79 * The version recognized by the Java 2 Platform, Standard Edition, 80 * v 1.2. 81 * 82 * The language described in 83 * <cite>The Java™ Language Specification, 84 * Second Edition</cite>, which includes the {@code 85 * strictfp} modifier. 86 */ 87 RELEASE_2, 88 89 /** 90 * The version recognized by the Java 2 Platform, Standard Edition, 91 * v 1.3. 92 * 93 * No major changes from {@code RELEASE_2}. 94 */ 95 RELEASE_3, 96 97 /** 98 * The version recognized by the Java 2 Platform, Standard Edition, 99 * v 1.4. 100 * 101 * Added a simple assertion facility. 102 */ 103 RELEASE_4, 104 105 /** 106 * The version recognized by the Java 2 Platform, Standard 107 * Edition 5.0. 108 * 109 * The language described in 110 * <cite>The Java™ Language Specification, 111 * Third Edition</cite>. First release to support 112 * generics, annotations, autoboxing, var-args, enhanced {@code 113 * for} loop, and hexadecimal floating-point literals. 114 */ 115 RELEASE_5, 116 117 /** 118 * The version recognized by the Java Platform, Standard Edition 119 * 6. 120 * 121 * No major changes from {@code RELEASE_5}. 122 */ 123 RELEASE_6, 124 125 /** 126 * The version recognized by the Java Platform, Standard Edition 127 * 7. 128 * 129 * Additions in this release include, diamond syntax for 130 * constructors, {@code try}-with-resources, strings in switch, 131 * binary literals, and multi-catch. 132 * @since 1.7 133 */ 134 RELEASE_7, 135 136 /** 137 * The version recognized by the Java Platform, Standard Edition 138 * 8. 139 * 140 * Additions in this release include lambda expressions and default methods. 141 * @since 1.8 142 */ 143 RELEASE_8, 144 145 /** 146 * The version recognized by the Java Platform, Standard Edition 147 * 9. 148 * 149 * Additions in this release include modules and removal of a 150 * single underscore from the set of legal identifier names. 151 * 152 * @since 9 153 */ 154 RELEASE_9, 155 156 /** 157 * The version recognized by the Java Platform, Standard Edition 158 * 10. 159 * 160 * Additions in this release include local variable type 161 * inference, {@code "var"}. 162 * 163 * @since 10 164 */ 165 RELEASE_10; 166 167 // Note that when adding constants for newer releases, the 168 // behavior of latest() and latestSupported() must be updated too. 169 170 /** 171 * Returns the latest source version that can be modeled. 172 * 173 * @return the latest source version that can be modeled 174 */ 175 public static SourceVersion latest() { 176 return RELEASE_10; 177 } 178 179 private static final SourceVersion latestSupported = getLatestSupported(); 180 181 private static SourceVersion getLatestSupported() { 182 try { 183 String specVersion = System.getProperty("java.specification.version"); 184 185 switch (specVersion) { 186 case "10": 187 return RELEASE_10; 188 case "9": 189 case "1.9": 190 return RELEASE_9; 191 case "1.8": 192 return RELEASE_8; 193 case "1.7": 194 return RELEASE_7; 195 case "1.6": 196 return RELEASE_6; 197 } 198 } catch (SecurityException se) {} 199 200 return RELEASE_5; 201 } 202 203 /** 204 * Returns the latest source version fully supported by the 205 * current execution environment. {@code RELEASE_5} or later must 206 * be returned. 207 * 208 * @return the latest source version that is fully supported 209 */ 210 public static SourceVersion latestSupported() { 211 return latestSupported; 212 } 213 214 /** 215 * Returns whether or not {@code name} is a syntactically valid 216 * identifier (simple name) or keyword in the latest source 217 * version. The method returns {@code true} if the name consists 218 * of an initial character for which {@link 219 * Character#isJavaIdentifierStart(int)} returns {@code true}, 220 * followed only by characters for which {@link 221 * Character#isJavaIdentifierPart(int)} returns {@code true}. 222 * This pattern matches regular identifiers, keywords, restricted 223 * keywords, and the literals {@code "true"}, {@code "false"}, 224 * {@code "null"}, and {@code "var"}. 225 * 226 * The method returns {@code false} for all other strings. 227 * 228 * @param name the string to check 229 * @return {@code true} if this string is a 230 * syntactically valid identifier or keyword, {@code false} 231 * otherwise. 232 */ 233 public static boolean isIdentifier(CharSequence name) { 234 String id = name.toString(); 235 236 if (id.length() == 0) { 237 return false; 238 } 239 int cp = id.codePointAt(0); 240 if (!Character.isJavaIdentifierStart(cp)) { 241 return false; 242 } 243 for (int i = Character.charCount(cp); 244 i < id.length(); 245 i += Character.charCount(cp)) { 246 cp = id.codePointAt(i); 247 if (!Character.isJavaIdentifierPart(cp)) { 248 return false; 249 } 250 } 251 return true; 252 } 253 254 /** 255 * Returns whether or not {@code name} is a syntactically valid 256 * qualified name in the latest source version. Unlike {@link 257 * #isIdentifier isIdentifier}, this method returns {@code false} 258 * for keywords, boolean literals, and the null literal. 259 * 260 * This method returns {@code true} for <i>restricted 261 * keywords</i>. 262 * 263 * @param name the string to check 264 * @return {@code true} if this string is a 265 * syntactically valid name, {@code false} otherwise. 266 * @jls 3.9 Keywords 267 * @jls 6.2 Names and Identifiers 268 */ 269 public static boolean isName(CharSequence name) { 270 return isName(name, latest()); 271 } 272 273 /** 274 * Returns whether or not {@code name} is a syntactically valid 275 * qualified name in the given source version. Unlike {@link 276 * #isIdentifier isIdentifier}, this method returns {@code false} 277 * for keywords, boolean literals, and the null literal. 278 * 279 * This method returns {@code true} for <i>restricted 280 * keywords</i>. 281 * 282 * This method returns {@code false} if {@code "var"} is a 283 * trailing simple name component of the qualified name argument 284 * and {@code "var"} is used for local variable type inference in 285 * the argument version. 286 * 287 * @param name the string to check 288 * @param version the version to use 289 * @return {@code true} if this string is a 290 * syntactically valid name, {@code false} otherwise. 291 * @jls 3.9 Keywords 292 * @jls 6.2 Names and Identifiers 293 * @since 9 294 */ 295 public static boolean isName(CharSequence name, SourceVersion version) { 296 String id = name.toString(); 297 298 String[] splits = id.split("\\.", -1); 299 for(String s : splits) { 300 if (!isIdentifier(s) || isKeyword(s, version)) 301 return false; 302 } 303 // The name "var" cannot be used for a type as of release 10. 304 if (version.compareTo(RELEASE_10) >= 0 && 305 splits[splits.length - 1].equals("var") ) { 306 return false; 307 } 308 return true; 309 } 310 311 /** 312 * Returns whether or not {@code s} is a keyword, boolean literal, 313 * or null literal in the latest source version. 314 * This method returns {@code false} for <i>restricted 315 * keywords</i> and {@code var}. 316 * 317 * @param s the string to check 318 * @return {@code true} if {@code s} is a keyword, or boolean 319 * literal, or null literal, {@code false} otherwise. 320 * @jls 3.9 Keywords 321 * @jls 3.10.3 Boolean Literals 322 * @jls 3.10.7 The Null Literal 323 */ 324 public static boolean isKeyword(CharSequence s) { 325 return isKeyword(s, latest()); 326 } 327 328 /** 329 * Returns whether or not {@code s} is a keyword, boolean literal, 330 * or null literal in the given source version. 331 * This method returns {@code false} for <i>restricted 332 * keywords</i> and {@code var}. 333 * 334 * @param s the string to check 335 * @param version the version to use 336 * @return {@code true} if {@code s} is a keyword, or boolean 337 * literal, or null literal, {@code false} otherwise. 338 * @jls 3.9 Keywords 339 * @jls 3.10.3 Boolean Literals 340 * @jls 3.10.7 The Null Literal 341 * @since 9 342 */ 343 public static boolean isKeyword(CharSequence s, SourceVersion version) { 344 String id = s.toString(); 345 switch(id) { 346 // A trip through history 347 case "strictfp": 348 return version.compareTo(RELEASE_2) >= 0; 349 350 case "assert": 351 return version.compareTo(RELEASE_4) >= 0; 352 353 case "enum": 354 return version.compareTo(RELEASE_5) >= 0; 355 356 case "_": 357 return version.compareTo(RELEASE_9) >= 0; 358 359 // Keywords common across versions 360 361 // Modifiers 362 case "public": case "protected": case "private": 363 case "abstract": case "static": case "final": 364 case "transient": case "volatile": case "synchronized": 365 case "native": 366 367 // Declarations 368 case "class": case "interface": case "extends": 369 case "package": case "throws": case "implements": 370 371 // Primitive types and void 372 case "boolean": case "byte": case "char": 373 case "short": case "int": case "long": 374 case "float": case "double": 375 case "void": 376 377 // Control flow 378 case "if": case "else": 379 case "try": case "catch": case "finally": 380 case "do": case "while": 381 case "for": case "continue": 382 case "switch": case "case": case "default": 383 case "break": case "throw": case "return": 384 385 // Other keywords 386 case "this": case "new": case "super": 387 case "import": case "instanceof": 388 389 // Forbidden! 390 case "goto": case "const": 391 392 // literals 393 case "null": case "true": case "false": 394 return true; 395 396 default: 397 return false; 398 } 399 } 400 }