SourceVersion.java revision 3890:05b91c7f6f9e
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
26package javax.lang.model;
27
28import java.util.Collections;
29import java.util.Set;
30import java.util.HashSet;
31
32/**
33 * Source versions of the Java™ programming language.
34 *
35 * See the appropriate edition of
36 * <cite>The Java&trade; 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&eacute;
45 * @since 1.6
46 */
47public 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&trade; 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&trade; 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&trade; 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&trade; 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     * @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 {
180            String specVersion = System.getProperty("java.specification.version");
181
182            switch (specVersion) {
183                case "10":
184                    return RELEASE_10;
185                case "9":
186                case "1.9":
187                    return RELEASE_9;
188                case "1.8":
189                    return RELEASE_8;
190                case "1.7":
191                    return RELEASE_7;
192                case "1.6":
193                    return RELEASE_6;
194            }
195        } catch (SecurityException se) {}
196
197        return RELEASE_5;
198    }
199
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, and the
220     * literals {@code "true"}, {@code "false"}, and {@code "null"}.
221     * The method returns {@code false} for all other strings.
222     *
223     * @param name the string to check
224     * @return {@code true} if this string is a
225     * syntactically valid identifier or keyword, {@code false}
226     * otherwise.
227     */
228    public static boolean isIdentifier(CharSequence name) {
229        String id = name.toString();
230
231        if (id.length() == 0) {
232            return false;
233        }
234        int cp = id.codePointAt(0);
235        if (!Character.isJavaIdentifierStart(cp)) {
236            return false;
237        }
238        for (int i = Character.charCount(cp);
239                i < id.length();
240                i += Character.charCount(cp)) {
241            cp = id.codePointAt(i);
242            if (!Character.isJavaIdentifierPart(cp)) {
243                return false;
244            }
245        }
246        return true;
247    }
248
249    /**
250     * Returns whether or not {@code name} is a syntactically valid
251     * qualified name in the latest source version.  Unlike {@link
252     * #isIdentifier isIdentifier}, this method returns {@code false}
253     * for keywords, boolean literals, and the null literal.
254     *
255     * @param name the string to check
256     * @return {@code true} if this string is a
257     * syntactically valid name, {@code false} otherwise.
258     * @jls 6.2 Names and Identifiers
259     */
260    public static boolean isName(CharSequence name) {
261        return isName(name, latest());
262    }
263
264    /**
265     * Returns whether or not {@code name} is a syntactically valid
266     * qualified name in the given source version.  Unlike {@link
267     * #isIdentifier isIdentifier}, this method returns {@code false}
268     * for keywords, boolean literals, and the null literal.
269     *
270     * @param name the string to check
271     * @param version the version to use
272     * @return {@code true} if this string is a
273     * syntactically valid name, {@code false} otherwise.
274     * @jls 6.2 Names and Identifiers
275     * @since 9
276     */
277    public static boolean isName(CharSequence name, SourceVersion version) {
278        String id = name.toString();
279
280        for(String s : id.split("\\.", -1)) {
281            if (!isIdentifier(s) || isKeyword(s, version))
282                return false;
283        }
284        return true;
285    }
286
287    /**
288     * Returns whether or not {@code s} is a keyword, boolean literal,
289     * or null literal in the latest source version.
290     *
291     * @param s the string to check
292     * @return {@code true} if {@code s} is a keyword, or boolean
293     * literal, or null literal, {@code false} otherwise.
294     * @jls 3.9 Keywords
295     * @jls 3.10.3 Boolean Literals
296     * @jls 3.10.7 The Null Literal
297     */
298    public static boolean isKeyword(CharSequence s) {
299        return isKeyword(s, latest());
300    }
301
302    /**
303     * Returns whether or not {@code s} is a keyword, boolean literal,
304     * or null literal in the given source version.
305     *
306     * @param s the string to check
307     * @param version the version to use
308     * @return {@code true} if {@code s} is a keyword, or boolean
309     * literal, or null literal, {@code false} otherwise.
310     * @jls 3.9 Keywords
311     * @jls 3.10.3 Boolean Literals
312     * @jls 3.10.7 The Null Literal
313     * @since 9
314     */
315    public static boolean isKeyword(CharSequence s, SourceVersion version) {
316        String id = s.toString();
317        switch(id) {
318            // A trip through history
319        case "strictfp":
320            return version.compareTo(RELEASE_2) >= 0;
321
322        case "assert":
323            return version.compareTo(RELEASE_4) >= 0;
324
325        case "enum":
326            return version.compareTo(RELEASE_5) >= 0;
327
328        case "_":
329            return version.compareTo(RELEASE_9) >= 0;
330
331            // Keywords common across versions
332
333            // Modifiers
334        case "public":    case "protected": case "private":
335        case "abstract":  case "static":    case "final":
336        case "transient": case "volatile":  case "synchronized":
337        case "native":
338
339            // Declarations
340        case "class":     case "interface": case "extends":
341        case "package":   case "throws":    case "implements":
342
343            // Primitive types and void
344        case "boolean":   case "byte":      case "char":
345        case "short":     case "int":       case "long":
346        case "float":     case "double":
347        case "void":
348
349            // Control flow
350        case "if":      case "else":
351        case "try":     case "catch":    case "finally":
352        case "do":      case "while":
353        case "for":     case "continue":
354        case "switch":  case "case":     case "default":
355        case "break":   case "throw":    case "return":
356
357            // Other keywords
358        case  "this":   case "new":      case "super":
359        case "import":  case "instanceof":
360
361            // Forbidden!
362        case "goto":        case "const":
363
364            // literals
365        case "null":         case "true":       case "false":
366            return true;
367
368        default:
369            return false;
370        }
371    }
372}
373