diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt index a158c235e61..0acccf62d7b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerFacade.kt @@ -26,8 +26,6 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.container.ComponentProvider import org.jetbrains.kotlin.context.ModuleContext -import org.jetbrains.kotlin.context.ProjectContext -import org.jetbrains.kotlin.context.withModule import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentProvider @@ -38,8 +36,6 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.TargetPlatformVersion import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.resolve.CompilerEnvironment -import org.jetbrains.kotlin.resolve.TargetEnvironment import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.getValue import java.util.* @@ -86,187 +82,6 @@ class EmptyResolverForProject : ResolverForProject() { override val builtInsProvider: (M) -> KotlinBuiltIns = { DefaultBuiltIns.Instance } } -class ResolverForProjectImpl( - private val debugName: String, - private val projectContext: ProjectContext, - modules: Collection, - private val modulesContent: (M) -> ModuleContent, - private val moduleLanguageSettingsProvider: LanguageSettingsProvider, - private val resolverForModuleFactoryByPlatform: (TargetPlatform?) -> ResolverForModuleFactory, - private val invalidateOnOOCB: Boolean, - override val builtInsProvider: (M) -> KotlinBuiltIns, - private val delegateResolver: ResolverForProject = EmptyResolverForProject(), - private val sdkDependency: (M) -> M?, - private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory, - private val isReleaseCoroutines: Boolean? = null -) : ResolverForProject() { - - private class ModuleData( - val moduleDescriptor: ModuleDescriptorImpl, - val modificationTracker: ModificationTracker? - ) { - val modificationCount: Long = modificationTracker?.modificationCount ?: Long.MIN_VALUE - - fun isOutOfDate(): Boolean { - val currentModCount = modificationTracker?.modificationCount - return currentModCount != null && currentModCount > modificationCount - } - } - - // Protected by ("projectContext.storageManager.lock") - private val descriptorByModule = mutableMapOf() - - // Protected by ("projectContext.storageManager.lock") - private val moduleInfoByDescriptor = mutableMapOf() - - @Suppress("UNCHECKED_CAST") - private val moduleInfoToResolvableInfo: Map = - modules.flatMap { module -> module.flatten().map { modulePart -> modulePart to module } }.toMap() as Map - - init { - assert(moduleInfoToResolvableInfo.values.toSet() == modules.toSet()) - } - - override fun tryGetResolverForModule(moduleInfo: M): ResolverForModule? { - if (!isCorrectModuleInfo(moduleInfo)) { - return null - } - return resolverForModuleDescriptor(doGetDescriptorForModule(moduleInfo)) - } - - private fun setupModuleDescriptor(module: M, moduleDescriptor: ModuleDescriptorImpl) { - moduleDescriptor.setDependencies( - LazyModuleDependencies( - projectContext.storageManager, - module, - sdkDependency(module), - this - ) - ) - - val content = modulesContent(module) - moduleDescriptor.initialize( - DelegatingPackageFragmentProvider( - this, moduleDescriptor, content, - packageOracleFactory.createOracle(module) - ) - ) - } - - // Protected by ("projectContext.storageManager.lock") - private val resolverByModuleDescriptor = mutableMapOf() - - override val allModules: Collection by lazy { - this.moduleInfoToResolvableInfo.keys + delegateResolver.allModules - } - - override val name: String - get() = "Resolver for '$debugName'" - - private fun isCorrectModuleInfo(moduleInfo: M) = moduleInfo in allModules - - override fun resolverForModuleDescriptor(descriptor: ModuleDescriptor): ResolverForModule { - return projectContext.storageManager.compute { - val module = moduleInfoByDescriptor[descriptor] - if (module == null) { - if (delegateResolver is EmptyResolverForProject<*>) { - throw IllegalStateException("$descriptor is not contained in resolver $name") - } - return@compute delegateResolver.resolverForModuleDescriptor(descriptor) - } - resolverByModuleDescriptor.getOrPut(descriptor) { - checkModuleIsCorrect(module) - - ResolverForModuleComputationTracker.getInstance(projectContext.project)?.onResolverComputed(module) - - val moduleContent = modulesContent(module) - - val languageVersionSettings = - moduleLanguageSettingsProvider.getLanguageVersionSettings(module, projectContext.project, isReleaseCoroutines) - - // FIXME(dsavvinov): make sure that module.platform returns platform with the same JvmTarget as this one - val targetPlatformVersion = moduleLanguageSettingsProvider.getTargetPlatform(module, projectContext.project) - - val resolverForModuleFactory = resolverForModuleFactoryByPlatform(module.platform) - resolverForModuleFactory.createResolverForModule( - descriptor as ModuleDescriptorImpl, - projectContext.withModule(descriptor), - moduleContent, - this@ResolverForProjectImpl, - languageVersionSettings - ) - } - } - } - - internal fun isResolverForModuleDescriptorComputed(descriptor: ModuleDescriptor) = - projectContext.storageManager.compute { - descriptor in resolverByModuleDescriptor - } - - override fun descriptorForModule(moduleInfo: M): ModuleDescriptorImpl { - checkModuleIsCorrect(moduleInfo) - return doGetDescriptorForModule(moduleInfo) - } - - override fun diagnoseUnknownModuleInfo(infos: List): Nothing { - DiagnoseUnknownModuleInfoReporter.report(name, infos) - } - - private fun checkModuleIsCorrect(moduleInfo: M) { - if (!isCorrectModuleInfo(moduleInfo)) { - diagnoseUnknownModuleInfo(listOf(moduleInfo)) - } - } - - private fun doGetDescriptorForModule(module: M): ModuleDescriptorImpl { - val moduleFromThisResolver = moduleInfoToResolvableInfo[module] - ?: return delegateResolver.descriptorForModule(module) as ModuleDescriptorImpl - - return projectContext.storageManager.compute { - var moduleData = descriptorByModule.getOrPut(moduleFromThisResolver) { - createModuleDescriptor(moduleFromThisResolver) - } - if (moduleData.isOutOfDate()) { - moduleData = recreateModuleDescriptor(moduleFromThisResolver) - } - moduleData.moduleDescriptor - } - } - - private fun recreateModuleDescriptor(module: M): ModuleData { - val oldDescriptor = descriptorByModule[module]?.moduleDescriptor - if (oldDescriptor != null) { - oldDescriptor.isValid = false - moduleInfoByDescriptor.remove(oldDescriptor) - resolverByModuleDescriptor.remove(oldDescriptor) - } - - val moduleData = createModuleDescriptor(module) - descriptorByModule[module] = moduleData - return moduleData - } - - private fun createModuleDescriptor(module: M): ModuleData { - val moduleDescriptor = ModuleDescriptorImpl( - module.name, - projectContext.storageManager, - builtInsProvider(module), - module.platform, - module.capabilities, - module.stableName - ) - moduleInfoByDescriptor[moduleDescriptor] = module - setupModuleDescriptor(module, moduleDescriptor) - val modificationTracker = (module as? TrackableModuleInfo)?.createModificationTracker() ?: if (invalidateOnOOCB) { - KotlinModificationTrackerService.getInstance(projectContext.project).outOfBlockModificationTracker - } else { - null - } - return ModuleData(moduleDescriptor, modificationTracker) - } -} - data class ModuleContent( val moduleInfo: M, val syntheticFiles: Collection, @@ -352,34 +167,6 @@ class LazyModuleDependencies( } - -private class DelegatingPackageFragmentProvider( - private val resolverForProject: ResolverForProjectImpl, - private val module: ModuleDescriptor, - moduleContent: ModuleContent, - private val packageOracle: PackageOracle -) : PackageFragmentProvider { - private val syntheticFilePackages = moduleContent.syntheticFiles.map { it.packageFqName }.toSet() - - override fun getPackageFragments(fqName: FqName): List { - if (certainlyDoesNotExist(fqName)) return emptyList() - - return resolverForProject.resolverForModuleDescriptor(module).packageFragmentProvider.getPackageFragments(fqName) - } - - override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection { - if (certainlyDoesNotExist(fqName)) return emptyList() - - return resolverForProject.resolverForModuleDescriptor(module).packageFragmentProvider.getSubPackagesOf(fqName, nameFilter) - } - - private fun certainlyDoesNotExist(fqName: FqName): Boolean { - if (resolverForProject.isResolverForModuleDescriptorComputed(module)) return false // let this request get cached inside delegate - - return !packageOracle.packageExists(fqName) && fqName !in syntheticFilePackages - } -} - interface PackageOracle { fun packageExists(fqName: FqName): Boolean @@ -426,53 +213,6 @@ interface ResolverForModuleComputationTracker { } } -private object DiagnoseUnknownModuleInfoReporter { - fun report(name: String, infos: List): Nothing { - val message = "$name does not know how to resolve $infos" - when { - name.contains(ResolverForProject.resolverForSdkName) -> errorInSdkResolver(message) - name.contains(ResolverForProject.resolverForLibrariesName) -> errorInLibrariesResolver(message) - name.contains(ResolverForProject.resolverForModulesName) -> { - when { - infos.isEmpty() -> errorInModulesResolverWithEmptyInfos(message) - infos.size == 1 -> { - val infoAsString = infos.single().toString() - when { - infoAsString.contains("ScriptDependencies") -> errorInModulesResolverWithScriptDependencies(message) - infoAsString.contains("Library") -> errorInModulesResolverWithLibraryInfo(message) - else -> errorInModulesResolver(message) - } - } - else -> throw errorInModulesResolver(message) - } - } - name.contains(ResolverForProject.resolverForScriptDependenciesName) -> errorInScriptDependenciesInfoResolver(message) - name.contains(ResolverForProject.resolverForSpecialInfoName) -> { - when { - name.contains("ScriptModuleInfo") -> errorInScriptModuleInfoResolver(message) - else -> errorInSpecialModuleInfoResolver(message) - } - } - else -> otherError(message) - } - } - - // Do not inline 'error*'-methods, they are needed to avoid Exception Analyzer merging those AssertionErrors - - private fun errorInSdkResolver(message: String): Nothing = throw AssertionError(message) - private fun errorInLibrariesResolver(message: String): Nothing = throw AssertionError(message) - private fun errorInModulesResolver(message: String): Nothing = throw AssertionError(message) - - private fun errorInModulesResolverWithEmptyInfos(message: String): Nothing = throw AssertionError(message) - private fun errorInModulesResolverWithScriptDependencies(message: String): Nothing = throw AssertionError(message) - private fun errorInModulesResolverWithLibraryInfo(message: String): Nothing = throw AssertionError(message) - - private fun errorInScriptDependenciesInfoResolver(message: String): Nothing = throw AssertionError(message) - private fun errorInScriptModuleInfoResolver(message: String): Nothing = throw AssertionError(message) - private fun errorInSpecialModuleInfoResolver(message: String): Nothing = throw AssertionError(message) - - private fun otherError(message: String): Nothing = throw AssertionError(message) -} @Suppress("UNCHECKED_CAST") fun ModuleInfo.getCapability(capability: ModuleDescriptor.Capability) = capabilities[capability] as? T diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/ResolverForProjectImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/ResolverForProjectImpl.kt new file mode 100644 index 00000000000..6cf9ba9ef31 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/ResolverForProjectImpl.kt @@ -0,0 +1,275 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analyzer + +import com.intellij.openapi.util.ModificationTracker +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.context.ProjectContext +import org.jetbrains.kotlin.context.withModule +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor +import org.jetbrains.kotlin.descriptors.PackageFragmentProvider +import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.platform.TargetPlatform + +class ResolverForProjectImpl( + private val debugName: String, + private val projectContext: ProjectContext, + modules: Collection, + private val modulesContent: (M) -> ModuleContent, + private val moduleLanguageSettingsProvider: LanguageSettingsProvider, + private val resolverForModuleFactoryByPlatform: (TargetPlatform?) -> ResolverForModuleFactory, + private val invalidateOnOOCB: Boolean, + override val builtInsProvider: (M) -> KotlinBuiltIns, + private val delegateResolver: ResolverForProject = EmptyResolverForProject(), + private val sdkDependency: (M) -> M?, + private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory, + private val isReleaseCoroutines: Boolean? = null +) : ResolverForProject() { + + private class ModuleData( + val moduleDescriptor: ModuleDescriptorImpl, + val modificationTracker: ModificationTracker? + ) { + val modificationCount: Long = modificationTracker?.modificationCount ?: Long.MIN_VALUE + + fun isOutOfDate(): Boolean { + val currentModCount = modificationTracker?.modificationCount + return currentModCount != null && currentModCount > modificationCount + } + } + + // Protected by ("projectContext.storageManager.lock") + private val descriptorByModule = mutableMapOf() + + // Protected by ("projectContext.storageManager.lock") + private val moduleInfoByDescriptor = mutableMapOf() + + @Suppress("UNCHECKED_CAST") + private val moduleInfoToResolvableInfo: Map = + modules.flatMap { module -> module.flatten().map { modulePart -> modulePart to module } }.toMap() as Map + + init { + assert(moduleInfoToResolvableInfo.values.toSet() == modules.toSet()) + } + + override fun tryGetResolverForModule(moduleInfo: M): ResolverForModule? { + if (!isCorrectModuleInfo(moduleInfo)) { + return null + } + return resolverForModuleDescriptor(doGetDescriptorForModule(moduleInfo)) + } + + private fun setupModuleDescriptor(module: M, moduleDescriptor: ModuleDescriptorImpl) { + moduleDescriptor.setDependencies( + LazyModuleDependencies( + projectContext.storageManager, + module, + sdkDependency(module), + this + ) + ) + + val content = modulesContent(module) + moduleDescriptor.initialize( + DelegatingPackageFragmentProvider( + this, moduleDescriptor, content, + packageOracleFactory.createOracle(module) + ) + ) + } + + // Protected by ("projectContext.storageManager.lock") + private val resolverByModuleDescriptor = mutableMapOf() + + override val allModules: Collection by lazy { + this.moduleInfoToResolvableInfo.keys + delegateResolver.allModules + } + + override val name: String + get() = "Resolver for '$debugName'" + + private fun isCorrectModuleInfo(moduleInfo: M) = moduleInfo in allModules + + override fun resolverForModuleDescriptor(descriptor: ModuleDescriptor): ResolverForModule { + return projectContext.storageManager.compute { + val module = moduleInfoByDescriptor[descriptor] + if (module == null) { + if (delegateResolver is EmptyResolverForProject<*>) { + throw IllegalStateException("$descriptor is not contained in resolver $name") + } + return@compute delegateResolver.resolverForModuleDescriptor(descriptor) + } + resolverByModuleDescriptor.getOrPut(descriptor) { + checkModuleIsCorrect(module) + + ResolverForModuleComputationTracker.getInstance(projectContext.project) + ?.onResolverComputed(module) + + val moduleContent = modulesContent(module) + + val languageVersionSettings = + moduleLanguageSettingsProvider.getLanguageVersionSettings(module, projectContext.project, isReleaseCoroutines) + + // FIXME(dsavvinov): make sure that module.platform returns platform with the same JvmTarget as this one + val targetPlatformVersion = moduleLanguageSettingsProvider.getTargetPlatform(module, projectContext.project) + + val resolverForModuleFactory = resolverForModuleFactoryByPlatform(module.platform) + resolverForModuleFactory.createResolverForModule( + descriptor as ModuleDescriptorImpl, + projectContext.withModule(descriptor), + moduleContent, + this@ResolverForProjectImpl, + languageVersionSettings + ) + } + } + } + + internal fun isResolverForModuleDescriptorComputed(descriptor: ModuleDescriptor) = + projectContext.storageManager.compute { + descriptor in resolverByModuleDescriptor + } + + override fun descriptorForModule(moduleInfo: M): ModuleDescriptorImpl { + checkModuleIsCorrect(moduleInfo) + return doGetDescriptorForModule(moduleInfo) + } + + override fun diagnoseUnknownModuleInfo(infos: List): Nothing { + DiagnoseUnknownModuleInfoReporter.report(name, infos) + } + + private fun checkModuleIsCorrect(moduleInfo: M) { + if (!isCorrectModuleInfo(moduleInfo)) { + diagnoseUnknownModuleInfo(listOf(moduleInfo)) + } + } + + private fun doGetDescriptorForModule(module: M): ModuleDescriptorImpl { + val moduleFromThisResolver = moduleInfoToResolvableInfo[module] + ?: return delegateResolver.descriptorForModule(module) as ModuleDescriptorImpl + + return projectContext.storageManager.compute { + var moduleData = descriptorByModule.getOrPut(moduleFromThisResolver) { + createModuleDescriptor(moduleFromThisResolver) + } + if (moduleData.isOutOfDate()) { + moduleData = recreateModuleDescriptor(moduleFromThisResolver) + } + moduleData.moduleDescriptor + } + } + + private fun recreateModuleDescriptor(module: M): ModuleData { + val oldDescriptor = descriptorByModule[module]?.moduleDescriptor + if (oldDescriptor != null) { + oldDescriptor.isValid = false + moduleInfoByDescriptor.remove(oldDescriptor) + resolverByModuleDescriptor.remove(oldDescriptor) + } + + val moduleData = createModuleDescriptor(module) + descriptorByModule[module] = moduleData + return moduleData + } + + private fun createModuleDescriptor(module: M): ModuleData { + val moduleDescriptor = ModuleDescriptorImpl( + module.name, + projectContext.storageManager, + builtInsProvider(module), + module.platform, + module.capabilities, + module.stableName + ) + moduleInfoByDescriptor[moduleDescriptor] = module + setupModuleDescriptor(module, moduleDescriptor) + val modificationTracker = (module as? TrackableModuleInfo)?.createModificationTracker() ?: if (invalidateOnOOCB) { + KotlinModificationTrackerService.getInstance(projectContext.project).outOfBlockModificationTracker + } else { + null + } + return ModuleData(moduleDescriptor, modificationTracker) + } +} + +private class DelegatingPackageFragmentProvider( + private val resolverForProject: ResolverForProjectImpl, + private val module: ModuleDescriptor, + moduleContent: ModuleContent, + private val packageOracle: PackageOracle +) : PackageFragmentProvider { + private val syntheticFilePackages = moduleContent.syntheticFiles.map { it.packageFqName }.toSet() + + override fun getPackageFragments(fqName: FqName): List { + if (certainlyDoesNotExist(fqName)) return emptyList() + + return resolverForProject.resolverForModuleDescriptor(module).packageFragmentProvider.getPackageFragments(fqName) + } + + override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection { + if (certainlyDoesNotExist(fqName)) return emptyList() + + return resolverForProject.resolverForModuleDescriptor(module).packageFragmentProvider.getSubPackagesOf(fqName, nameFilter) + } + + private fun certainlyDoesNotExist(fqName: FqName): Boolean { + if (resolverForProject.isResolverForModuleDescriptorComputed(module)) return false // let this request get cached inside delegate + + return !packageOracle.packageExists(fqName) && fqName !in syntheticFilePackages + } +} + +private object DiagnoseUnknownModuleInfoReporter { + fun report(name: String, infos: List): Nothing { + val message = "$name does not know how to resolve $infos" + when { + name.contains(ResolverForProject.resolverForSdkName) -> errorInSdkResolver(message) + name.contains(ResolverForProject.resolverForLibrariesName) -> errorInLibrariesResolver(message) + name.contains(ResolverForProject.resolverForModulesName) -> { + when { + infos.isEmpty() -> errorInModulesResolverWithEmptyInfos(message) + infos.size == 1 -> { + val infoAsString = infos.single().toString() + when { + infoAsString.contains("ScriptDependencies") -> errorInModulesResolverWithScriptDependencies(message) + infoAsString.contains("Library") -> errorInModulesResolverWithLibraryInfo(message) + else -> errorInModulesResolver(message) + } + } + else -> throw errorInModulesResolver(message) + } + } + name.contains(ResolverForProject.resolverForScriptDependenciesName) -> errorInScriptDependenciesInfoResolver(message) + name.contains(ResolverForProject.resolverForSpecialInfoName) -> { + when { + name.contains("ScriptModuleInfo") -> errorInScriptModuleInfoResolver(message) + else -> errorInSpecialModuleInfoResolver(message) + } + } + else -> otherError(message) + } + } + + // Do not inline 'error*'-methods, they are needed to avoid Exception Analyzer merging those AssertionErrors + + private fun errorInSdkResolver(message: String): Nothing = throw AssertionError(message) + private fun errorInLibrariesResolver(message: String): Nothing = throw AssertionError(message) + private fun errorInModulesResolver(message: String): Nothing = throw AssertionError(message) + + private fun errorInModulesResolverWithEmptyInfos(message: String): Nothing = throw AssertionError(message) + private fun errorInModulesResolverWithScriptDependencies(message: String): Nothing = throw AssertionError(message) + private fun errorInModulesResolverWithLibraryInfo(message: String): Nothing = throw AssertionError(message) + + private fun errorInScriptDependenciesInfoResolver(message: String): Nothing = throw AssertionError(message) + private fun errorInScriptModuleInfoResolver(message: String): Nothing = throw AssertionError(message) + private fun errorInSpecialModuleInfoResolver(message: String): Nothing = throw AssertionError(message) + + private fun otherError(message: String): Nothing = throw AssertionError(message) +}