1 /* 2 * Copyright (c) 2005, 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. 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: local-variable type inference (var) 60 * 11: local-variable syntax for lambda parameters 61 * 12: no changes (switch expressions in preview) 62 * 13: TBD 63 */ 64 65 /** 66 * The original version. 67 * 68 * The language described in 69 * <cite>The Java™ Language Specification, First Edition</cite>. 70 */ 71 RELEASE_0, 72 73 /** 74 * The version recognized by the Java Platform 1.1. 75 * 76 * The language is {@code RELEASE_0} augmented with nested classes as described in the 1.1 update to 77 * <cite>The Java™ Language Specification, First Edition</cite>. 78 */ 79 RELEASE_1, 80 81 /** 82 * The version recognized by the Java 2 Platform, Standard Edition, 83 * v 1.2. 84 * 85 * The language described in 86 * <cite>The Java™ Language Specification, 87 * Second Edition</cite>, which includes the {@code 88 * strictfp} modifier. 89 */ 90 RELEASE_2, 91 92 /** 93 * The version recognized by the Java 2 Platform, Standard Edition, 94 * v 1.3. 95 * 96 * No major changes from {@code RELEASE_2}. 97 */ 98 RELEASE_3, 99 100 /** 101 * The version recognized by the Java 2 Platform, Standard Edition, 102 * v 1.4. 103 * 104 * Added a simple assertion facility. 105 */ 106 RELEASE_4, 107 108 /** 109 * The version recognized by the Java 2 Platform, Standard 110 * Edition 5.0. 111 * 112 * The language described in 113 * <cite>The Java™ Language Specification, 114 * Third Edition</cite>. First release to support 115 * generics, annotations, autoboxing, var-args, enhanced {@code 116 * for} loop, and hexadecimal floating-point literals. 117 */ 118 RELEASE_5, 119 120 /** 121 * The version recognized by the Java Platform, Standard Edition 122 * 6. 123 * 124 * No major changes from {@code RELEASE_5}. 125 */ 126 RELEASE_6, 127 128 /** 129 * The version recognized by the Java Platform, Standard Edition 130 * 7. 131 * 132 * Additions in this release include, diamond syntax for 133 * constructors, {@code try}-with-resources, strings in switch, 134 * binary literals, and multi-catch. 135 * @since 1.7 136 */ 137 RELEASE_7, 138 139 /** 140 * The version recognized by the Java Platform, Standard Edition 141 * 8. 142 * 143 * Additions in this release include lambda expressions and default methods. 144 * @since 1.8 145 */ 146 RELEASE_8, 147 148 /** 149 * The version recognized by the Java Platform, Standard Edition 150 * 9. 151 * 152 * Additions in this release include modules and removal of a 153 * single underscore from the set of legal identifier names. 154 * 155 * @since 9 156 */ 157 RELEASE_9, 158 159 /** 160 * The version recognized by the Java Platform, Standard Edition 161 * 10. 162 * 163 * Additions in this release include local-variable type inference 164 * ({@code var}). 165 * 166 * @since 10 167 */ 168 RELEASE_10, 169 170 /** 171 * The version recognized by the Java Platform, Standard Edition 172 * 11. 173 * 174 * Additions in this release include local-variable syntax for 175 * lambda parameters. 176 * 177 * @since 11 178 */ 179 RELEASE_11, 180 181 /** 182 * The version recognized by the Java Platform, Standard Edition 183 * 12. 184 * 185 * @since 12 186 */ 187 RELEASE_12, 188 189 /** 190 * The version recognized by the Java Platform, Standard Edition 191 * 13. 192 * 193 * @since 13 194 */ 195 RELEASE_13; 196 197 // Note that when adding constants for newer releases, the 198 // behavior of latest() and latestSupported() must be updated too. 199 200 /** 201 * Returns the latest source version that can be modeled. 202 * 203 * @return the latest source version that can be modeled 204 */ 205 public static SourceVersion latest() { 206 return RELEASE_13; 207 } 208 209 private static final SourceVersion latestSupported = getLatestSupported(); 210 211 /* 212 * The integer to release enum constant implemented by this method 213 * assumes the JEP 322: "Time-Based Release Versioning" scheme is 214 * in effect. This scheme began in JDK 10. If the JDK versioning 215 * scheme is revised, this method may need to be updated 216 * accordingly. 217 */ 218 private static SourceVersion getLatestSupported() { 219 int intVersion = Runtime.version().feature(); 220 return (intVersion >= 11) ? 221 valueOf("RELEASE_" + Math.min(13, intVersion)): 222 RELEASE_10; 223 } 224 225 /** 226 * Returns the latest source version fully supported by the 227 * current execution environment. {@code RELEASE_9} or later must 228 * be returned. 229 * 230 * @apiNote This method is included alongside {@link latest} to 231 * allow situations where the language model API is running on a 232 * platform version different than the latest version modeled by 233 * the API to be identified. One way that sort of situation can 234 * occur is if a IDE or similar tool is using the API to model 235 * source version <i>N</i> while running on platform version 236 * (<i>N</i> - 1). Running in this configuration is 237 * supported by the API. Running an API on platform versions 238 * earlier than (<i>N</i> - 1) or later than <i>N</i> 239 * may or may not work as an implementation detail. 240 * 241 * @return the latest source version that is fully supported 242 */ 243 public static SourceVersion latestSupported() { 244 return latestSupported; 245 } 246 247 /** 248 * Returns whether or not {@code name} is a syntactically valid 249 * identifier (simple name) or keyword in the latest source 250 * version. The method returns {@code true} if the name consists 251 * of an initial character for which {@link 252 * Character#isJavaIdentifierStart(int)} returns {@code true}, 253 * followed only by characters for which {@link 254 * Character#isJavaIdentifierPart(int)} returns {@code true}. 255 * This pattern matches regular identifiers, keywords, restricted 256 * keywords, and the literals {@code "true"}, {@code "false"}, 257 * {@code "null"}, and {@code "var"}. 258 * 259 * The method returns {@code false} for all other strings. 260 * 261 * @param name the string to check 262 * @return {@code true} if this string is a 263 * syntactically valid identifier or keyword, {@code false} 264 * otherwise. 265 */ 266 public static boolean isIdentifier(CharSequence name) { 267 String id = name.toString(); 268 269 if (id.length() == 0) { 270 return false; 271 } 272 int cp = id.codePointAt(0); 273 if (!Character.isJavaIdentifierStart(cp)) { 274 return false; 275 } 276 for (int i = Character.charCount(cp); 277 i < id.length(); 278 i += Character.charCount(cp)) { 279 cp = id.codePointAt(i); 280 if (!Character.isJavaIdentifierPart(cp)) { 281 return false; 282 } 283 } 284 return true; 285 } 286 287 /** 288 * Returns whether or not {@code name} is a syntactically valid 289 * qualified name in the latest source version. Unlike {@link 290 * #isIdentifier isIdentifier}, this method returns {@code false} 291 * for keywords, boolean literals, and the null literal. 292 * 293 * This method returns {@code true} for <i>restricted 294 * keywords</i> and {@code "var"}. 295 * 296 * @param name the string to check 297 * @return {@code true} if this string is a 298 * syntactically valid name, {@code false} otherwise. 299 * @jls 3.9 Keywords 300 * @jls 6.2 Names and Identifiers 301 */ 302 public static boolean isName(CharSequence name) { 303 return isName(name, latest()); 304 } 305 306 /** 307 * Returns whether or not {@code name} is a syntactically valid 308 * qualified name in the given source version. Unlike {@link 309 * #isIdentifier isIdentifier}, this method returns {@code false} 310 * for keywords, boolean literals, and the null literal. 311 * 312 * This method returns {@code true} for <i>restricted 313 * keywords</i> and {@code "var"}. 314 * 315 * @param name the string to check 316 * @param version the version to use 317 * @return {@code true} if this string is a 318 * syntactically valid name, {@code false} otherwise. 319 * @jls 3.9 Keywords 320 * @jls 6.2 Names and Identifiers 321 * @since 9 322 */ 323 public static boolean isName(CharSequence name, SourceVersion version) { 324 String id = name.toString(); 325 326 for(String s : id.split("\\.", -1)) { 327 if (!isIdentifier(s) || isKeyword(s, version)) 328 return false; 329 } 330 return true; 331 } 332 333 /** 334 * Returns whether or not {@code s} is a keyword, boolean literal, 335 * or null literal in the latest source version. 336 * This method returns {@code false} for <i>restricted 337 * keywords</i> and {@code "var"}. 338 * 339 * @param s the string to check 340 * @return {@code true} if {@code s} is a keyword, or boolean 341 * literal, or null literal, {@code false} otherwise. 342 * @jls 3.9 Keywords 343 * @jls 3.10.3 Boolean Literals 344 * @jls 3.10.7 The Null Literal 345 */ 346 public static boolean isKeyword(CharSequence s) { 347 return isKeyword(s, latest()); 348 } 349 350 /** 351 * Returns whether or not {@code s} is a keyword, boolean literal, 352 * or null literal in the given source version. 353 * This method returns {@code false} for <i>restricted 354 * keywords</i> and {@code "var"}. 355 * 356 * @param s the string to check 357 * @param version the version to use 358 * @return {@code true} if {@code s} is a keyword, or boolean 359 * literal, or null literal, {@code false} otherwise. 360 * @jls 3.9 Keywords 361 * @jls 3.10.3 Boolean Literals 362 * @jls 3.10.7 The Null Literal 363 * @since 9 364 */ 365 public static boolean isKeyword(CharSequence s, SourceVersion version) { 366 String id = s.toString(); 367 switch(id) { 368 // A trip through history 369 case "strictfp": 370 return version.compareTo(RELEASE_2) >= 0; 371 372 case "assert": 373 return version.compareTo(RELEASE_4) >= 0; 374 375 case "enum": 376 return version.compareTo(RELEASE_5) >= 0; 377 378 case "_": 379 return version.compareTo(RELEASE_9) >= 0; 380 381 // Keywords common across versions 382 383 // Modifiers 384 case "public": case "protected": case "private": 385 case "abstract": case "static": case "final": 386 case "transient": case "volatile": case "synchronized": 387 case "native": 388 389 // Declarations 390 case "class": case "interface": case "extends": 391 case "package": case "throws": case "implements": 392 393 // Primitive types and void 394 case "boolean": case "byte": case "char": 395 case "short": case "int": case "long": 396 case "float": case "double": 397 case "void": 398 399 // Control flow 400 case "if": case "else": 401 case "try": case "catch": case "finally": 402 case "do": case "while": 403 case "for": case "continue": 404 case "switch": case "case": case "default": 405 case "break": case "throw": case "return": 406 407 // Other keywords 408 case "this": case "new": case "super": 409 case "import": case "instanceof": 410 411 // Forbidden! 412 case "goto": case "const": 413 414 // literals 415 case "null": case "true": case "false": 416 return true; 417 418 default: 419 return false; 420 } 421 } 422 }