From 8fc953f529b72aaa137b9615e825f8021cbeb8ca Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Fri, 19 May 2017 23:28:34 +0300 Subject: [PATCH] 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 --- .../kotlin/analyzer/AnalyzerFacade.kt | 4 +- .../MultiModuleJavaAnalysisCustomTest.kt | 2 +- .../idea/caches/resolve/BuiltInsCache.kt | 86 ------------------- .../caches/resolve/KotlinCacheServiceImpl.kt | 78 ++++++++++------- .../caches/resolve/ModuleDependencyMapper.kt | 45 +++++----- .../languageVersionsViaFacets/m1/m1.kt | 9 ++ .../languageVersionsViaFacets/m2/m2.kt | 10 +++ .../resolve/MultiModuleHighlightingTest.kt | 34 ++++++++ 8 files changed, 124 insertions(+), 144 deletions(-) delete mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/BuiltInsCache.kt create mode 100644 idea/testData/multiModuleHighlighting/languageVersionsViaFacets/m1/m1.kt create mode 100644 idea/testData/multiModuleHighlighting/languageVersionsViaFacets/m2/m2.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt index fba5511a14f..b941cc6b72b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt @@ -165,7 +165,7 @@ abstract class AnalyzerFacade { modulesContent: (M) -> ModuleContent, platformParameters: P, targetEnvironment: TargetEnvironment = CompilerEnvironment, - builtIns: (M) -> KotlinBuiltIns = { DefaultBuiltIns.Instance }, + builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance, delegateResolver: ResolverForProject = EmptyResolverForProject(), packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty }, firstDependency: M? = null, @@ -175,7 +175,7 @@ abstract class AnalyzerFacade { val storageManager = projectContext.storageManager 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) for (module in modules) { diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt index c492b99c3b4..73606e4516d 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt @@ -76,7 +76,7 @@ class MultiModuleJavaAnalysisCustomTest : KtUsefulTestCase() { val moduleName = javaClass.name.asString().toLowerCase().first().toString() modules.first { it._name == moduleName } }, - builtIns = { builtIns }, + builtIns = builtIns, modulePlatforms = { MultiTargetPlatform.Specific("JVM") } ) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/BuiltInsCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/BuiltInsCache.kt deleted file mode 100644 index c0d2e3b63e1..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/BuiltInsCache.kt +++ /dev/null @@ -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 = object : SLRUCache(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 - } - } -} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt index b0a89abc085..9afc18578af 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.idea.caches.resolve +import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project 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.util.containers.SLRUCache import org.jetbrains.kotlin.analyzer.EmptyResolverForProject +import org.jetbrains.kotlin.analyzer.LanguageSettingsProvider import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.caches.resolve.KotlinCacheService +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.container.getService import org.jetbrains.kotlin.container.tryGetService import org.jetbrains.kotlin.context.GlobalContext @@ -54,6 +57,11 @@ import java.lang.IllegalStateException 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 { override fun getResolutionFacade(elements: List): ResolutionFacade { return getFacadeToAnalyzeFiles(elements.map { it.containingKtFile }) @@ -61,10 +69,10 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { override fun getSuppressionCache(): KotlinSuppressCache = kotlinSuppressCache.value - private val globalFacadesPerPlatformAndSdk: SLRUCache, GlobalFacade> = - object : SLRUCache, GlobalFacade>(2 * 3, 2 * 3) { - override fun createValue(key: Pair): GlobalFacade { - return GlobalFacade(key.first, key.second) + private val globalFacadesPerPlatformAndSdk: SLRUCache = + object : SLRUCache(2 * 3 * 2, 2 * 3 * 2) { + override fun createValue(settings: PlatformAnalysisSettings): GlobalFacade { + return GlobalFacade(settings) } } @@ -87,15 +95,15 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { ): ProjectResolutionFacade { val sdk = findJdk(dependenciesModuleInfo.dependencies, project) 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() return ProjectResolutionFacade( "facadeForScriptDependencies", project, globalContext, globalResolveSessionProvider( "dependencies of scripts", - platform, - sdk, + facadeKey, reuseDataFrom = sdkFacade, allModules = dependenciesModuleInfo.dependencies(), //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() val facadeForSdk = ProjectResolutionFacade( "facadeForSdk", project, sdkContext, globalResolveSessionProvider( - "sdk $sdk", - platform, - sdk, + "sdk ${settings.sdk}", + settings, moduleFilter = { it is SdkInfo }, dependencies = listOf( LibraryModificationTracker.getInstance(project), @@ -132,9 +139,8 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { "facadeForLibraries", project, librariesContext, globalResolveSessionProvider( - "project libraries for platform $platform", - platform, - sdk, + "project libraries for platform ${settings.sdk}", + settings, reuseDataFrom = facadeForSdk, moduleFilter = { it is LibraryInfo }, dependencies = listOf( @@ -150,9 +156,8 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { "facadeForModules", project, modulesContext, globalResolveSessionProvider( - "project source roots and libraries for platform $platform", - platform, - sdk, + "project source roots and libraries for platform ${settings.platform}", + settings, reuseDataFrom = facadeForLibraries, moduleFilter = { !it.isLibraryClasses() }, 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") fun getProjectService(platform: TargetPlatform, ideaModuleInfo: IdeaModuleInfo, serviceClass: Class): 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() + .getLanguageVersionSettings(this, project) + .supportsFeature(LanguageFeature.AdditionalBuiltInsMembers) } fun tryGetProjectService(platform: TargetPlatform, ideaModuleInfo: IdeaModuleInfo, serviceClass: Class): 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?) = - getOrBuildGlobalFacade(platform, sdk).facadeForModules + private fun globalFacade(settings: PlatformAnalysisSettings) = + getOrBuildGlobalFacade(settings).facadeForModules - private fun librariesFacade(platform: TargetPlatform, sdk: Sdk?) = getOrBuildGlobalFacade(platform, sdk).facadeForLibraries + private fun librariesFacade(settings: PlatformAnalysisSettings) = getOrBuildGlobalFacade(settings).facadeForLibraries @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()?.sdk @@ -183,6 +196,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { val targetPlatform = files.map { TargetPlatformDetector.getPlatform(it) }.toSet().single() val syntheticFileModule = files.map(KtFile::getModuleInfo).toSet().single() val sdk = syntheticFileModule.sdk + val settings = PlatformAnalysisSettings(targetPlatform, sdk, syntheticFileModule.supportsAdditionalBuiltInsMembers()) val filesModificationTracker: ModificationTracker // File copies are created during completion and receive correct modification events through POM. // Dummy files created e.g. by J2K do not receive events. @@ -205,8 +219,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { ): (GlobalContextImpl, Project) -> ModuleResolverProvider { return globalResolveSessionProvider( debugName, - targetPlatform, - sdk, + settings, syntheticFiles = files, reuseDataFrom = reuseDataFrom, moduleFilter = moduleFilter, @@ -218,7 +231,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { return when { syntheticFileModule is ModuleSourceInfo -> { val dependentModules = syntheticFileModule.getDependentModules() - val modulesFacade = globalFacade(targetPlatform, sdk) + val modulesFacade = globalFacade(settings) val globalContext = modulesFacade.globalContext.contextWithNewLockAndCompositeExceptionTracker() ProjectResolutionFacade( "facadeForSynthetic in ModuleSourceInfo", @@ -261,7 +274,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { } syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> { - val librariesFacade = librariesFacade(targetPlatform, sdk) + val librariesFacade = librariesFacade(settings) val globalContext = librariesFacade.globalContext.contextWithNewLockAndCompositeExceptionTracker() ProjectResolutionFacade( "facadeForSynthetic in LibrarySourceInfo or NotUnderContentRootModuleInfo", @@ -362,7 +375,8 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { } 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) } @@ -382,8 +396,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { private fun globalResolveSessionProvider( debugName: String, - platform: TargetPlatform, - sdk: Sdk?, + settings: PlatformAnalysisSettings, dependencies: Collection, moduleFilter: (IdeaModuleInfo) -> Boolean, reuseDataFrom: ProjectResolutionFacade? = null, @@ -394,11 +407,10 @@ private fun globalResolveSessionProvider( val delegateResolverForProject = delegateResolverProvider?.resolverForProject ?: EmptyResolverForProject() createModuleResolverProvider( - debugName, project, globalContext, sdk, - platform, + debugName, project, globalContext, settings, syntheticFiles, delegateResolverForProject, moduleFilter, allModules, - delegateResolverProvider?.builtInsCache, + delegateResolverProvider?.builtIns, dependencies ) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ModuleDependencyMapper.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ModuleDependencyMapper.kt index 9072a26dff2..35c6e1149ae 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ModuleDependencyMapper.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ModuleDependencyMapper.kt @@ -26,39 +26,34 @@ import com.intellij.openapi.roots.LibraryOrderEntry import com.intellij.openapi.roots.ModuleRootManager import org.jetbrains.kotlin.analyzer.AnalyzerFacade import org.jetbrains.kotlin.analyzer.ModuleContent -import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ResolverForProject +import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.context.GlobalContextImpl import org.jetbrains.kotlin.context.withProject import org.jetbrains.kotlin.idea.project.AnalyzerFacadeProvider 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.impl.JavaClassImpl +import org.jetbrains.kotlin.platform.JvmBuiltIns 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.platform.JvmPlatform fun createModuleResolverProvider( debugName: String, project: Project, globalContext: GlobalContextImpl, - sdk: Sdk?, - platform: TargetPlatform, + analysisSettings: PlatformAnalysisSettings, syntheticFiles: Collection, delegateResolver: ResolverForProject, moduleFilter: (IdeaModuleInfo) -> Boolean, allModules: Collection?, - builtInsCache: BuiltInsCache?, // this cache is null only for SDK resolver provider + providedBuiltIns: KotlinBuiltIns?, // null means create new builtins based on SDK dependencies: Collection ): ModuleResolverProvider { - var sdkBuiltIns: KotlinBuiltIns? = null - - val builtInsProvider: (ModuleInfo) -> KotlinBuiltIns = builtInsCache?.let { it::getBuiltIns } ?: run { - sdkBuiltIns = BuiltInsCache.calculateBuiltIns(platform, sdk, globalContext); - - { _: ModuleInfo -> sdkBuiltIns!! } - } + val builtIns = providedBuiltIns ?: createBuiltIns(analysisSettings, globalContext) val allModuleInfos = (allModules ?: collectAllModuleInfosFromIdeaModel(project)).toHashSet() @@ -81,10 +76,10 @@ fun createModuleResolverProvider( return AnalyzerFacade.setupResolverForProject( debugName, globalContext.withProject(project), modulesToCreateResolversFor, - { module -> AnalyzerFacadeProvider.getAnalyzerFacade(module.platform ?: platform) }, - modulesContent, jvmPlatformParameters, IdeaEnvironment, builtInsProvider, + { module -> AnalyzerFacadeProvider.getAnalyzerFacade(module.platform ?: analysisSettings.platform) }, + modulesContent, jvmPlatformParameters, IdeaEnvironment, builtIns, delegateResolver, { _, c -> IDEPackagePartProvider(c.moduleContentScope) }, - sdk?.let { SdkInfo(project, it) }, + analysisSettings.sdk?.let { SdkInfo(project, it) }, modulePlatforms = { module -> module.platform?.multiTargetPlatform }, packageOracleFactory = project.service() ) @@ -92,15 +87,14 @@ fun createModuleResolverProvider( val resolverForProject = createResolverForProject() - val newBuiltInsCache = builtInsCache ?: run { - val sdkModuleDescriptor = sdk?.let { resolverForProject.descriptorForModule(SdkInfo(project, it)) } - - BuiltInsCache.createCacheAndInitializeBuiltIns(project, platform, sdk, sdkModuleDescriptor, sdkBuiltIns!!, globalContext) + if (providedBuiltIns == null && builtIns is JvmBuiltIns) { + val sdkModuleDescriptor = analysisSettings.sdk!!.let { resolverForProject.descriptorForModule(SdkInfo(project, it)) } + builtIns.initialize(sdkModuleDescriptor, analysisSettings.isAdditionalBuiltInFeaturesSupported) } return ModuleResolverProviderImpl( resolverForProject, - newBuiltInsCache, + builtIns, dependencies + listOf(globalContext.exceptionTracker) ) } @@ -130,6 +124,13 @@ fun collectAllModuleInfosFromIdeaModel(project: Project): List { 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 { return ProjectJdkTable.getInstance().allJdks.toList() } @@ -137,12 +138,12 @@ fun getAllProjectSdks(): Collection { interface ModuleResolverProvider { val resolverForProject: ResolverForProject - val builtInsCache: BuiltInsCache + val builtIns: KotlinBuiltIns val cacheDependencies: Collection } class ModuleResolverProviderImpl( override val resolverForProject: ResolverForProject, - override val builtInsCache: BuiltInsCache, + override val builtIns: KotlinBuiltIns, override val cacheDependencies: Collection ) : ModuleResolverProvider diff --git a/idea/testData/multiModuleHighlighting/languageVersionsViaFacets/m1/m1.kt b/idea/testData/multiModuleHighlighting/languageVersionsViaFacets/m1/m1.kt new file mode 100644 index 00000000000..fb7184047cf --- /dev/null +++ b/idea/testData/multiModuleHighlighting/languageVersionsViaFacets/m1/m1.kt @@ -0,0 +1,9 @@ +package languageVersion1_1 + +public fun useJavaMap1_1(): java.util.HashMap { + val g = java.util.HashMap() + g.values.removeIf { it < 5 } + return g +} + +val use1_0 = languageVersion1_0.useJavaMap1_0().values.removeIf { it < 5 } \ No newline at end of file diff --git a/idea/testData/multiModuleHighlighting/languageVersionsViaFacets/m2/m2.kt b/idea/testData/multiModuleHighlighting/languageVersionsViaFacets/m2/m2.kt new file mode 100644 index 00000000000..b480ee4fd6f --- /dev/null +++ b/idea/testData/multiModuleHighlighting/languageVersionsViaFacets/m2/m2.kt @@ -0,0 +1,10 @@ +package languageVersion1_0 + +public fun useJavaMap1_0(): java.util.HashMap { + val g = java.util.HashMap() + g.values.removeIf { it < 5 } + return g +} + +val use1_1 = languageVersion1_1.useJavaMap1_1().values.removeIf { it < 5 } + diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleHighlightingTest.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleHighlightingTest.kt index eee52a252cf..378393c26a3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleHighlightingTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleHighlightingTest.kt @@ -16,15 +16,21 @@ package org.jetbrains.kotlin.idea.caches.resolve +import com.intellij.facet.FacetManager import com.intellij.openapi.module.Module import com.intellij.openapi.roots.DependencyScope import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess import org.jetbrains.kotlin.analyzer.ModuleInfo 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.config.JvmTarget +import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.config.TargetPlatformKind 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 class MultiModuleHighlightingTest : AbstractMultiModuleHighlightingTest() { @@ -107,6 +113,34 @@ class MultiModuleHighlightingTest : AbstractMultiModuleHighlightingTest() { 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() { override val testPath get() = super.testPath + "multiplatform/"