Modules with different language levels can't be analyzed together

"Supports additional builtIn members" setting
    is basically adding members to some types
If we analyze them toghether other modules would leak types
    that have those members (or don't) into other modules scopes
    leading to code that has erroneous highlighting

See KT-17357

#KT-17357 Fixed
This commit is contained in:
Pavel V. Talanov
2017-05-19 23:28:34 +03:00
parent eedc35aefd
commit 8fc953f529
8 changed files with 124 additions and 144 deletions
@@ -165,7 +165,7 @@ abstract class AnalyzerFacade<in P : PlatformAnalysisParameters> {
modulesContent: (M) -> ModuleContent, modulesContent: (M) -> ModuleContent,
platformParameters: P, platformParameters: P,
targetEnvironment: TargetEnvironment = CompilerEnvironment, targetEnvironment: TargetEnvironment = CompilerEnvironment,
builtIns: (M) -> KotlinBuiltIns = { DefaultBuiltIns.Instance }, builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance,
delegateResolver: ResolverForProject<M> = EmptyResolverForProject(), delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty }, packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty },
firstDependency: M? = null, firstDependency: M? = null,
@@ -175,7 +175,7 @@ abstract class AnalyzerFacade<in P : PlatformAnalysisParameters> {
val storageManager = projectContext.storageManager val storageManager = projectContext.storageManager
val resolverForProject = ResolverForProjectImpl(debugName, modules.keysToMap { module -> val resolverForProject = ResolverForProjectImpl(debugName, modules.keysToMap { module ->
ModuleDescriptorImpl(module.name, storageManager, builtIns(module), modulePlatforms(module), module.capabilities) ModuleDescriptorImpl(module.name, storageManager, builtIns, modulePlatforms(module), module.capabilities)
}, delegateResolver) }, delegateResolver)
for (module in modules) { for (module in modules) {
@@ -76,7 +76,7 @@ class MultiModuleJavaAnalysisCustomTest : KtUsefulTestCase() {
val moduleName = javaClass.name.asString().toLowerCase().first().toString() val moduleName = javaClass.name.asString().toLowerCase().first().toString()
modules.first { it._name == moduleName } modules.first { it._name == moduleName }
}, },
builtIns = { builtIns }, builtIns = builtIns,
modulePlatforms = { MultiTargetPlatform.Specific("JVM") } modulePlatforms = { MultiTargetPlatform.Specific("JVM") }
) )
@@ -1,86 +0,0 @@
/*
* 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.caches.resolve
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.util.containers.SLRUCache
import org.jetbrains.kotlin.analyzer.LanguageSettingsProvider
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
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.getLanguageVersionSettings
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.platform.JvmBuiltIns
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
class BuiltInsCache private constructor(
private val project: Project,
platform: TargetPlatform,
sdk: Sdk?,
sdkModuleDescriptor: ModuleDescriptor?,
sdkContext: GlobalContextImpl
) {
private val cache: SLRUCache<Boolean, KotlinBuiltIns> = object : SLRUCache<Boolean, KotlinBuiltIns>(2, 2) {
override fun createValue(key: Boolean): KotlinBuiltIns {
val builtIns = calculateBuiltIns(platform, sdk, sdkContext)
if (builtIns is JvmBuiltIns) {
builtIns.initialize(sdkModuleDescriptor!!, key)
}
return builtIns
}
}
fun getBuiltIns(moduleInfo: ModuleInfo): KotlinBuiltIns {
val languageFeatureSettings = LanguageSettingsProvider.getInstance(project).getLanguageVersionSettings(moduleInfo, project)
return cache.get(languageFeatureSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers))
}
companion object {
fun calculateBuiltIns(platform: TargetPlatform, sdk: Sdk?, sdkContext: GlobalContextImpl): KotlinBuiltIns = when {
platform is JsPlatform -> JsPlatform.builtIns
platform is JvmPlatform && sdk != null -> JvmBuiltIns(sdkContext.storageManager)
else -> DefaultBuiltIns.Instance
}
fun createCacheAndInitializeBuiltIns(
project: Project,
platform: TargetPlatform,
sdk: Sdk?,
sdkModuleDescriptor: ModuleDescriptor?,
sdkBuiltIns: KotlinBuiltIns,
sdkContext: GlobalContextImpl
): BuiltInsCache {
val builtInsCache = BuiltInsCache(project, platform, sdk, sdkModuleDescriptor, sdkContext)
if (sdkBuiltIns is JvmBuiltIns) {
val isAdditionalBuiltInsFeatureSupported = project.getLanguageVersionSettings().supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)
sdkBuiltIns.initialize(
sdkModuleDescriptor!!, // sdk is not null for JvmBuiltIns because of calculateBuiltIns
isAdditionalBuiltInsFeatureSupported)
builtInsCache.cache.put(isAdditionalBuiltInsFeatureSupported, sdkBuiltIns)
}
return builtInsCache
}
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.caches.resolve package org.jetbrains.kotlin.idea.caches.resolve
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.Sdk
@@ -29,8 +30,10 @@ import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.PsiModificationTracker
import com.intellij.util.containers.SLRUCache import com.intellij.util.containers.SLRUCache
import org.jetbrains.kotlin.analyzer.EmptyResolverForProject import org.jetbrains.kotlin.analyzer.EmptyResolverForProject
import org.jetbrains.kotlin.analyzer.LanguageSettingsProvider
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.container.getService import org.jetbrains.kotlin.container.getService
import org.jetbrains.kotlin.container.tryGetService import org.jetbrains.kotlin.container.tryGetService
import org.jetbrains.kotlin.context.GlobalContext import org.jetbrains.kotlin.context.GlobalContext
@@ -54,6 +57,11 @@ import java.lang.IllegalStateException
internal val LOG = Logger.getInstance(KotlinCacheService::class.java) internal val LOG = Logger.getInstance(KotlinCacheService::class.java)
// For every different instance of these settings we must create a different builtIns instance and thus a different moduleDescriptor graph
// since in the current implementation types from one module are leaking into other modules' resolution
// meaning that we can't just change those setting on a per module basis
data class PlatformAnalysisSettings(val platform: TargetPlatform, val sdk: Sdk?, val isAdditionalBuiltInFeaturesSupported: Boolean)
class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
override fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade { override fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade {
return getFacadeToAnalyzeFiles(elements.map { it.containingKtFile }) return getFacadeToAnalyzeFiles(elements.map { it.containingKtFile })
@@ -61,10 +69,10 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
override fun getSuppressionCache(): KotlinSuppressCache = kotlinSuppressCache.value override fun getSuppressionCache(): KotlinSuppressCache = kotlinSuppressCache.value
private val globalFacadesPerPlatformAndSdk: SLRUCache<Pair<TargetPlatform, Sdk?>, GlobalFacade> = private val globalFacadesPerPlatformAndSdk: SLRUCache<PlatformAnalysisSettings, GlobalFacade> =
object : SLRUCache<Pair<TargetPlatform, Sdk?>, GlobalFacade>(2 * 3, 2 * 3) { object : SLRUCache<PlatformAnalysisSettings, GlobalFacade>(2 * 3 * 2, 2 * 3 * 2) {
override fun createValue(key: Pair<TargetPlatform, Sdk?>): GlobalFacade { override fun createValue(settings: PlatformAnalysisSettings): GlobalFacade {
return GlobalFacade(key.first, key.second) return GlobalFacade(settings)
} }
} }
@@ -87,15 +95,15 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
): ProjectResolutionFacade { ): ProjectResolutionFacade {
val sdk = findJdk(dependenciesModuleInfo.dependencies, project) val sdk = findJdk(dependenciesModuleInfo.dependencies, project)
val platform = JvmPlatform // TODO: Js scripts? val platform = JvmPlatform // TODO: Js scripts?
val sdkFacade = GlobalFacade(platform, sdk).facadeForSdk val facadeKey = PlatformAnalysisSettings(platform, sdk, true)
val sdkFacade = GlobalFacade(facadeKey).facadeForSdk
val globalContext = sdkFacade.globalContext.contextWithNewLockAndCompositeExceptionTracker() val globalContext = sdkFacade.globalContext.contextWithNewLockAndCompositeExceptionTracker()
return ProjectResolutionFacade( return ProjectResolutionFacade(
"facadeForScriptDependencies", "facadeForScriptDependencies",
project, globalContext, project, globalContext,
globalResolveSessionProvider( globalResolveSessionProvider(
"dependencies of scripts", "dependencies of scripts",
platform, facadeKey,
sdk,
reuseDataFrom = sdkFacade, reuseDataFrom = sdkFacade,
allModules = dependenciesModuleInfo.dependencies(), allModules = dependenciesModuleInfo.dependencies(),
//TODO: provide correct trackers //TODO: provide correct trackers
@@ -111,15 +119,14 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
} }
private inner class GlobalFacade(platform: TargetPlatform, sdk: Sdk?) { private inner class GlobalFacade(settings: PlatformAnalysisSettings) {
private val sdkContext = GlobalContext() private val sdkContext = GlobalContext()
val facadeForSdk = ProjectResolutionFacade( val facadeForSdk = ProjectResolutionFacade(
"facadeForSdk", "facadeForSdk",
project, sdkContext, project, sdkContext,
globalResolveSessionProvider( globalResolveSessionProvider(
"sdk $sdk", "sdk ${settings.sdk}",
platform, settings,
sdk,
moduleFilter = { it is SdkInfo }, moduleFilter = { it is SdkInfo },
dependencies = listOf( dependencies = listOf(
LibraryModificationTracker.getInstance(project), LibraryModificationTracker.getInstance(project),
@@ -132,9 +139,8 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
"facadeForLibraries", "facadeForLibraries",
project, librariesContext, project, librariesContext,
globalResolveSessionProvider( globalResolveSessionProvider(
"project libraries for platform $platform", "project libraries for platform ${settings.sdk}",
platform, settings,
sdk,
reuseDataFrom = facadeForSdk, reuseDataFrom = facadeForSdk,
moduleFilter = { it is LibraryInfo }, moduleFilter = { it is LibraryInfo },
dependencies = listOf( dependencies = listOf(
@@ -150,9 +156,8 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
"facadeForModules", "facadeForModules",
project, modulesContext, project, modulesContext,
globalResolveSessionProvider( globalResolveSessionProvider(
"project source roots and libraries for platform $platform", "project source roots and libraries for platform ${settings.platform}",
platform, settings,
sdk,
reuseDataFrom = facadeForLibraries, reuseDataFrom = facadeForLibraries,
moduleFilter = { !it.isLibraryClasses() }, moduleFilter = { !it.isLibraryClasses() },
dependencies = listOf(PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)) dependencies = listOf(PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT))
@@ -161,20 +166,28 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
@Deprecated("Use JetElement.getResolutionFacade(), please avoid introducing new usages") @Deprecated("Use JetElement.getResolutionFacade(), please avoid introducing new usages")
fun <T : Any> getProjectService(platform: TargetPlatform, ideaModuleInfo: IdeaModuleInfo, serviceClass: Class<T>): T { fun <T : Any> getProjectService(platform: TargetPlatform, ideaModuleInfo: IdeaModuleInfo, serviceClass: Class<T>): T {
return globalFacade(platform, ideaModuleInfo.sdk).resolverForModuleInfo(ideaModuleInfo).componentProvider.getService(serviceClass) val settings = PlatformAnalysisSettings(platform, ideaModuleInfo.sdk, ideaModuleInfo.supportsAdditionalBuiltInsMembers())
return globalFacade(settings).resolverForModuleInfo(ideaModuleInfo).componentProvider.getService(serviceClass)
}
private fun IdeaModuleInfo.supportsAdditionalBuiltInsMembers(): Boolean {
return project.service<LanguageSettingsProvider>()
.getLanguageVersionSettings(this, project)
.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)
} }
fun <T : Any> tryGetProjectService(platform: TargetPlatform, ideaModuleInfo: IdeaModuleInfo, serviceClass: Class<T>): T? { fun <T : Any> tryGetProjectService(platform: TargetPlatform, ideaModuleInfo: IdeaModuleInfo, serviceClass: Class<T>): T? {
return globalFacade(platform, ideaModuleInfo.sdk).tryGetResolverForModuleInfo(ideaModuleInfo)?.componentProvider?.tryGetService(serviceClass) val settings = PlatformAnalysisSettings(platform, ideaModuleInfo.sdk, ideaModuleInfo.supportsAdditionalBuiltInsMembers())
return globalFacade(settings).tryGetResolverForModuleInfo(ideaModuleInfo)?.componentProvider?.tryGetService(serviceClass)
} }
private fun globalFacade(platform: TargetPlatform, sdk: Sdk?) = private fun globalFacade(settings: PlatformAnalysisSettings) =
getOrBuildGlobalFacade(platform, sdk).facadeForModules getOrBuildGlobalFacade(settings).facadeForModules
private fun librariesFacade(platform: TargetPlatform, sdk: Sdk?) = getOrBuildGlobalFacade(platform, sdk).facadeForLibraries private fun librariesFacade(settings: PlatformAnalysisSettings) = getOrBuildGlobalFacade(settings).facadeForLibraries
@Synchronized @Synchronized
private fun getOrBuildGlobalFacade(platform: TargetPlatform, sdk: Sdk?) = globalFacadesPerPlatformAndSdk[Pair(platform, sdk)] private fun getOrBuildGlobalFacade(settings: PlatformAnalysisSettings) = globalFacadesPerPlatformAndSdk[settings]
private val IdeaModuleInfo.sdk: Sdk? get() = dependencies().firstIsInstanceOrNull<SdkInfo>()?.sdk private val IdeaModuleInfo.sdk: Sdk? get() = dependencies().firstIsInstanceOrNull<SdkInfo>()?.sdk
@@ -183,6 +196,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
val targetPlatform = files.map { TargetPlatformDetector.getPlatform(it) }.toSet().single() val targetPlatform = files.map { TargetPlatformDetector.getPlatform(it) }.toSet().single()
val syntheticFileModule = files.map(KtFile::getModuleInfo).toSet().single() val syntheticFileModule = files.map(KtFile::getModuleInfo).toSet().single()
val sdk = syntheticFileModule.sdk val sdk = syntheticFileModule.sdk
val settings = PlatformAnalysisSettings(targetPlatform, sdk, syntheticFileModule.supportsAdditionalBuiltInsMembers())
val filesModificationTracker: ModificationTracker val filesModificationTracker: ModificationTracker
// File copies are created during completion and receive correct modification events through POM. // File copies are created during completion and receive correct modification events through POM.
// Dummy files created e.g. by J2K do not receive events. // Dummy files created e.g. by J2K do not receive events.
@@ -205,8 +219,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
): (GlobalContextImpl, Project) -> ModuleResolverProvider { ): (GlobalContextImpl, Project) -> ModuleResolverProvider {
return globalResolveSessionProvider( return globalResolveSessionProvider(
debugName, debugName,
targetPlatform, settings,
sdk,
syntheticFiles = files, syntheticFiles = files,
reuseDataFrom = reuseDataFrom, reuseDataFrom = reuseDataFrom,
moduleFilter = moduleFilter, moduleFilter = moduleFilter,
@@ -218,7 +231,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
return when { return when {
syntheticFileModule is ModuleSourceInfo -> { syntheticFileModule is ModuleSourceInfo -> {
val dependentModules = syntheticFileModule.getDependentModules() val dependentModules = syntheticFileModule.getDependentModules()
val modulesFacade = globalFacade(targetPlatform, sdk) val modulesFacade = globalFacade(settings)
val globalContext = modulesFacade.globalContext.contextWithNewLockAndCompositeExceptionTracker() val globalContext = modulesFacade.globalContext.contextWithNewLockAndCompositeExceptionTracker()
ProjectResolutionFacade( ProjectResolutionFacade(
"facadeForSynthetic in ModuleSourceInfo", "facadeForSynthetic in ModuleSourceInfo",
@@ -261,7 +274,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
} }
syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> { syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> {
val librariesFacade = librariesFacade(targetPlatform, sdk) val librariesFacade = librariesFacade(settings)
val globalContext = librariesFacade.globalContext.contextWithNewLockAndCompositeExceptionTracker() val globalContext = librariesFacade.globalContext.contextWithNewLockAndCompositeExceptionTracker()
ProjectResolutionFacade( ProjectResolutionFacade(
"facadeForSynthetic in LibrarySourceInfo or NotUnderContentRootModuleInfo", "facadeForSynthetic in LibrarySourceInfo or NotUnderContentRootModuleInfo",
@@ -362,7 +375,8 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
} }
private fun getResolutionFacadeByModuleInfo(moduleInfo: IdeaModuleInfo, platform: TargetPlatform): ResolutionFacade { private fun getResolutionFacadeByModuleInfo(moduleInfo: IdeaModuleInfo, platform: TargetPlatform): ResolutionFacade {
val projectFacade = globalFacade(platform, moduleInfo.sdk) val settings = PlatformAnalysisSettings(platform, moduleInfo.sdk, moduleInfo.supportsAdditionalBuiltInsMembers())
val projectFacade = globalFacade(settings)
return ResolutionFacadeImpl(projectFacade, moduleInfo) return ResolutionFacadeImpl(projectFacade, moduleInfo)
} }
@@ -382,8 +396,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
private fun globalResolveSessionProvider( private fun globalResolveSessionProvider(
debugName: String, debugName: String,
platform: TargetPlatform, settings: PlatformAnalysisSettings,
sdk: Sdk?,
dependencies: Collection<Any>, dependencies: Collection<Any>,
moduleFilter: (IdeaModuleInfo) -> Boolean, moduleFilter: (IdeaModuleInfo) -> Boolean,
reuseDataFrom: ProjectResolutionFacade? = null, reuseDataFrom: ProjectResolutionFacade? = null,
@@ -394,11 +407,10 @@ private fun globalResolveSessionProvider(
val delegateResolverForProject = delegateResolverProvider?.resolverForProject ?: EmptyResolverForProject() val delegateResolverForProject = delegateResolverProvider?.resolverForProject ?: EmptyResolverForProject()
createModuleResolverProvider( createModuleResolverProvider(
debugName, project, globalContext, sdk, debugName, project, globalContext, settings,
platform,
syntheticFiles, delegateResolverForProject, moduleFilter, syntheticFiles, delegateResolverForProject, moduleFilter,
allModules, allModules,
delegateResolverProvider?.builtInsCache, delegateResolverProvider?.builtIns,
dependencies dependencies
) )
} }
@@ -26,39 +26,34 @@ import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ModuleRootManager
import org.jetbrains.kotlin.analyzer.AnalyzerFacade import org.jetbrains.kotlin.analyzer.AnalyzerFacade
import org.jetbrains.kotlin.analyzer.ModuleContent import org.jetbrains.kotlin.analyzer.ModuleContent
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.ResolverForProject import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.context.GlobalContextImpl import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.context.withProject import org.jetbrains.kotlin.context.withProject
import org.jetbrains.kotlin.idea.project.AnalyzerFacadeProvider import org.jetbrains.kotlin.idea.project.AnalyzerFacadeProvider
import org.jetbrains.kotlin.idea.project.IdeaEnvironment import org.jetbrains.kotlin.idea.project.IdeaEnvironment
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
import org.jetbrains.kotlin.platform.JvmBuiltIns
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
fun createModuleResolverProvider( fun createModuleResolverProvider(
debugName: String, debugName: String,
project: Project, project: Project,
globalContext: GlobalContextImpl, globalContext: GlobalContextImpl,
sdk: Sdk?, analysisSettings: PlatformAnalysisSettings,
platform: TargetPlatform,
syntheticFiles: Collection<KtFile>, syntheticFiles: Collection<KtFile>,
delegateResolver: ResolverForProject<IdeaModuleInfo>, delegateResolver: ResolverForProject<IdeaModuleInfo>,
moduleFilter: (IdeaModuleInfo) -> Boolean, moduleFilter: (IdeaModuleInfo) -> Boolean,
allModules: Collection<IdeaModuleInfo>?, allModules: Collection<IdeaModuleInfo>?,
builtInsCache: BuiltInsCache?, // this cache is null only for SDK resolver provider providedBuiltIns: KotlinBuiltIns?, // null means create new builtins based on SDK
dependencies: Collection<Any> dependencies: Collection<Any>
): ModuleResolverProvider { ): ModuleResolverProvider {
var sdkBuiltIns: KotlinBuiltIns? = null val builtIns = providedBuiltIns ?: createBuiltIns(analysisSettings, globalContext)
val builtInsProvider: (ModuleInfo) -> KotlinBuiltIns = builtInsCache?.let { it::getBuiltIns } ?: run {
sdkBuiltIns = BuiltInsCache.calculateBuiltIns(platform, sdk, globalContext);
{ _: ModuleInfo -> sdkBuiltIns!! }
}
val allModuleInfos = (allModules ?: collectAllModuleInfosFromIdeaModel(project)).toHashSet() val allModuleInfos = (allModules ?: collectAllModuleInfosFromIdeaModel(project)).toHashSet()
@@ -81,10 +76,10 @@ fun createModuleResolverProvider(
return AnalyzerFacade.setupResolverForProject( return AnalyzerFacade.setupResolverForProject(
debugName, globalContext.withProject(project), modulesToCreateResolversFor, debugName, globalContext.withProject(project), modulesToCreateResolversFor,
{ module -> AnalyzerFacadeProvider.getAnalyzerFacade(module.platform ?: platform) }, { module -> AnalyzerFacadeProvider.getAnalyzerFacade(module.platform ?: analysisSettings.platform) },
modulesContent, jvmPlatformParameters, IdeaEnvironment, builtInsProvider, modulesContent, jvmPlatformParameters, IdeaEnvironment, builtIns,
delegateResolver, { _, c -> IDEPackagePartProvider(c.moduleContentScope) }, delegateResolver, { _, c -> IDEPackagePartProvider(c.moduleContentScope) },
sdk?.let { SdkInfo(project, it) }, analysisSettings.sdk?.let { SdkInfo(project, it) },
modulePlatforms = { module -> module.platform?.multiTargetPlatform }, modulePlatforms = { module -> module.platform?.multiTargetPlatform },
packageOracleFactory = project.service<IdePackageOracleFactory>() packageOracleFactory = project.service<IdePackageOracleFactory>()
) )
@@ -92,15 +87,14 @@ fun createModuleResolverProvider(
val resolverForProject = createResolverForProject() val resolverForProject = createResolverForProject()
val newBuiltInsCache = builtInsCache ?: run { if (providedBuiltIns == null && builtIns is JvmBuiltIns) {
val sdkModuleDescriptor = sdk?.let { resolverForProject.descriptorForModule(SdkInfo(project, it)) } val sdkModuleDescriptor = analysisSettings.sdk!!.let { resolverForProject.descriptorForModule(SdkInfo(project, it)) }
builtIns.initialize(sdkModuleDescriptor, analysisSettings.isAdditionalBuiltInFeaturesSupported)
BuiltInsCache.createCacheAndInitializeBuiltIns(project, platform, sdk, sdkModuleDescriptor, sdkBuiltIns!!, globalContext)
} }
return ModuleResolverProviderImpl( return ModuleResolverProviderImpl(
resolverForProject, resolverForProject,
newBuiltInsCache, builtIns,
dependencies + listOf(globalContext.exceptionTracker) dependencies + listOf(globalContext.exceptionTracker)
) )
} }
@@ -130,6 +124,13 @@ fun collectAllModuleInfosFromIdeaModel(project: Project): List<IdeaModuleInfo> {
return collectAllModuleInfos return collectAllModuleInfos
} }
private fun createBuiltIns(settings: PlatformAnalysisSettings, sdkContext: GlobalContextImpl): KotlinBuiltIns = when {
settings.platform is JsPlatform -> JsPlatform.builtIns
settings.platform is JvmPlatform && settings.sdk != null -> JvmBuiltIns(sdkContext.storageManager)
else -> DefaultBuiltIns.Instance
}
fun getAllProjectSdks(): Collection<Sdk> { fun getAllProjectSdks(): Collection<Sdk> {
return ProjectJdkTable.getInstance().allJdks.toList() return ProjectJdkTable.getInstance().allJdks.toList()
} }
@@ -137,12 +138,12 @@ fun getAllProjectSdks(): Collection<Sdk> {
interface ModuleResolverProvider { interface ModuleResolverProvider {
val resolverForProject: ResolverForProject<IdeaModuleInfo> val resolverForProject: ResolverForProject<IdeaModuleInfo>
val builtInsCache: BuiltInsCache val builtIns: KotlinBuiltIns
val cacheDependencies: Collection<Any> val cacheDependencies: Collection<Any>
} }
class ModuleResolverProviderImpl( class ModuleResolverProviderImpl(
override val resolverForProject: ResolverForProject<IdeaModuleInfo>, override val resolverForProject: ResolverForProject<IdeaModuleInfo>,
override val builtInsCache: BuiltInsCache, override val builtIns: KotlinBuiltIns,
override val cacheDependencies: Collection<Any> override val cacheDependencies: Collection<Any>
) : ModuleResolverProvider ) : ModuleResolverProvider
@@ -0,0 +1,9 @@
package languageVersion1_1
public fun useJavaMap1_1(): java.util.HashMap<Int, Int> {
val g = java.util.HashMap<Int, Int>()
g.values.removeIf { it < 5 }
return g
}
val use1_0 = languageVersion1_0.useJavaMap1_0().values.removeIf { it < 5 }
@@ -0,0 +1,10 @@
package languageVersion1_0
public fun useJavaMap1_0(): java.util.HashMap<Int, Int> {
val g = java.util.HashMap<Int, Int>()
g.values.<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: removeIf">removeIf</error> { <error>it</error> < 5 }
return g
}
val use1_1 = languageVersion1_1.useJavaMap1_1().values.<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: removeIf">removeIf</error> { <error>it</error> < 5 }
@@ -16,15 +16,21 @@
package org.jetbrains.kotlin.idea.caches.resolve package org.jetbrains.kotlin.idea.caches.resolve
import com.intellij.facet.FacetManager
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.DependencyScope import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.ResolverForModuleComputationTracker import org.jetbrains.kotlin.analyzer.ResolverForModuleComputationTracker
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.TargetPlatformKind import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.idea.completion.test.withServiceRegistered import org.jetbrains.kotlin.idea.completion.test.withServiceRegistered
import org.jetbrains.kotlin.idea.facet.KotlinFacetConfiguration
import org.jetbrains.kotlin.idea.facet.KotlinFacetType
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
class MultiModuleHighlightingTest : AbstractMultiModuleHighlightingTest() { class MultiModuleHighlightingTest : AbstractMultiModuleHighlightingTest() {
@@ -107,6 +113,34 @@ class MultiModuleHighlightingTest : AbstractMultiModuleHighlightingTest() {
checkHighlightingInAllFiles() checkHighlightingInAllFiles()
} }
fun testLanguageVersionsViaFacets() {
val m1 = module("m1", useFullJdk = true).setupKotlinFacet {
settings.languageLevel = LanguageVersion.KOTLIN_1_1
}
val m2 = module("m2", useFullJdk = true).setupKotlinFacet {
settings.languageLevel = LanguageVersion.KOTLIN_1_0
}
m1.addDependency(m2)
m2.addDependency(m1)
checkHighlightingInAllFiles()
}
private fun Module.setupKotlinFacet(configure: KotlinFacetConfiguration.() -> Unit) = apply {
runWriteAction {
val facet = FacetManager.getInstance(this).addFacet(KotlinFacetType.INSTANCE, KotlinFacetType.NAME, null)
val configuration = facet.configuration
// this is actually needed so facet settings object is in a valid state
configuration.settings.compilerArguments = K2JVMCompilerArguments()
// make sure module-specific settings are used
configuration.settings.useProjectSettings = false
configuration.configure()
}
}
class MultiPlatform : AbstractMultiModuleHighlightingTest() { class MultiPlatform : AbstractMultiModuleHighlightingTest() {
override val testPath get() = super.testPath + "multiplatform/" override val testPath get() = super.testPath + "multiplatform/"