IDEA-359853 move JavaSdkVersion, JavaFeature, and LanguageLevel to java.syntax

GitOrigin-RevId: 68d300600bac4dd3bf4b102ba62aab4f4872ea11
This commit is contained in:
Max Medvedev
2025-04-01 00:38:44 +00:00
committed by intellij-monorepo-bot
parent f3370984c9
commit 4bbedb572d
7 changed files with 290 additions and 309 deletions
@@ -0,0 +1,12 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.psi
import com.intellij.openapi.util.Key
import com.intellij.pom.java.LanguageLevel
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
object LanguageLevelKey {
@JvmField
val FILE_LANGUAGE_LEVEL_KEY: Key<LanguageLevel> = Key.create("FORCE_LANGUAGE_LEVEL")
}
@@ -1081,7 +1081,7 @@ public final class PsiUtil extends PsiUtilCore {
return false;
}
public static final Key<LanguageLevel> FILE_LANGUAGE_LEVEL_KEY = LanguageLevel.FILE_LANGUAGE_LEVEL_KEY;
public static final Key<LanguageLevel> FILE_LANGUAGE_LEVEL_KEY = LanguageLevelKey.FILE_LANGUAGE_LEVEL_KEY;
public static boolean isLanguageLevel5OrHigher(@NotNull PsiElement element) {
return getLanguageLevel(element).isAtLeast(LanguageLevel.JDK_1_5);
@@ -1,19 +1,16 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.projectRoots;
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.projectRoots
import com.intellij.openapi.util.NlsSafe;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.util.lang.JavaVersion;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import com.intellij.openapi.util.NlsSafe
import com.intellij.pom.java.LanguageLevel
import com.intellij.util.lang.JavaVersion
import com.intellij.util.lang.JavaVersion.Companion.tryParse
/**
* Represents a version of Java SDK. Use {@code JavaSdk#getVersion(Sdk)} method to obtain a version of an {@code Sdk}.
* Represents a version of Java SDK. Use `JavaSdk#getVersion(Sdk)` method to obtain a version of an `Sdk`.
* @see LanguageLevel
*/
public enum JavaSdkVersion {
enum class JavaSdkVersion(val maxLanguageLevel: LanguageLevel) {
JDK_1_0(LanguageLevel.JDK_1_3),
JDK_1_1(LanguageLevel.JDK_1_3),
JDK_1_2(LanguageLevel.JDK_1_3),
@@ -41,45 +38,42 @@ public enum JavaSdkVersion {
JDK_24(LanguageLevel.JDK_24),
JDK_25(LanguageLevel.JDK_X);
private final LanguageLevel myMaxLanguageLevel;
JavaSdkVersion(@NotNull LanguageLevel maxLanguageLevel) {
myMaxLanguageLevel = maxLanguageLevel;
}
public @NotNull LanguageLevel getMaxLanguageLevel() {
return myMaxLanguageLevel;
}
public @NotNull @NlsSafe String getDescription() {
int feature = ordinal();
return feature < 5 ? "1." + feature : String.valueOf(feature);
}
public boolean isAtLeast(@NotNull JavaSdkVersion version) {
return compareTo(version) >= 0;
}
public static @NotNull JavaSdkVersion fromLanguageLevel(@NotNull LanguageLevel languageLevel) throws IllegalArgumentException {
JavaSdkVersion[] values = values();
if (languageLevel == LanguageLevel.JDK_X) {
return values[values.length - 1];
val description: @NlsSafe String
get() {
val feature = ordinal
return if (feature < 5) "1.$feature" else feature.toString()
}
int feature = languageLevel.feature();
if (feature < values.length) {
return values[feature];
fun isAtLeast(version: JavaSdkVersion): Boolean {
return compareTo(version) >= 0
}
companion object {
@Throws(IllegalArgumentException::class)
@JvmStatic
fun fromLanguageLevel(languageLevel: LanguageLevel): JavaSdkVersion {
val values = JavaSdkVersion.entries.toTypedArray()
if (languageLevel == LanguageLevel.JDK_X) {
return values[values.size - 1]
}
val feature = languageLevel.feature()
if (feature < values.size) {
return values[feature]
}
throw IllegalArgumentException("Can't map " + languageLevel + " to any of " + values.contentToString())
}
throw new IllegalArgumentException("Can't map " + languageLevel + " to any of " + Arrays.toString(values));
}
/** See {@link JavaVersion#parse(String)} for supported formats. */
public static @Nullable JavaSdkVersion fromVersionString(@NotNull String versionString) {
JavaVersion version = JavaVersion.tryParse(versionString);
return version != null ? fromJavaVersion(version) : null;
}
/** See [JavaVersion.parse] for supported formats. */
@JvmStatic
fun fromVersionString(versionString: String): JavaSdkVersion? {
val version = tryParse(versionString)
return if (version != null) fromJavaVersion(version) else null
}
public static @Nullable JavaSdkVersion fromJavaVersion(@NotNull JavaVersion version) {
JavaSdkVersion[] values = values();
return version.feature < values.length ? values[version.feature] : null;
@JvmStatic
fun fromJavaVersion(version: JavaVersion): JavaSdkVersion? {
val values = JavaSdkVersion.entries.toTypedArray()
return if (version.feature < values.size) values[version.feature] else null
}
}
}
@@ -1,18 +1,18 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.pom.java;
package com.intellij.pom.java
import com.intellij.core.JavaPsiBundle;
import org.jetbrains.annotations.*;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import com.intellij.java.syntax.JavaSyntaxBundle
import com.intellij.java.syntax.JavaSyntaxBundle.message
import org.jetbrains.annotations.Contract
import org.jetbrains.annotations.Nls
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.PropertyKey
/**
* Represents Java language, JVM, or standard library features and provides information
* Represents Java language, JVM, or standard library features and provides information
* whether a particular features is available in a given context
*/
public enum JavaFeature {
enum class JavaFeature {
ASSERTIONS(LanguageLevel.JDK_1_4, "feature.assertions"),
ENUMS(LanguageLevel.JDK_1_5, "feature.enums"),
GENERICS(LanguageLevel.JDK_1_5, "feature.generics"),
@@ -82,20 +82,15 @@ public enum JavaFeature {
ENUM_QUALIFIED_NAME_IN_SWITCH(LanguageLevel.JDK_21, "feature.enum.qualified.name.in.switch"),
SEQUENCED_COLLECTIONS(LanguageLevel.JDK_21, "feature.sequenced.collections"),
STRING_TEMPLATES(LanguageLevel.JDK_21_PREVIEW, "feature.string.templates") {
@Override
public boolean isSufficient(@NotNull LanguageLevel useSiteLevel) {
return super.isSufficient(useSiteLevel) && !useSiteLevel.isAtLeast(LanguageLevel.JDK_23);
override fun isSufficient(useSiteLevel: LanguageLevel): Boolean {
return super.isSufficient(useSiteLevel) && !useSiteLevel.isAtLeast(LanguageLevel.JDK_23)
}
@Override
public boolean isLimited() {
return true;
}
override val isLimited: Boolean get() = true
},
UNNAMED_PATTERNS_AND_VARIABLES(LanguageLevel.JDK_22, "feature.unnamed.vars") {
@Override
public boolean isSufficient(@NotNull LanguageLevel useSiteLevel) {
return super.isSufficient(useSiteLevel) || LanguageLevel.JDK_21_PREVIEW == useSiteLevel;
override fun isSufficient(useSiteLevel: LanguageLevel): Boolean {
return super.isSufficient(useSiteLevel) || LanguageLevel.JDK_21_PREVIEW == useSiteLevel
}
},
//jep 463,477
@@ -108,7 +103,7 @@ public enum JavaFeature {
STREAM_GATHERERS(LanguageLevel.JDK_22_PREVIEW, "feature.stream.gatherers"),
STATEMENTS_BEFORE_SUPER(LanguageLevel.JDK_22_PREVIEW, "feature.statements.before.super"),
/**
* Was a preview feature in Java 20 Preview.
* Was a preview feature in Java 20 Preview.
* Keep the implementation, as it could reappear in the future.
*/
RECORD_PATTERNS_IN_FOR_EACH(LanguageLevel.JDK_X, "feature.record.patterns.in.for.each",
@@ -132,111 +127,95 @@ public enum JavaFeature {
VALHALLA_VALUE_CLASSES(LanguageLevel.JDK_X, "feature.valhalla.value.classes"),
;
private final @NotNull LanguageLevel myLevel;
private final @PropertyKey(resourceBundle = JavaPsiBundle.BUNDLE) @NotNull String myKey;
private final boolean myCanBeCustomized;
private final Set<LanguageLevel> myObsoletePreviewLevels;
JavaFeature(@NotNull LanguageLevel level, @NotNull @PropertyKey(resourceBundle = JavaPsiBundle.BUNDLE) String key) {
this(level, key, false);
}
JavaFeature(@NotNull LanguageLevel level, @NotNull @PropertyKey(resourceBundle = JavaPsiBundle.BUNDLE) String key,
@NotNull LanguageLevel @NotNull ... obsoletePreviewLevels) {
myLevel = level;
myKey = key;
myCanBeCustomized = false;
myObsoletePreviewLevels = EnumSet.noneOf(LanguageLevel.class);
for (LanguageLevel obsoletePreviewLevel : obsoletePreviewLevels) {
if (!obsoletePreviewLevel.isUnsupported()) throw new IllegalArgumentException(obsoletePreviewLevel.toString());
myObsoletePreviewLevels.add(obsoletePreviewLevel);
}
}
JavaFeature(@NotNull LanguageLevel level, @NotNull @PropertyKey(resourceBundle = JavaPsiBundle.BUNDLE) String key,
boolean canBeCustomized) {
myLevel = level;
myKey = key;
myCanBeCustomized = canBeCustomized;
myObsoletePreviewLevels = Collections.emptySet();
}
/**
* @return Human-readable feature name
*/
public @NotNull @Nls String getFeatureName() {
return JavaPsiBundle.message(myKey);
}
/**
* @return minimal language level where feature is available.
* Note that this doesn't mean that the feature is available on every language level which is higher.
* In most of the cases, {@code PsiUtil.isAvailable(PsiElement)} or {@link #isSufficient(LanguageLevel)} should be used instead.
* In most of the cases, `PsiUtil.isAvailable(PsiElement)` or [.isSufficient] should be used instead.
*/
public @NotNull LanguageLevel getMinimumLevel() {
return myLevel;
val minimumLevel: LanguageLevel
private val myKey: @PropertyKey(resourceBundle = JavaSyntaxBundle.BUNDLE) String
private val myCanBeCustomized: Boolean
private val myObsoletePreviewLevels: Set<LanguageLevel>
constructor(
level: LanguageLevel,
key: @PropertyKey(resourceBundle = JavaSyntaxBundle.BUNDLE) String,
vararg obsoletePreviewLevels: LanguageLevel
) {
minimumLevel = level
myKey = key
myCanBeCustomized = false
myObsoletePreviewLevels = mutableSetOf()
for (obsoletePreviewLevel in obsoletePreviewLevels) {
require(obsoletePreviewLevel.isUnsupported) { obsoletePreviewLevel.toString() }
myObsoletePreviewLevels.add(obsoletePreviewLevel)
}
}
constructor(
level: LanguageLevel,
key: @PropertyKey(resourceBundle = JavaSyntaxBundle.BUNDLE) String,
canBeCustomized: Boolean = false
) {
minimumLevel = level
myKey = key
myCanBeCustomized = canBeCustomized
myObsoletePreviewLevels = emptySet()
}
/**
* @return true if the availability of this feature can be additionally filtered using {@link LanguageFeatureProvider}.
* Human-readable feature name
*/
val featureName: @Nls String
get() = message(myKey)
/**
* @return true if the availability of this feature can be additionally filtered using [LanguageFeatureProvider].
*/
@Contract(pure = true)
public boolean canBeCustomized() {
return myCanBeCustomized;
fun canBeCustomized(): Boolean {
return myCanBeCustomized
}
@Contract(pure = true)
public boolean isSufficient(@NotNull LanguageLevel useSiteLevel) {
return (useSiteLevel.isAtLeast(myLevel) ||
useSiteLevel.isUnsupported() && myObsoletePreviewLevels.contains(useSiteLevel)) &&
(!myLevel.isPreview() || useSiteLevel.isPreview());
open fun isSufficient(useSiteLevel: LanguageLevel): Boolean {
return (useSiteLevel.isAtLeast(this.minimumLevel) ||
useSiteLevel.isUnsupported && myObsoletePreviewLevels.contains(useSiteLevel)) &&
(!minimumLevel.isPreview || useSiteLevel.isPreview)
}
@Contract(pure = true)
public boolean isLimited() {
return false;
}
@get:Contract(pure = true)
open val isLimited: Boolean
get() = false
/**
* Override if feature was preview and then accepted as standard
*/
@Contract(pure = true)
public LanguageLevel getStandardLevel() {
return myLevel.isPreview() ? null : myLevel;
}
@get:Contract(pure = true)
val standardLevel: LanguageLevel?
get() = if (minimumLevel.isPreview) null else this.minimumLevel
// Should correspond to jdk.internal.javac.PreviewFeature.Feature enum
@Contract(pure = true)
public static @Nullable JavaFeature convertFromPreviewFeatureName(@NotNull @NonNls String feature) {
switch (feature) {
case "PATTERN_MATCHING_IN_INSTANCEOF":
return PATTERNS;
case "TEXT_BLOCKS":
return TEXT_BLOCKS;
case "RECORDS":
return RECORDS;
case "SEALED_CLASSES":
return SEALED_CLASSES;
case "STRING_TEMPLATES":
return STRING_TEMPLATES;
case "UNNAMED_CLASSES":
case "IMPLICIT_CLASSES":
return IMPLICIT_CLASSES;
case "SCOPED_VALUES":
return SCOPED_VALUES;
case "STRUCTURED_CONCURRENCY":
return STRUCTURED_CONCURRENCY;
case "CLASSFILE_API":
return CLASSFILE_API;
case "STREAM_GATHERERS":
return STREAM_GATHERERS;
case "FOREIGN":
return FOREIGN_FUNCTIONS;
case "VIRTUAL_THREADS":
return VIRTUAL_THREADS;
default:
return null;
companion object {
// Should correspond to jdk.internal.javac.PreviewFeature.Feature enum
@Contract(pure = true)
@JvmStatic
fun convertFromPreviewFeatureName(feature: @NonNls String): JavaFeature? {
return when (feature) {
"PATTERN_MATCHING_IN_INSTANCEOF" -> PATTERNS
"TEXT_BLOCKS" -> TEXT_BLOCKS
"RECORDS" -> RECORDS
"SEALED_CLASSES" -> SEALED_CLASSES
"STRING_TEMPLATES" -> STRING_TEMPLATES
"UNNAMED_CLASSES", "IMPLICIT_CLASSES" -> IMPLICIT_CLASSES
"SCOPED_VALUES" -> SCOPED_VALUES
"STRUCTURED_CONCURRENCY" -> STRUCTURED_CONCURRENCY
"CLASSFILE_API" -> CLASSFILE_API
"STREAM_GATHERERS" -> STREAM_GATHERERS
"FOREIGN" -> FOREIGN_FUNCTIONS
"VIRTUAL_THREADS" -> VIRTUAL_THREADS
else -> null
}
}
}
}
@@ -1,85 +1,81 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.pom.java;
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.pom.java
import com.intellij.core.JavaPsiBundle;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.util.lang.JavaVersion;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.intellij.java.syntax.JavaSyntaxBundle.messagePointer
import com.intellij.openapi.projectRoots.JavaSdkVersion
import com.intellij.openapi.util.NlsSafe
import com.intellij.util.lang.JavaVersion
import com.intellij.util.lang.JavaVersion.Companion.compose
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.Nls
/**
* Represents a language level (i.e. features available) of a Java code.
* The {@link org.jetbrains.jps.model.java.LanguageLevel} class is a compiler-side counterpart of this enum.
* <p>
* Unsupported language levels are marked as {@link ApiStatus.Obsolete} to draw attention. They should not be normally used,
* except probably in rare tests and inside {@link JavaFeature}.
* The [org.jetbrains.jps.model.java.LanguageLevel] class is a compiler-side counterpart of this enum.
*
*
* Unsupported language levels are marked as [ApiStatus.Obsolete] to draw attention. They should not be normally used,
* except probably in rare tests and inside [JavaFeature].
*
* @see com.intellij.openapi.roots.LanguageLevelModuleExtension
*
* @see com.intellij.openapi.roots.LanguageLevelProjectExtension
*
* @see JavaSdkVersion
*
* @see JavaFeature
*/
public enum LanguageLevel {
JDK_1_3(JavaPsiBundle.messagePointer("jdk.1.3.language.level.description"), 3),
JDK_1_4(JavaPsiBundle.messagePointer("jdk.1.4.language.level.description"), 4),
JDK_1_5(JavaPsiBundle.messagePointer("jdk.1.5.language.level.description"), 5),
JDK_1_6(JavaPsiBundle.messagePointer("jdk.1.6.language.level.description"), 6),
JDK_1_7(JavaPsiBundle.messagePointer("jdk.1.7.language.level.description"), 7),
JDK_1_8(JavaPsiBundle.messagePointer("jdk.1.8.language.level.description"), 8),
JDK_1_9(JavaPsiBundle.messagePointer("jdk.1.9.language.level.description"), 9),
JDK_10(JavaPsiBundle.messagePointer("jdk.10.language.level.description"), 10),
JDK_11(JavaPsiBundle.messagePointer("jdk.11.language.level.description"), 11),
JDK_12(JavaPsiBundle.messagePointer("jdk.12.language.level.description"), 12),
JDK_13(JavaPsiBundle.messagePointer("jdk.13.language.level.description"), 13),
JDK_14(JavaPsiBundle.messagePointer("jdk.14.language.level.description"), 14),
JDK_15(JavaPsiBundle.messagePointer("jdk.15.language.level.description"), 15),
JDK_16(JavaPsiBundle.messagePointer("jdk.16.language.level.description"), 16),
JDK_17(JavaPsiBundle.messagePointer("jdk.17.language.level.description"), 17),
enum class LanguageLevel {
JDK_1_3(messagePointer("jdk.1.3.language.level.description"), 3),
JDK_1_4(messagePointer("jdk.1.4.language.level.description"), 4),
JDK_1_5(messagePointer("jdk.1.5.language.level.description"), 5),
JDK_1_6(messagePointer("jdk.1.6.language.level.description"), 6),
JDK_1_7(messagePointer("jdk.1.7.language.level.description"), 7),
JDK_1_8(messagePointer("jdk.1.8.language.level.description"), 8),
JDK_1_9(messagePointer("jdk.1.9.language.level.description"), 9),
JDK_10(messagePointer("jdk.10.language.level.description"), 10),
JDK_11(messagePointer("jdk.11.language.level.description"), 11),
JDK_12(messagePointer("jdk.12.language.level.description"), 12),
JDK_13(messagePointer("jdk.13.language.level.description"), 13),
JDK_14(messagePointer("jdk.14.language.level.description"), 14),
JDK_15(messagePointer("jdk.15.language.level.description"), 15),
JDK_16(messagePointer("jdk.16.language.level.description"), 16),
JDK_17(messagePointer("jdk.17.language.level.description"), 17),
@ApiStatus.Obsolete
JDK_17_PREVIEW(17),
JDK_18(JavaPsiBundle.messagePointer("jdk.18.language.level.description"), 18),
JDK_18(messagePointer("jdk.18.language.level.description"), 18),
@ApiStatus.Obsolete
JDK_18_PREVIEW(18),
JDK_19(JavaPsiBundle.messagePointer("jdk.19.language.level.description"), 19),
JDK_19(messagePointer("jdk.19.language.level.description"), 19),
@ApiStatus.Obsolete
JDK_19_PREVIEW(19),
JDK_20(JavaPsiBundle.messagePointer("jdk.20.language.level.description"), 20),
JDK_20(messagePointer("jdk.20.language.level.description"), 20),
@ApiStatus.Obsolete
JDK_20_PREVIEW(20),
JDK_21(JavaPsiBundle.messagePointer("jdk.21.language.level.description"), 21),
JDK_21_PREVIEW(JavaPsiBundle.messagePointer("jdk.21.preview.language.level.description"), 21),
JDK_22(JavaPsiBundle.messagePointer("jdk.22.language.level.description"), 22),
JDK_22_PREVIEW(JavaPsiBundle.messagePointer("jdk.22.preview.language.level.description"), 22),
JDK_23(JavaPsiBundle.messagePointer("jdk.23.language.level.description"), 23),
JDK_23_PREVIEW(JavaPsiBundle.messagePointer("jdk.23.preview.language.level.description"), 23),
JDK_24(JavaPsiBundle.messagePointer("jdk.24.language.level.description"), 24),
JDK_24_PREVIEW(JavaPsiBundle.messagePointer("jdk.24.preview.language.level.description"), 24),
JDK_X(JavaPsiBundle.messagePointer("jdk.X.language.level.description"), 25),
JDK_21(messagePointer("jdk.21.language.level.description"), 21),
JDK_21_PREVIEW(messagePointer("jdk.21.preview.language.level.description"), 21),
JDK_22(messagePointer("jdk.22.language.level.description"), 22),
JDK_22_PREVIEW(messagePointer("jdk.22.preview.language.level.description"), 22),
JDK_23(messagePointer("jdk.23.language.level.description"), 23),
JDK_23_PREVIEW(messagePointer("jdk.23.preview.language.level.description"), 23),
JDK_24(messagePointer("jdk.24.language.level.description"), 24),
JDK_24_PREVIEW(messagePointer("jdk.24.preview.language.level.description"), 24),
JDK_X(messagePointer("jdk.X.language.level.description"), 25),
;
/**
* Should point to the latest released JDK.
*/
public static final LanguageLevel HIGHEST = JDK_24;
private val myPresentableText: () -> @Nls String
private val myVersion: JavaVersion
val isPreview: Boolean
private final Supplier<@Nls String> myPresentableText;
private final JavaVersion myVersion;
private final boolean myPreview;
private final boolean myUnsupported;
private static final Map<Integer, LanguageLevel> ourStandardVersions =
Stream.of(values()).filter(ver -> !ver.isPreview())
.collect(Collectors.toMap(ver -> ver.myVersion.feature, Function.identity()));
/**
* @return true if this language level is not supported anymore. It's still possible to invoke compiler or launch the program
* using this language level. However, it's not guaranteed that the code insight features will work correctly.
*/
val isUnsupported: Boolean
/**
* Construct the language level for a supported Java version
@@ -87,11 +83,11 @@ public enum LanguageLevel {
* @param presentableTextSupplier a supplier that returns the language level description
* @param major the major version number. Whether the version is a preview version is determined by the enum constant name
*/
LanguageLevel(Supplier<@Nls String> presentableTextSupplier, int major) {
myPresentableText = presentableTextSupplier;
myVersion = JavaVersion.compose(major);
myUnsupported = false;
myPreview = name().endsWith("_PREVIEW") || name().endsWith("_X");
constructor(presentableTextSupplier: () -> @Nls String, major: Int) {
myPresentableText = presentableTextSupplier
myVersion = compose(major)
this.isUnsupported = false
this.isPreview = name.endsWith("_PREVIEW") || name.endsWith("_X")
}
/**
@@ -99,60 +95,47 @@ public enum LanguageLevel {
*
* @param major the major version number. Unsupported Java version is always a preview version
*/
LanguageLevel(int major) {
myPresentableText = JavaPsiBundle.messagePointer("jdk.unsupported.preview.language.level.description", major);
myVersion = JavaVersion.compose(major);
myUnsupported = true;
myPreview = true;
if (!name().endsWith("_PREVIEW")) {
throw new IllegalArgumentException("Only preview versions could be unsupported: " + name());
constructor(major: Int) {
myPresentableText = messagePointer("jdk.unsupported.preview.language.level.description", major)
myVersion = compose(major)
this.isUnsupported = true
this.isPreview = true
require(name.endsWith("_PREVIEW")) { "Only preview versions could be unsupported: " + name }
}
val previewLevel: LanguageLevel?
/**
* @return corresponding preview level, or `null` if level has no paired preview level
*/
get() {
if (this.isPreview) return this
try {
return valueOf(name + "_PREVIEW")
}
catch (_: IllegalArgumentException) {
return null
}
}
}
public boolean isPreview() {
return myPreview;
}
/**
* @return true if this language level is not supported anymore. It's still possible to invoke compiler or launch the program
* using this language level. However, it's not guaranteed that the code insight features will work correctly.
*/
public boolean isUnsupported() {
return myUnsupported;
}
/**
* @return corresponding preview level, or {@code null} if level has no paired preview level
*/
public @Nullable LanguageLevel getPreviewLevel() {
if (myPreview) return this;
try {
return valueOf(name() + "_PREVIEW");
val nonPreviewLevel: LanguageLevel
/**
* @return corresponding non-preview level; this if this level is non-preview already
*/
get() {
if (!this.isPreview) return this
return requireNotNull(ourStandardVersions[myVersion.feature])
}
catch (IllegalArgumentException e) {
return null;
}
}
/**
* @return corresponding non-preview level; this if this level is non-preview already
*/
public @NotNull LanguageLevel getNonPreviewLevel() {
if (!myPreview) return this;
return Objects.requireNonNull(ourStandardVersions.get(myVersion.feature));
}
public @NotNull @Nls String getPresentableText() {
return myPresentableText.get();
}
val presentableText: @Nls String
get() = myPresentableText()
/**
* @param level level to compare to
* @return true, if this language level is at least the same or newer than the level we are comparing to.
* A preview level for Java version X is assumed to be between non-preview version X and non-preview version X+1
*/
public boolean isAtLeast(@NotNull LanguageLevel level) {
return compareTo(level) >= 0;
fun isAtLeast(level: LanguageLevel): Boolean {
return compareTo(level) >= 0
}
/**
@@ -160,58 +143,71 @@ public enum LanguageLevel {
* @return true if this language level is strictly less than the level we are comparing to.
* A preview level for Java version X is assumed to be between non-preview version X and non-preview version X+1
*/
public boolean isLessThan(@NotNull LanguageLevel level) {
return compareTo(level) < 0;
fun isLessThan(level: LanguageLevel): Boolean {
return compareTo(level) < 0
}
/**
* @return the {@link JavaVersion} object that corresponds to this language level
* @return the [JavaVersion] object that corresponds to this language level
*/
public @NotNull JavaVersion toJavaVersion() {
return myVersion;
fun toJavaVersion(): JavaVersion {
return myVersion
}
/**
* @return the language level feature number (like 8 for {@link #JDK_1_8}).
* @return the language level feature number (like 8 for [.JDK_1_8]).
*/
public int feature() {
return myVersion.feature;
fun feature(): Int {
return myVersion.feature
}
/**
* @return short representation of the corresponding language level, like '8', or '21-preview'
*/
public @NlsSafe String getShortText() {
if (this == JDK_X) {
return "X";
}
int feature = feature();
if (feature < 5) {
return "1." + feature;
}
return feature + (isPreview() ? "-preview" : "");
}
/** See {@link JavaVersion#parse(String)} for supported formats. */
public static @Nullable LanguageLevel parse(@Nullable String compilerComplianceOption) {
if (compilerComplianceOption != null) {
JavaSdkVersion sdkVersion = JavaSdkVersion.fromVersionString(compilerComplianceOption);
if (sdkVersion != null) {
return sdkVersion.getMaxLanguageLevel();
val shortText: @NlsSafe String
/**
* @return short representation of the corresponding language level, like '8', or '21-preview'
*/
get() {
if (this == JDK_X) {
return "X"
}
val feature = feature()
if (feature < 5) {
return "1.$feature"
}
return feature.toString() + (if (this.isPreview) "-preview" else "")
}
return null;
}
/**
* @param feature major Java language level number
* @return a {@link LanguageLevel} constant that correspond to the specified level (non-preview).
* Returns null for unknown/unsupported input. May return {@link #JDK_X} if language level is one level
* higher than maximal supported.
*/
public static @Nullable LanguageLevel forFeature(int feature) {
return ourStandardVersions.get(feature);
}
companion object {
/**
* Should point to the latest released JDK.
*/
@JvmField
val HIGHEST: LanguageLevel = JDK_24
public static final Key<LanguageLevel> FILE_LANGUAGE_LEVEL_KEY = Key.create("FORCE_LANGUAGE_LEVEL");
private val ourStandardVersions: Map<Int, LanguageLevel> = LanguageLevel.entries.asSequence()
.filterNot { ver -> ver.isPreview }
.associateBy { ver -> ver.myVersion.feature }
/** See [JavaVersion.parse] for supported formats. */
@JvmStatic
fun parse(compilerComplianceOption: String?): LanguageLevel? {
if (compilerComplianceOption != null) {
val sdkVersion = JavaSdkVersion.fromVersionString(compilerComplianceOption)
if (sdkVersion != null) {
return sdkVersion.maxLanguageLevel
}
}
return null
}
/**
* @param feature major Java language level number
* @return a [LanguageLevel] constant that correspond to the specified level (non-preview).
* Returns null for unknown/unsupported input. May return [.JDK_X] if language level is one level
* higher than maximal supported.
*/
@JvmStatic
fun forFeature(feature: Int): LanguageLevel? {
return ourStandardVersions[feature]
}
}
}
@@ -29,7 +29,7 @@ import com.intellij.platform.workspace.jps.entities.exModuleOptions
import com.intellij.platform.workspace.storage.entities
import com.intellij.pom.java.AcceptedLanguageLevelsSettings
import com.intellij.pom.java.LanguageLevel
import com.intellij.pom.java.LanguageLevel.HIGHEST
import com.intellij.pom.java.LanguageLevel.Companion.HIGHEST
import com.intellij.util.containers.ContainerUtil
import com.intellij.util.text.VersionComparatorUtil
import com.intellij.workspaceModel.ide.legacyBridge.findModuleEntity
@@ -310,14 +310,14 @@ object MavenImportUtil {
private fun adjustPreviewLanguageLevel(mavenProject: MavenProject, level: LanguageLevel): LanguageLevel {
val enablePreviewProperty = mavenProject.properties.getProperty("maven.compiler.enablePreview")
if (enablePreviewProperty.toBoolean()) {
return level.getPreviewLevel() ?: level
return level.previewLevel ?: level
}
val compilerConfiguration = mavenProject.getPluginConfiguration(COMPILER_PLUGIN_GROUP_ID, COMPILER_PLUGIN_ARTIFACT_ID)
if (compilerConfiguration != null) {
val enablePreviewParameter = compilerConfiguration.getChildTextTrim("enablePreview")
if (enablePreviewParameter.toBoolean()) {
return level.getPreviewLevel() ?: level
return level.previewLevel ?: level
}
val compilerArgs = compilerConfiguration.getChild("compilerArgs")
@@ -326,7 +326,7 @@ object MavenImportUtil {
compilerArgs.getChildren("arg").any { isPreviewText(it) } ||
compilerArgs.getChildren("compilerArg").any{ isPreviewText(it) }
) {
return level.getPreviewLevel() ?: level
return level.previewLevel ?: level
}
}
}
@@ -504,7 +504,7 @@ object MavenUtil {
if (sdk != null && sdk.getSdkType() is JavaSdk) {
val javaSdk = sdk.getSdkType() as JavaSdk
val version: JavaSdkVersion? = javaSdk.getVersion(sdk)
val description = if (version == null) null else version.getDescription()
val description = if (version == null) null else version.description
val shouldSetLangLevel = version != null && version.isAtLeast(JavaSdkVersion.JDK_1_6)
conditions.setProperty("SHOULD_SET_LANG_LEVEL", shouldSetLangLevel.toString())
properties.setProperty("COMPILER_LEVEL_SOURCE", description)