Kotlin Facet: Detect language/API version by stdlib when "Use project settings" is enabled, but project-level language/api version is not specified explicitly

This commit is contained in:
Alexey Sedunov
2017-02-15 12:25:37 +03:00
parent 0d2122bb1d
commit 2e01f62afe
14 changed files with 186 additions and 114 deletions
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.platform.JvmBuiltIns
import org.jetbrains.kotlin.resolve.TargetPlatform
@@ -74,7 +74,7 @@ class BuiltInsCache private constructor(
val builtInsCache = BuiltInsCache(project, platform, sdk, sdkModuleDescriptor, sdkContext)
if (sdkBuiltIns is JvmBuiltIns) {
val isAdditionalBuiltInsFeatureSupported = project.languageVersionSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)
val isAdditionalBuiltInsFeatureSupported = project.getLanguageVersionSettings().supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)
sdkBuiltIns.initialize(
sdkModuleDescriptor!!, // sdk is not null for JvmBuiltIns because of calculateBuiltIns
isAdditionalBuiltInsFeatureSupported)
@@ -0,0 +1,74 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.facet
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ModuleRootModel
import com.intellij.util.text.VersionComparatorUtil
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.TargetPlatformKind
interface KotlinVersionInfoProvider {
companion object {
val EP_NAME: ExtensionPointName<KotlinVersionInfoProvider> = ExtensionPointName.create("org.jetbrains.kotlin.versionInfoProvider")!!
}
fun getCompilerVersion(module: Module): String?
fun getLibraryVersions(
module: Module,
targetPlatform: TargetPlatformKind<*>,
rootModel: ModuleRootModel?
): Collection<String>
}
fun getRuntimeLibraryVersions(
module: Module,
rootModel: ModuleRootModel?,
targetPlatform: TargetPlatformKind<*>
): Collection<String> {
return KotlinVersionInfoProvider.EP_NAME
.extensions
.map { it.getLibraryVersions(module, targetPlatform, rootModel) }
.firstOrNull { it.isNotEmpty() } ?: emptyList()
}
fun getLibraryLanguageLevel(
module: Module,
rootModel: ModuleRootModel?,
targetPlatform: TargetPlatformKind<*>?
): LanguageVersion {
val minVersion = getRuntimeLibraryVersions(module, rootModel, targetPlatform ?: TargetPlatformKind.Jvm[JvmTarget.JVM_1_8])
.minWith(VersionComparatorUtil.COMPARATOR)
return getDefaultLanguageLevel(module, minVersion)
}
fun getDefaultLanguageLevel(
module: Module,
explicitVersion: String? = null
): LanguageVersion {
val libVersion = explicitVersion
?: KotlinVersionInfoProvider.EP_NAME.extensions
.mapNotNull { it.getCompilerVersion(module) }
.minWith(VersionComparatorUtil.COMPARATOR)
?: return LanguageVersion.LATEST
return when {
libVersion.startsWith("1.0") -> LanguageVersion.KOTLIN_1_0
else -> LanguageVersion.KOTLIN_1_1
}
}
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings
import org.jetbrains.kotlin.idea.facet.getLibraryLanguageLevel
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.TargetPlatform
@@ -42,31 +43,58 @@ private val multiPlatformProjectsArg: String by lazy {
"-" + CommonCompilerArguments::multiPlatform.annotations.filterIsInstance<Argument>().single().value
}
val Project.languageVersionSettings: LanguageVersionSettings
get() {
val arguments = KotlinCommonCompilerArgumentsHolder.getInstance(this).settings
val languageVersion = LanguageVersion.fromVersionString(arguments.languageVersion) ?: LanguageVersion.LATEST
val apiVersion = ApiVersion.createByLanguageVersion(LanguageVersion.fromVersionString(arguments.apiVersion) ?: languageVersion)
val compilerSettings = KotlinCompilerSettings.getInstance(this).settings
val extraLanguageFeatures = getExtraLanguageFeatures(
TargetPlatformKind.Common,
CoroutineSupport.byCompilerArguments(KotlinCommonCompilerArgumentsHolder.getInstance(this).settings),
compilerSettings,
null
)
return LanguageVersionSettingsImpl(
languageVersion,
apiVersion,
extraLanguageFeatures
)
private fun Module.getAndCacheLanguageLevelByDependencies(): LanguageVersion {
val languageLevel = getLibraryLanguageLevel(
this,
null,
KotlinFacetSettingsProvider.getInstance(project).getSettings(this).versionInfo.targetPlatformKind
)
// Preserve inferred version in facet/project settings
val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getSettings(this)
if (facetSettings.useProjectSettings) {
with(KotlinCommonCompilerArgumentsHolder.getInstance(project).settings) {
languageVersion = languageLevel.versionString
apiVersion = languageLevel.versionString
}
}
else {
with(facetSettings.versionInfo) {
this.languageLevel = languageLevel
this.apiLevel = languageLevel
}
}
return languageLevel
}
fun Project.getLanguageVersionSettings(contextModule: Module? = null): LanguageVersionSettings {
val arguments = KotlinCommonCompilerArgumentsHolder.getInstance(this).settings
val languageVersion =
LanguageVersion.fromVersionString(arguments.languageVersion)
?: contextModule?.getAndCacheLanguageLevelByDependencies()
?: LanguageVersion.LATEST
val apiVersion = ApiVersion.createByLanguageVersion(LanguageVersion.fromVersionString(arguments.apiVersion) ?: languageVersion)
val compilerSettings = KotlinCompilerSettings.getInstance(this).settings
val extraLanguageFeatures = getExtraLanguageFeatures(
TargetPlatformKind.Common,
CoroutineSupport.byCompilerArguments(KotlinCommonCompilerArgumentsHolder.getInstance(this).settings),
compilerSettings,
null
)
return LanguageVersionSettingsImpl(
languageVersion,
apiVersion,
extraLanguageFeatures
)
}
val Module.languageVersionSettings: LanguageVersionSettings
get() {
val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getSettings(this)
if (facetSettings.useProjectSettings) return project.languageVersionSettings
if (facetSettings.useProjectSettings) return project.getLanguageVersionSettings(this)
val versionInfo = facetSettings.versionInfo
val languageVersion = versionInfo.languageLevel ?: LanguageVersion.LATEST
val languageVersion = versionInfo.languageLevel ?: getAndCacheLanguageLevelByDependencies()
val apiVersion = versionInfo.apiLevel ?: languageVersion
val extraLanguageFeatures = getExtraLanguageFeatures(
@@ -385,7 +385,8 @@ object KeywordCompletion {
}
private fun isSupportedAtLanguageLevel(keyword: KtKeywordToken, position: PsiElement): Boolean {
val languageVersionSettings = ModuleUtilCore.findModuleForPsiElement(position)?.languageVersionSettings ?: LanguageVersionSettingsImpl.DEFAULT
val languageVersionSettings = ModuleUtilCore.findModuleForPsiElement(position)?.languageVersionSettings
?: LanguageVersionSettingsImpl.DEFAULT
val feature = when (keyword) {
KtTokens.TYPE_ALIAS_KEYWORD -> LanguageFeature.TypeAliases
KtTokens.HEADER_KEYWORD, KtTokens.IMPL_KEYWORD -> LanguageFeature.MultiPlatformProjects
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.maven.facet
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ModuleRootModel
import org.jetbrains.idea.maven.project.MavenProjectsManager
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.idea.facet.KotlinVersionInfoProvider
@@ -30,7 +31,7 @@ class MavenKotlinVersionInfoProvider : KotlinVersionInfoProvider {
return mavenProject.findPlugin(KotlinMavenConfigurator.GROUP_ID, KotlinMavenConfigurator.MAVEN_PLUGIN_ID)?.version
}
override fun getLibraryVersions(module: Module, targetPlatform: TargetPlatformKind<*>): Collection<String> {
override fun getLibraryVersions(module: Module, targetPlatform: TargetPlatformKind<*>, rootModel: ModuleRootModel?): Collection<String> {
val projectsManager = MavenProjectsManager.getInstance(module.project)
val mavenProject = projectsManager.findProject(module) ?: return emptyList()
return targetPlatform
+1
View File
@@ -2091,6 +2091,7 @@
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.noarg.NoArgClassBuilderInterceptorExtension"/>
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.noarg.ide.IdeNoArgComponentContainerContributor"/>
<defaultErrorMessages implementation="org.jetbrains.kotlin.noarg.diagnostic.DefaultErrorMessagesNoArg"/>
<versionInfoProvider implementation="org.jetbrains.kotlin.idea.facet.KotlinVersionInfoProviderByModuleDependencies"/>
</extensions>
</idea-plugin>
@@ -20,15 +20,15 @@ import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.LanguageSettingsProvider
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.idea.caches.resolve.ModuleSourceInfo
import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.project.targetPlatform
import org.jetbrains.kotlin.utils.DescriptionAware
class LanguageVersionSettingsProviderImpl : LanguageSettingsProvider {
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project): LanguageVersionSettings {
return (moduleInfo as? ModuleSourceInfo)?.module?.languageVersionSettings ?: project.languageVersionSettings
return (moduleInfo as? ModuleSourceInfo)?.module?.languageVersionSettings ?: project.getLanguageVersionSettings()
}
override fun getTargetPlatform(moduleInfo: ModuleInfo): DescriptionAware {
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.configuration
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ModuleRootModel
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.idea.facet.KotlinVersionInfoProvider
import org.jetbrains.kotlin.idea.facet.mavenLibraryIds
@@ -44,7 +45,7 @@ class GradleKotlinVersionInfoProvider : KotlinVersionInfoProvider {
return runReadAction { getGradleFile(module)?.let { DifferentKotlinGradleVersionInspection.getKotlinPluginVersion(it) } }
}
override fun getLibraryVersions(module: Module, targetPlatform: TargetPlatformKind<*>): Collection<String> {
override fun getLibraryVersions(module: Module, targetPlatform: TargetPlatformKind<*>, rootModel: ModuleRootModel?): Collection<String> {
return runReadAction {
getGradleFile(module)?.let {
DifferentStdlibGradleVersionInspection.getKotlinStdlibVersions(it, targetPlatform.mavenLibraryIds)
@@ -52,7 +52,9 @@ class FrameworkLibraryValidatorWithDynamicDescription(
// TODO: propose to configure kotlin-stdlib-common once it's available
if (targetPlatform == TargetPlatformKind.Common) return true
if (KotlinVersionInfoProvider.EP_NAME.extensions.any { it.getLibraryVersions(context.module, targetPlatform).isNotEmpty() }) return true
if (KotlinVersionInfoProvider.EP_NAME.extensions.any {
it.getLibraryVersions(context.module, targetPlatform, context.rootModel).isNotEmpty()
}) return true
val libraryDescription = targetPlatform.libraryDescription
val libraryKinds = libraryDescription.suitableLibraryKinds
@@ -1,30 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.facet
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.module.Module
import org.jetbrains.kotlin.config.TargetPlatformKind
interface KotlinVersionInfoProvider {
companion object {
val EP_NAME: ExtensionPointName<KotlinVersionInfoProvider> = ExtensionPointName.create("org.jetbrains.kotlin.versionInfoProvider")!!
}
fun getCompilerVersion(module: Module): String?
fun getLibraryVersions(module: Module, targetPlatform: TargetPlatformKind<*>): Collection<String>
}
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.facet
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.ModuleRootModel
import com.intellij.openapi.roots.OrderRootType
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.idea.framework.JSLibraryStdPresentationProvider
import org.jetbrains.kotlin.idea.framework.JavaRuntimePresentationProvider
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
class KotlinVersionInfoProviderByModuleDependencies : KotlinVersionInfoProvider {
override fun getCompilerVersion(module: Module) = bundledRuntimeVersion()
override fun getLibraryVersions(module: Module, targetPlatform: TargetPlatformKind<*>, rootModel: ModuleRootModel?): Collection<String> {
val presentationProvider = when (targetPlatform) {
is TargetPlatformKind.JavaScript -> JSLibraryStdPresentationProvider.getInstance()
is TargetPlatformKind.Jvm -> JavaRuntimePresentationProvider.getInstance()
is TargetPlatformKind.Common -> return emptyList()
}
return (rootModel ?: ModuleRootManager.getInstance(module))
.orderEntries
.asSequence()
.filterIsInstance<LibraryOrderEntry>()
.mapNotNull { it.library?.let { presentationProvider.detect(it.getFiles(OrderRootType.CLASSES).toList())?.versionString } }
.toList()
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,10 +20,8 @@ import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsPr
import com.intellij.openapi.module.Module
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.JavaSdkVersion
import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.ModuleRootModel
import com.intellij.openapi.roots.OrderRootType
import com.intellij.util.text.VersionComparatorUtil
import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
@@ -32,36 +30,9 @@ import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JsCompilerArgumen
import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JvmCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings
import org.jetbrains.kotlin.idea.framework.JSLibraryStdPresentationProvider
import org.jetbrains.kotlin.idea.framework.JavaRuntimePresentationProvider
import org.jetbrains.kotlin.idea.versions.*
import java.lang.reflect.Field
private fun getRuntimeLibraryVersions(
module: Module,
rootModel: ModuleRootModel?,
targetPlatform: TargetPlatformKind<*>
): Collection<String> {
val presentationProvider = when (targetPlatform) {
is TargetPlatformKind.JavaScript -> JSLibraryStdPresentationProvider.getInstance()
is TargetPlatformKind.Jvm -> JavaRuntimePresentationProvider.getInstance()
is TargetPlatformKind.Common -> return emptyList()
}
KotlinVersionInfoProvider.EP_NAME
.extensions
.map { it.getLibraryVersions(module, targetPlatform) }
.firstOrNull { it.isNotEmpty() }
?.let { return it }
return (rootModel ?: ModuleRootManager.getInstance(module))
.orderEntries
.asSequence()
.filterIsInstance<LibraryOrderEntry>()
.mapNotNull { it.library?.let { presentationProvider.detect(it.getFiles(OrderRootType.CLASSES).toList())?.versionString } }
.toList()
}
private fun getDefaultTargetPlatform(module: Module, rootModel: ModuleRootModel?): TargetPlatformKind<*> {
if (getRuntimeLibraryVersions(module, rootModel, TargetPlatformKind.JavaScript).isNotEmpty()) {
return TargetPlatformKind.JavaScript
@@ -78,31 +49,6 @@ private fun getDefaultTargetPlatform(module: Module, rootModel: ModuleRootModel?
}
}
private fun getDefaultLanguageLevel(
module: Module,
explicitVersion: String? = null
): LanguageVersion {
val libVersion = explicitVersion
?: KotlinVersionInfoProvider.EP_NAME.extensions
.mapNotNull { it.getCompilerVersion(module) }
.minWith(VersionComparatorUtil.COMPARATOR)
?: bundledRuntimeVersion()
return when {
libVersion.startsWith("1.0") -> LanguageVersion.KOTLIN_1_0
else -> LanguageVersion.KOTLIN_1_1
}
}
internal fun getLibraryLanguageLevel(
module: Module,
rootModel: ModuleRootModel?,
targetPlatform: TargetPlatformKind<*>?
): LanguageVersion {
val minVersion = getRuntimeLibraryVersions(module, rootModel, targetPlatform ?: TargetPlatformKind.Jvm[JvmTarget.JVM_1_8])
.minWith(VersionComparatorUtil.COMPARATOR)
return getDefaultLanguageLevel(module, minVersion)
}
fun KotlinFacetSettings.initializeIfNeeded(module: Module, rootModel: ModuleRootModel?) {
val project = module.project
@@ -23,7 +23,10 @@ import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.KtVisitorVoid
import org.jetbrains.kotlin.resolve.deprecatedByOverriddenMessage
import org.jetbrains.kotlin.resolve.getDeprecations
@@ -26,7 +26,7 @@ import com.intellij.util.Query
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.*
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection