Skip to content

Commit 2e01f62

Browse files
committed
Kotlin Facet: Detect language/API version by stdlib when "Use project settings" is enabled, but project-level language/api version is not specified explicitly
1 parent 0d2122b commit 2e01f62

File tree

14 files changed

+186
-114
lines changed

14 files changed

+186
-114
lines changed

idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/BuiltInsCache.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
2626
import org.jetbrains.kotlin.config.LanguageFeature
2727
import org.jetbrains.kotlin.context.GlobalContextImpl
2828
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
29-
import org.jetbrains.kotlin.idea.project.languageVersionSettings
29+
import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings
3030
import org.jetbrains.kotlin.js.resolve.JsPlatform
3131
import org.jetbrains.kotlin.platform.JvmBuiltIns
3232
import org.jetbrains.kotlin.resolve.TargetPlatform
@@ -74,7 +74,7 @@ class BuiltInsCache private constructor(
7474
val builtInsCache = BuiltInsCache(project, platform, sdk, sdkModuleDescriptor, sdkContext)
7575

7676
if (sdkBuiltIns is JvmBuiltIns) {
77-
val isAdditionalBuiltInsFeatureSupported = project.languageVersionSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)
77+
val isAdditionalBuiltInsFeatureSupported = project.getLanguageVersionSettings().supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)
7878
sdkBuiltIns.initialize(
7979
sdkModuleDescriptor!!, // sdk is not null for JvmBuiltIns because of calculateBuiltIns
8080
isAdditionalBuiltInsFeatureSupported)
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2010-2017 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.jetbrains.kotlin.idea.facet
18+
19+
import com.intellij.openapi.extensions.ExtensionPointName
20+
import com.intellij.openapi.module.Module
21+
import com.intellij.openapi.roots.ModuleRootModel
22+
import com.intellij.util.text.VersionComparatorUtil
23+
import org.jetbrains.kotlin.config.JvmTarget
24+
import org.jetbrains.kotlin.config.LanguageVersion
25+
import org.jetbrains.kotlin.config.TargetPlatformKind
26+
27+
interface KotlinVersionInfoProvider {
28+
companion object {
29+
val EP_NAME: ExtensionPointName<KotlinVersionInfoProvider> = ExtensionPointName.create("org.jetbrains.kotlin.versionInfoProvider")!!
30+
}
31+
32+
fun getCompilerVersion(module: Module): String?
33+
fun getLibraryVersions(
34+
module: Module,
35+
targetPlatform: TargetPlatformKind<*>,
36+
rootModel: ModuleRootModel?
37+
): Collection<String>
38+
}
39+
40+
fun getRuntimeLibraryVersions(
41+
module: Module,
42+
rootModel: ModuleRootModel?,
43+
targetPlatform: TargetPlatformKind<*>
44+
): Collection<String> {
45+
return KotlinVersionInfoProvider.EP_NAME
46+
.extensions
47+
.map { it.getLibraryVersions(module, targetPlatform, rootModel) }
48+
.firstOrNull { it.isNotEmpty() } ?: emptyList()
49+
}
50+
51+
fun getLibraryLanguageLevel(
52+
module: Module,
53+
rootModel: ModuleRootModel?,
54+
targetPlatform: TargetPlatformKind<*>?
55+
): LanguageVersion {
56+
val minVersion = getRuntimeLibraryVersions(module, rootModel, targetPlatform ?: TargetPlatformKind.Jvm[JvmTarget.JVM_1_8])
57+
.minWith(VersionComparatorUtil.COMPARATOR)
58+
return getDefaultLanguageLevel(module, minVersion)
59+
}
60+
61+
fun getDefaultLanguageLevel(
62+
module: Module,
63+
explicitVersion: String? = null
64+
): LanguageVersion {
65+
val libVersion = explicitVersion
66+
?: KotlinVersionInfoProvider.EP_NAME.extensions
67+
.mapNotNull { it.getCompilerVersion(module) }
68+
.minWith(VersionComparatorUtil.COMPARATOR)
69+
?: return LanguageVersion.LATEST
70+
return when {
71+
libVersion.startsWith("1.0") -> LanguageVersion.KOTLIN_1_0
72+
else -> LanguageVersion.KOTLIN_1_1
73+
}
74+
}

idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/Platform.kt

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.config.*
2929
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
3030
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
3131
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings
32+
import org.jetbrains.kotlin.idea.facet.getLibraryLanguageLevel
3233
import org.jetbrains.kotlin.psi.KtElement
3334
import org.jetbrains.kotlin.resolve.TargetPlatform
3435

@@ -42,31 +43,58 @@ private val multiPlatformProjectsArg: String by lazy {
4243
"-" + CommonCompilerArguments::multiPlatform.annotations.filterIsInstance<Argument>().single().value
4344
}
4445

45-
val Project.languageVersionSettings: LanguageVersionSettings
46-
get() {
47-
val arguments = KotlinCommonCompilerArgumentsHolder.getInstance(this).settings
48-
val languageVersion = LanguageVersion.fromVersionString(arguments.languageVersion) ?: LanguageVersion.LATEST
49-
val apiVersion = ApiVersion.createByLanguageVersion(LanguageVersion.fromVersionString(arguments.apiVersion) ?: languageVersion)
50-
val compilerSettings = KotlinCompilerSettings.getInstance(this).settings
51-
val extraLanguageFeatures = getExtraLanguageFeatures(
52-
TargetPlatformKind.Common,
53-
CoroutineSupport.byCompilerArguments(KotlinCommonCompilerArgumentsHolder.getInstance(this).settings),
54-
compilerSettings,
55-
null
56-
)
57-
return LanguageVersionSettingsImpl(
58-
languageVersion,
59-
apiVersion,
60-
extraLanguageFeatures
61-
)
46+
private fun Module.getAndCacheLanguageLevelByDependencies(): LanguageVersion {
47+
val languageLevel = getLibraryLanguageLevel(
48+
this,
49+
null,
50+
KotlinFacetSettingsProvider.getInstance(project).getSettings(this).versionInfo.targetPlatformKind
51+
)
52+
53+
// Preserve inferred version in facet/project settings
54+
val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getSettings(this)
55+
if (facetSettings.useProjectSettings) {
56+
with(KotlinCommonCompilerArgumentsHolder.getInstance(project).settings) {
57+
languageVersion = languageLevel.versionString
58+
apiVersion = languageLevel.versionString
59+
}
6260
}
61+
else {
62+
with(facetSettings.versionInfo) {
63+
this.languageLevel = languageLevel
64+
this.apiLevel = languageLevel
65+
}
66+
}
67+
68+
return languageLevel
69+
}
70+
71+
fun Project.getLanguageVersionSettings(contextModule: Module? = null): LanguageVersionSettings {
72+
val arguments = KotlinCommonCompilerArgumentsHolder.getInstance(this).settings
73+
val languageVersion =
74+
LanguageVersion.fromVersionString(arguments.languageVersion)
75+
?: contextModule?.getAndCacheLanguageLevelByDependencies()
76+
?: LanguageVersion.LATEST
77+
val apiVersion = ApiVersion.createByLanguageVersion(LanguageVersion.fromVersionString(arguments.apiVersion) ?: languageVersion)
78+
val compilerSettings = KotlinCompilerSettings.getInstance(this).settings
79+
val extraLanguageFeatures = getExtraLanguageFeatures(
80+
TargetPlatformKind.Common,
81+
CoroutineSupport.byCompilerArguments(KotlinCommonCompilerArgumentsHolder.getInstance(this).settings),
82+
compilerSettings,
83+
null
84+
)
85+
return LanguageVersionSettingsImpl(
86+
languageVersion,
87+
apiVersion,
88+
extraLanguageFeatures
89+
)
90+
}
6391

6492
val Module.languageVersionSettings: LanguageVersionSettings
6593
get() {
6694
val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getSettings(this)
67-
if (facetSettings.useProjectSettings) return project.languageVersionSettings
95+
if (facetSettings.useProjectSettings) return project.getLanguageVersionSettings(this)
6896
val versionInfo = facetSettings.versionInfo
69-
val languageVersion = versionInfo.languageLevel ?: LanguageVersion.LATEST
97+
val languageVersion = versionInfo.languageLevel ?: getAndCacheLanguageLevelByDependencies()
7098
val apiVersion = versionInfo.apiLevel ?: languageVersion
7199

72100
val extraLanguageFeatures = getExtraLanguageFeatures(

idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,8 @@ object KeywordCompletion {
385385
}
386386

387387
private fun isSupportedAtLanguageLevel(keyword: KtKeywordToken, position: PsiElement): Boolean {
388-
val languageVersionSettings = ModuleUtilCore.findModuleForPsiElement(position)?.languageVersionSettings ?: LanguageVersionSettingsImpl.DEFAULT
388+
val languageVersionSettings = ModuleUtilCore.findModuleForPsiElement(position)?.languageVersionSettings
389+
?: LanguageVersionSettingsImpl.DEFAULT
389390
val feature = when (keyword) {
390391
KtTokens.TYPE_ALIAS_KEYWORD -> LanguageFeature.TypeAliases
391392
KtTokens.HEADER_KEYWORD, KtTokens.IMPL_KEYWORD -> LanguageFeature.MultiPlatformProjects

idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/facet/MavenKotlinVersionInfoProvider.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.jetbrains.kotlin.idea.maven.facet
1818

1919
import com.intellij.openapi.module.Module
20+
import com.intellij.openapi.roots.ModuleRootModel
2021
import org.jetbrains.idea.maven.project.MavenProjectsManager
2122
import org.jetbrains.kotlin.config.TargetPlatformKind
2223
import org.jetbrains.kotlin.idea.facet.KotlinVersionInfoProvider
@@ -30,7 +31,7 @@ class MavenKotlinVersionInfoProvider : KotlinVersionInfoProvider {
3031
return mavenProject.findPlugin(KotlinMavenConfigurator.GROUP_ID, KotlinMavenConfigurator.MAVEN_PLUGIN_ID)?.version
3132
}
3233

33-
override fun getLibraryVersions(module: Module, targetPlatform: TargetPlatformKind<*>): Collection<String> {
34+
override fun getLibraryVersions(module: Module, targetPlatform: TargetPlatformKind<*>, rootModel: ModuleRootModel?): Collection<String> {
3435
val projectsManager = MavenProjectsManager.getInstance(module.project)
3536
val mavenProject = projectsManager.findProject(module) ?: return emptyList()
3637
return targetPlatform

idea/src/META-INF/plugin.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2091,6 +2091,7 @@
20912091
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.noarg.NoArgClassBuilderInterceptorExtension"/>
20922092
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.noarg.ide.IdeNoArgComponentContainerContributor"/>
20932093
<defaultErrorMessages implementation="org.jetbrains.kotlin.noarg.diagnostic.DefaultErrorMessagesNoArg"/>
2094+
<versionInfoProvider implementation="org.jetbrains.kotlin.idea.facet.KotlinVersionInfoProviderByModuleDependencies"/>
20942095
</extensions>
20952096

20962097
</idea-plugin>

idea/src/org/jetbrains/kotlin/idea/compiler/LanguageVersionSettingsProviderImpl.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ import com.intellij.openapi.project.Project
2020
import org.jetbrains.kotlin.analyzer.LanguageSettingsProvider
2121
import org.jetbrains.kotlin.analyzer.ModuleInfo
2222
import org.jetbrains.kotlin.config.LanguageVersionSettings
23-
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
2423
import org.jetbrains.kotlin.idea.caches.resolve.ModuleSourceInfo
24+
import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings
2525
import org.jetbrains.kotlin.idea.project.languageVersionSettings
2626
import org.jetbrains.kotlin.idea.project.targetPlatform
2727
import org.jetbrains.kotlin.utils.DescriptionAware
2828

2929
class LanguageVersionSettingsProviderImpl : LanguageSettingsProvider {
3030
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project): LanguageVersionSettings {
31-
return (moduleInfo as? ModuleSourceInfo)?.module?.languageVersionSettings ?: project.languageVersionSettings
31+
return (moduleInfo as? ModuleSourceInfo)?.module?.languageVersionSettings ?: project.getLanguageVersionSettings()
3232
}
3333

3434
override fun getTargetPlatform(moduleInfo: ModuleInfo): DescriptionAware {

idea/src/org/jetbrains/kotlin/idea/configuration/GradleKotlinVersionInfoProvider.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.configuration
1818

1919
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
2020
import com.intellij.openapi.module.Module
21+
import com.intellij.openapi.roots.ModuleRootModel
2122
import org.jetbrains.kotlin.config.TargetPlatformKind
2223
import org.jetbrains.kotlin.idea.facet.KotlinVersionInfoProvider
2324
import org.jetbrains.kotlin.idea.facet.mavenLibraryIds
@@ -44,7 +45,7 @@ class GradleKotlinVersionInfoProvider : KotlinVersionInfoProvider {
4445
return runReadAction { getGradleFile(module)?.let { DifferentKotlinGradleVersionInspection.getKotlinPluginVersion(it) } }
4546
}
4647

47-
override fun getLibraryVersions(module: Module, targetPlatform: TargetPlatformKind<*>): Collection<String> {
48+
override fun getLibraryVersions(module: Module, targetPlatform: TargetPlatformKind<*>, rootModel: ModuleRootModel?): Collection<String> {
4849
return runReadAction {
4950
getGradleFile(module)?.let {
5051
DifferentStdlibGradleVersionInspection.getKotlinStdlibVersions(it, targetPlatform.mavenLibraryIds)

idea/src/org/jetbrains/kotlin/idea/facet/FrameworkLibraryValidatorWithDynamicDescription.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ class FrameworkLibraryValidatorWithDynamicDescription(
5252
// TODO: propose to configure kotlin-stdlib-common once it's available
5353
if (targetPlatform == TargetPlatformKind.Common) return true
5454

55-
if (KotlinVersionInfoProvider.EP_NAME.extensions.any { it.getLibraryVersions(context.module, targetPlatform).isNotEmpty() }) return true
55+
if (KotlinVersionInfoProvider.EP_NAME.extensions.any {
56+
it.getLibraryVersions(context.module, targetPlatform, context.rootModel).isNotEmpty()
57+
}) return true
5658

5759
val libraryDescription = targetPlatform.libraryDescription
5860
val libraryKinds = libraryDescription.suitableLibraryKinds

idea/src/org/jetbrains/kotlin/idea/facet/KotlinVersionInfoProvider.kt

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2010-2017 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.jetbrains.kotlin.idea.facet
18+
19+
import com.intellij.openapi.module.Module
20+
import com.intellij.openapi.roots.LibraryOrderEntry
21+
import com.intellij.openapi.roots.ModuleRootManager
22+
import com.intellij.openapi.roots.ModuleRootModel
23+
import com.intellij.openapi.roots.OrderRootType
24+
import org.jetbrains.kotlin.config.TargetPlatformKind
25+
import org.jetbrains.kotlin.idea.framework.JSLibraryStdPresentationProvider
26+
import org.jetbrains.kotlin.idea.framework.JavaRuntimePresentationProvider
27+
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
28+
29+
class KotlinVersionInfoProviderByModuleDependencies : KotlinVersionInfoProvider {
30+
override fun getCompilerVersion(module: Module) = bundledRuntimeVersion()
31+
32+
override fun getLibraryVersions(module: Module, targetPlatform: TargetPlatformKind<*>, rootModel: ModuleRootModel?): Collection<String> {
33+
val presentationProvider = when (targetPlatform) {
34+
is TargetPlatformKind.JavaScript -> JSLibraryStdPresentationProvider.getInstance()
35+
is TargetPlatformKind.Jvm -> JavaRuntimePresentationProvider.getInstance()
36+
is TargetPlatformKind.Common -> return emptyList()
37+
}
38+
return (rootModel ?: ModuleRootManager.getInstance(module))
39+
.orderEntries
40+
.asSequence()
41+
.filterIsInstance<LibraryOrderEntry>()
42+
.mapNotNull { it.library?.let { presentationProvider.detect(it.getFiles(OrderRootType.CLASSES).toList())?.versionString } }
43+
.toList()
44+
}
45+
}

0 commit comments

Comments
 (0)