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,
platformParameters: P,
targetEnvironment: TargetEnvironment = CompilerEnvironment,
builtIns: (M) -> KotlinBuiltIns = { DefaultBuiltIns.Instance },
builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance,
delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty },
firstDependency: M? = null,
@@ -175,7 +175,7 @@ abstract class AnalyzerFacade<in P : PlatformAnalysisParameters> {
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) {
@@ -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") }
)
@@ -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
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<KtElement>): 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<Pair<TargetPlatform, Sdk?>, GlobalFacade> =
object : SLRUCache<Pair<TargetPlatform, Sdk?>, GlobalFacade>(2 * 3, 2 * 3) {
override fun createValue(key: Pair<TargetPlatform, Sdk?>): GlobalFacade {
return GlobalFacade(key.first, key.second)
private val globalFacadesPerPlatformAndSdk: SLRUCache<PlatformAnalysisSettings, GlobalFacade> =
object : SLRUCache<PlatformAnalysisSettings, GlobalFacade>(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 <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? {
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<SdkInfo>()?.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<Any>,
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
)
}
@@ -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<KtFile>,
delegateResolver: ResolverForProject<IdeaModuleInfo>,
moduleFilter: (IdeaModuleInfo) -> Boolean,
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>
): 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<IdePackageOracleFactory>()
)
@@ -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<IdeaModuleInfo> {
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> {
return ProjectJdkTable.getInstance().allJdks.toList()
}
@@ -137,12 +138,12 @@ fun getAllProjectSdks(): Collection<Sdk> {
interface ModuleResolverProvider {
val resolverForProject: ResolverForProject<IdeaModuleInfo>
val builtInsCache: BuiltInsCache
val builtIns: KotlinBuiltIns
val cacheDependencies: Collection<Any>
}
class ModuleResolverProviderImpl(
override val resolverForProject: ResolverForProject<IdeaModuleInfo>,
override val builtInsCache: BuiltInsCache,
override val builtIns: KotlinBuiltIns,
override val cacheDependencies: Collection<Any>
) : 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
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/"