Refactoring: remove ModuleResolverProvider, inline createModuleResolverProvider

This commit is contained in:
Nikolay Krasko
2018-02-22 16:10:18 +03:00
parent de68607d5f
commit 90802f2d7c
3 changed files with 117 additions and 164 deletions
@@ -62,6 +62,7 @@ abstract class ResolverForProject<M : ModuleInfo> {
abstract val name: String
abstract val allModules: Collection<M>
abstract val builtIns: KotlinBuiltIns
override fun toString() = name
}
@@ -77,6 +78,7 @@ class EmptyResolverForProject<M : ModuleInfo> : ResolverForProject<M>() {
override fun descriptorForModule(moduleInfo: M) = diagnoseUnknownModuleInfo(listOf(moduleInfo))
override val allModules: Collection<M> = listOf()
override fun diagnoseUnknownModuleInfo(infos: List<ModuleInfo>) = throw IllegalStateException("Should not be called for $infos")
override val builtIns get() = DefaultBuiltIns.Instance
}
class ResolverForProjectImpl<M : ModuleInfo>(
@@ -87,7 +89,7 @@ class ResolverForProjectImpl<M : ModuleInfo>(
private val modulesContent: (M) -> ModuleContent,
private val platformParameters: PlatformAnalysisParameters,
private val targetEnvironment: TargetEnvironment = CompilerEnvironment,
private val builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance,
override val builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance,
private val delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
private val packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty },
private val firstDependency: M? = null,
@@ -1,115 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.caches.resolve
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.ModuleContent
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.analyzer.ResolverForProjectImpl
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.caches.resolve.IdePlatformSupport
import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.context.withProject
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo
import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider
import org.jetbrains.kotlin.idea.project.IdeaEnvironment
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.jvm.JvmPlatformParameters
fun createModuleResolverProvider(
debugName: String,
project: Project,
globalContext: GlobalContextImpl,
analysisSettings: PlatformAnalysisSettings,
syntheticFiles: Collection<KtFile>,
delegateResolver: ResolverForProject<IdeaModuleInfo>,
moduleFilter: (IdeaModuleInfo) -> Boolean,
allModules: Collection<IdeaModuleInfo>,
providedBuiltIns: KotlinBuiltIns?, // null means create new builtins based on SDK
dependencies: Collection<Any>,
invalidateOnOOCB: Boolean = true
): ModuleResolverProvider {
val builtIns = providedBuiltIns ?: createBuiltIns(analysisSettings, globalContext)
val allModuleInfos = allModules.toMutableSet()
val syntheticFilesByModule = syntheticFiles.groupBy(KtFile::getModuleInfo)
val syntheticFilesModules = syntheticFilesByModule.keys
allModuleInfos.addAll(syntheticFilesModules)
val modulesToCreateResolversFor = allModuleInfos.filter(moduleFilter)
val modulesContent = { module: IdeaModuleInfo ->
ModuleContent(syntheticFilesByModule[module] ?: listOf(), module.contentScope())
}
val jvmPlatformParameters = JvmPlatformParameters { javaClass: JavaClass ->
val psiClass = (javaClass as JavaClassImpl).psi
psiClass.getNullableModuleInfo()
}
val resolverForProject = ResolverForProjectImpl(
debugName, globalContext.withProject(project), modulesToCreateResolversFor,
{ module ->
val platform = module.platform ?: analysisSettings.platform
IdePlatformSupport.facades[platform] ?: throw UnsupportedOperationException("Unsupported platform $platform")
},
modulesContent, jvmPlatformParameters,
IdeaEnvironment, builtIns,
delegateResolver, { _, c -> IDEPackagePartProvider(c.moduleContentScope) },
analysisSettings.sdk?.let { SdkInfo(project, it) },
modulePlatforms = { module -> module.platform?.multiTargetPlatform },
packageOracleFactory = ServiceManager.getService(project, IdePackageOracleFactory::class.java),
languageSettingsProvider = IDELanguageSettingsProvider,
invalidateOnOOCB = invalidateOnOOCB
)
if (providedBuiltIns == null && builtIns is JvmBuiltIns) {
val sdkModuleDescriptor = analysisSettings.sdk!!.let { resolverForProject.descriptorForModule(
SdkInfo(
project,
it
)
) }
builtIns.initialize(sdkModuleDescriptor, analysisSettings.isAdditionalBuiltInFeaturesSupported)
}
return ModuleResolverProvider(
resolverForProject,
builtIns,
dependencies + listOf(globalContext.exceptionTracker)
)
}
private fun createBuiltIns(settings: PlatformAnalysisSettings, sdkContext: GlobalContextImpl): KotlinBuiltIns {
val supportInstance = IdePlatformSupport.platformSupport[settings.platform] ?: return DefaultBuiltIns.Instance
return supportInstance.createBuiltIns(settings, sdkContext)
}
class ModuleResolverProvider(
val resolverForProject: ResolverForProject<IdeaModuleInfo>,
val builtIns: KotlinBuiltIns,
val cacheDependencies: Collection<Any>
)
@@ -16,21 +16,30 @@
package org.jetbrains.kotlin.idea.caches.resolve
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.util.containers.SLRUCache
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.analyzer.EmptyResolverForProject
import org.jetbrains.kotlin.analyzer.ResolverForModule
import org.jetbrains.kotlin.analyzer.*
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.caches.resolve.IdePlatformSupport
import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.context.withProject
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.idea.caches.project.*
import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider
import org.jetbrains.kotlin.idea.project.IdeaEnvironment
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.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.CompositeBindingContext
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
internal class ProjectResolutionFacade(
@@ -41,7 +50,7 @@ internal class ProjectResolutionFacade(
val settings: PlatformAnalysisSettings,
val reuseDataFrom: ProjectResolutionFacade?,
val moduleFilter: (IdeaModuleInfo) -> Boolean,
val dependencies: List<Any>,
dependencies: List<Any>,
private val invalidateOnOOCB: Boolean,
val syntheticFiles: Collection<KtFile> = listOf(),
val allModules: Collection<IdeaModuleInfo>? = null // null means create resolvers for modules from idea model
@@ -49,66 +58,115 @@ internal class ProjectResolutionFacade(
private val cachedValue = CachedValuesManager.getManager(project).createCachedValue(
{
val resolverProvider = computeModuleResolverProvider()
CachedValueProvider.Result.create(resolverProvider, resolverProvider.cacheDependencies)
CachedValueProvider.Result.create(resolverProvider, resolverForProjectDependencies)
},
/* trackValue = */ false
)
private fun computeModuleResolverProvider(): ModuleResolverProvider {
val delegateResolverProvider = reuseDataFrom?.moduleResolverProvider
val delegateResolverForProject = delegateResolverProvider?.resolverForProject ?: EmptyResolverForProject()
return createModuleResolverProvider(
resolverDebugName,
project,
globalContext,
settings,
syntheticFiles = syntheticFiles,
delegateResolver = delegateResolverForProject,
moduleFilter = moduleFilter,
allModules = allModules ?: collectAllModuleInfosFromIdeaModel(project),
providedBuiltIns = delegateResolverProvider?.builtIns,
dependencies = dependencies,
invalidateOnOOCB = invalidateOnOOCB
)
}
private val moduleResolverProvider: ModuleResolverProvider
private val cachedResolverForProject: ResolverForProject<IdeaModuleInfo>
get() = globalContext.storageManager.compute { cachedValue.value }
private val resolverForProject get() = moduleResolverProvider.resolverForProject
fun resolverForModuleInfo(moduleInfo: IdeaModuleInfo) = resolverForProject.resolverForModule(moduleInfo)
fun resolverForElement(element: PsiElement): ResolverForModule {
val infos = element.getModuleInfos()
return infos.asIterable().firstNotNullResult { resolverForProject.tryGetResolverForModule(it) }
?: resolverForProject.tryGetResolverForModule(NotUnderContentRootModuleInfo)
?: resolverForProject.diagnoseUnknownModuleInfo(infos.toList())
}
fun resolverForDescriptor(moduleDescriptor: ModuleDescriptor) = resolverForProject.resolverForModuleDescriptor(moduleDescriptor)
fun findModuleDescriptor(ideaModuleInfo: IdeaModuleInfo): ModuleDescriptor {
return resolverForProject.descriptorForModule(ideaModuleInfo)
}
private val analysisResults = CachedValuesManager.getManager(project).createCachedValue(
{
val resolverProvider = moduleResolverProvider
val resolverForProject = cachedResolverForProject
val results = object : SLRUCache<KtFile, PerFileAnalysisCache>(2, 3) {
override fun createValue(file: KtFile): PerFileAnalysisCache {
return PerFileAnalysisCache(
file,
resolverProvider.resolverForProject.resolverForModule(file.getModuleInfo()).componentProvider
resolverForProject.resolverForModule(file.getModuleInfo()).componentProvider
)
}
}
val allDependencies = resolverProvider.cacheDependencies + listOf(PsiModificationTracker.MODIFICATION_COUNT)
val allDependencies = resolverForProjectDependencies + listOf(PsiModificationTracker.MODIFICATION_COUNT)
CachedValueProvider.Result.create(results, allDependencies)
}, false
)
private val resolverForProjectDependencies = dependencies + listOf(globalContext.exceptionTracker)
private fun computeModuleResolverProvider(): ResolverForProject<IdeaModuleInfo> {
val delegateResolverForProject: ResolverForProject<IdeaModuleInfo>
val delegateBuiltIns: KotlinBuiltIns?
if (reuseDataFrom != null) {
delegateResolverForProject = reuseDataFrom.cachedResolverForProject
delegateBuiltIns = delegateResolverForProject.builtIns
} else {
delegateResolverForProject = EmptyResolverForProject()
delegateBuiltIns = null
}
val builtIns = delegateBuiltIns ?: createBuiltIns(
settings,
globalContext
)
val allModuleInfos = (allModules ?: collectAllModuleInfosFromIdeaModel(project)).toMutableSet()
val syntheticFilesByModule = syntheticFiles.groupBy(KtFile::getModuleInfo)
val syntheticFilesModules = syntheticFilesByModule.keys
allModuleInfos.addAll(syntheticFilesModules)
val modulesToCreateResolversFor = allModuleInfos.filter(moduleFilter)
val modulesContentFactory = { module: IdeaModuleInfo ->
ModuleContent(syntheticFilesByModule[module] ?: listOf(), module.contentScope())
}
val jvmPlatformParameters = JvmPlatformParameters { javaClass: JavaClass ->
val psiClass = (javaClass as JavaClassImpl).psi
psiClass.getNullableModuleInfo()
}
val resolverForProject = ResolverForProjectImpl(
resolverDebugName,
globalContext.withProject(project),
modulesToCreateResolversFor,
{ module ->
val platform = module.platform ?: settings.platform
IdePlatformSupport.facades[platform] ?: throw UnsupportedOperationException("Unsupported platform $platform")
},
modulesContentFactory,
jvmPlatformParameters,
IdeaEnvironment,
builtIns,
delegateResolverForProject,
packagePartProviderFactory = { _, c -> IDEPackagePartProvider(c.moduleContentScope) },
firstDependency = settings.sdk?.let { SdkInfo(project, it) },
modulePlatforms = { module -> module.platform?.multiTargetPlatform },
packageOracleFactory = ServiceManager.getService(project, IdePackageOracleFactory::class.java),
languageSettingsProvider = IDELanguageSettingsProvider,
invalidateOnOOCB = invalidateOnOOCB
)
if (delegateBuiltIns == null && builtIns is JvmBuiltIns) {
val sdkModuleDescriptor = settings.sdk!!.let {
resolverForProject.descriptorForModule(
SdkInfo(project, it)
)
}
builtIns.initialize(sdkModuleDescriptor, settings.isAdditionalBuiltInFeaturesSupported)
}
return resolverForProject
}
fun resolverForModuleInfo(moduleInfo: IdeaModuleInfo) = cachedResolverForProject.resolverForModule(moduleInfo)
fun resolverForElement(element: PsiElement): ResolverForModule {
val infos = element.getModuleInfos()
return infos.asIterable().firstNotNullResult { cachedResolverForProject.tryGetResolverForModule(it) }
?: cachedResolverForProject.tryGetResolverForModule(NotUnderContentRootModuleInfo)
?: cachedResolverForProject.diagnoseUnknownModuleInfo(infos.toList())
}
fun resolverForDescriptor(moduleDescriptor: ModuleDescriptor) = cachedResolverForProject.resolverForModuleDescriptor(moduleDescriptor)
fun findModuleDescriptor(ideaModuleInfo: IdeaModuleInfo): ModuleDescriptor {
return cachedResolverForProject.descriptorForModule(ideaModuleInfo)
}
fun getAnalysisResultsForElements(elements: Collection<KtElement>): AnalysisResult {
assert(elements.isNotEmpty()) { "elements collection should not be empty" }
val slruCache = synchronized(analysisResults) {
@@ -122,14 +180,22 @@ internal class ProjectResolutionFacade(
}
val withError = results.firstOrNull { it.isError() }
val bindingContext = CompositeBindingContext.create(results.map { it.bindingContext })
return if (withError != null)
AnalysisResult.internalError(bindingContext, withError.error)
else
if (withError != null) {
return AnalysisResult.internalError(bindingContext, withError.error)
}
//TODO: (module refactoring) several elements are passed here in debugger
AnalysisResult.success(bindingContext, findModuleDescriptor(elements.first().getModuleInfo()))
return AnalysisResult.success(bindingContext, findModuleDescriptor(elements.first().getModuleInfo()))
}
override fun toString(): String {
return "$debugString@${Integer.toHexString(hashCode())}"
}
companion object {
private fun createBuiltIns(settings: PlatformAnalysisSettings, sdkContext: GlobalContextImpl): KotlinBuiltIns {
val supportInstance = IdePlatformSupport.platformSupport[settings.platform] ?: return DefaultBuiltIns.Instance
return supportInstance.createBuiltIns(settings, sdkContext)
}
}
}