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 * @since 10 161 */ 162 RELEASE_10; 163 164 // Note that when adding constants for newer releases, the 165 // behavior of latest() and latestSupported() must be updated too. 166 167 /** 168 * Returns the latest source version that can be modeled. 169 * 170 * @return the latest source version that can be modeled 171 */ 172 public static SourceVersion latest() { 173 return RELEASE_10; 174 } 175 176 private static final SourceVersion latestSupported = getLatestSupported(); 177 178 private static SourceVersion getLatestSupported() { 179 try { 200 /** 201 * Returns the latest source version fully supported by the 202 * current execution environment. {@code RELEASE_5} or later must 203 * be returned. 204 * 205 * @return the latest source version that is fully supported 206 */ 207 public static SourceVersion latestSupported() { 208 return latestSupported; 209 } 210 211 /** 212 * Returns whether or not {@code name} is a syntactically valid 213 * identifier (simple name) or keyword in the latest source 214 * version. The method returns {@code true} if the name consists 215 * of an initial character for which {@link 216 * Character#isJavaIdentifierStart(int)} returns {@code true}, 217 * followed only by characters for which {@link 218 * Character#isJavaIdentifierPart(int)} returns {@code true}. 219 * This pattern matches regular identifiers, keywords, restricted 220 * keywords, and the literals {@code "true"}, {@code "false"}, and 221 * {@code "null"}. 222 * The method returns {@code false} for all other strings. 223 * 224 * @param name the string to check 225 * @return {@code true} if this string is a 226 * syntactically valid identifier or keyword, {@code false} 227 * otherwise. 228 */ 229 public static boolean isIdentifier(CharSequence name) { 230 String id = name.toString(); 231 232 if (id.length() == 0) { 233 return false; 234 } 235 int cp = id.codePointAt(0); 236 if (!Character.isJavaIdentifierStart(cp)) { 237 return false; 238 } 239 for (int i = Character.charCount(cp); 240 i < id.length(); 241 i += Character.charCount(cp)) { 242 cp = id.codePointAt(i); 243 if (!Character.isJavaIdentifierPart(cp)) { 244 return false; 245 } 246 } 247 return true; 248 } 249 250 /** 251 * Returns whether or not {@code name} is a syntactically valid 252 * qualified name in the latest source version. Unlike {@link 253 * #isIdentifier isIdentifier}, this method returns {@code false} 254 * for keywords, boolean literals, and the null literal. 255 * This method returns {@code true} for <i>restricted 256 * keywords</i>. 257 * 258 * @param name the string to check 259 * @return {@code true} if this string is a 260 * syntactically valid name, {@code false} otherwise. 261 * @jls 3.9 Keywords 262 * @jls 6.2 Names and Identifiers 263 */ 264 public static boolean isName(CharSequence name) { 265 return isName(name, latest()); 266 } 267 268 /** 269 * Returns whether or not {@code name} is a syntactically valid 270 * qualified name in the given source version. Unlike {@link 271 * #isIdentifier isIdentifier}, this method returns {@code false} 272 * for keywords, boolean literals, and the null literal. 273 * This method returns {@code true} for <i>restricted 274 * keywords</i>. 275 * 276 * @param name the string to check 277 * @param version the version to use 278 * @return {@code true} if this string is a 279 * syntactically valid name, {@code false} otherwise. 280 * @jls 3.9 Keywords 281 * @jls 6.2 Names and Identifiers 282 * @since 9 283 */ 284 public static boolean isName(CharSequence name, SourceVersion version) { 285 String id = name.toString(); 286 287 for(String s : id.split("\\.", -1)) { 288 if (!isIdentifier(s) || isKeyword(s, version)) 289 return false; 290 } 291 return true; 292 } 293 294 /** 295 * Returns whether or not {@code s} is a keyword, boolean literal, 296 * or null literal in the latest source version. 297 * This method returns {@code false} for <i>restricted 298 * keywords</i>. 299 * 300 * @param s the string to check 301 * @return {@code true} if {@code s} is a keyword, or boolean 302 * literal, or null literal, {@code false} otherwise. 303 * @jls 3.9 Keywords 304 * @jls 3.10.3 Boolean Literals 305 * @jls 3.10.7 The Null Literal 306 */ 307 public static boolean isKeyword(CharSequence s) { 308 return isKeyword(s, latest()); 309 } 310 311 /** 312 * Returns whether or not {@code s} is a keyword, boolean literal, 313 * or null literal in the given source version. 314 * This method returns {@code false} for <i>restricted 315 * keywords</i>. 316 * 317 * @param s the string to check 318 * @param version the version to use 319 * @return {@code true} if {@code s} is a keyword, or boolean 320 * literal, or null literal, {@code false} otherwise. 321 * @jls 3.9 Keywords 322 * @jls 3.10.3 Boolean Literals 323 * @jls 3.10.7 The Null Literal 324 * @since 9 325 */ 326 public static boolean isKeyword(CharSequence s, SourceVersion version) { 327 String id = s.toString(); 328 switch(id) { 329 // A trip through history 330 case "strictfp": 331 return version.compareTo(RELEASE_2) >= 0; 332 333 case "assert": 334 return version.compareTo(RELEASE_4) >= 0; 335 | 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 { 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 |