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