[Injection] Make component containers composition more granular and flexible

Previously, containers set-up was performed by calls to static functions
like 'createContainerForLazyResolve', which would set-up whole container
from scratch.

This has several issues:
- complicates code re-use and encourages copy-paste of one and the same
set-up logic
- complicates composition of multiplatform containers (because each
set-up method relies on the fact that it should take an empty
container and compose it completely)

The idea of this commit is to split set-up methods into smaller ones,
with finer areas of responsibility, which allows to re-use them
in various scenarios (and, in particularly motivating composition
of multiplatform container)
This commit is contained in:
Dmitry Savvinov
2019-04-01 13:00:47 +03:00
parent 72e28d37fc
commit 602f642018
5 changed files with 137 additions and 93 deletions
@@ -19,24 +19,21 @@ package org.jetbrains.kotlin.analyzer.common
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.analyzer.*
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.platform.TargetPlatformVersion
import org.jetbrains.kotlin.container.StorageComponentContainer
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.container.useImpl
import org.jetbrains.kotlin.container.useInstance
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.contracts.ContractDeserializerImpl
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.container.useImpl
import org.jetbrains.kotlin.container.useInstance
import org.jetbrains.kotlin.frontend.di.configureModule
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.frontend.di.configureStandardResolveComponents
import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.CommonPlatforms
@@ -141,7 +138,7 @@ object CommonResolverForModuleFactory : ResolverForModuleFactory() {
val trace = CodeAnalyzerInitializer.getInstance(project).createTrace()
val container = createContainerToResolveCommonCode(
moduleContext, trace, declarationProviderFactory, moduleContentScope, targetEnvironment, metadataPartProvider,
languageVersionSettings
languageVersionSettings, CommonPlatforms.defaultCommonPlatform, CommonPlatformCompilerServices
)
val packageFragmentProviders = listOf(
@@ -151,35 +148,41 @@ object CommonResolverForModuleFactory : ResolverForModuleFactory() {
return ResolverForModule(CompositePackageFragmentProvider(packageFragmentProviders), container)
}
}
private fun createContainerToResolveCommonCode(
moduleContext: ModuleContext,
bindingTrace: BindingTrace,
declarationProviderFactory: DeclarationProviderFactory,
moduleContentScope: GlobalSearchScope,
targetEnvironment: TargetEnvironment,
metadataPartProvider: MetadataPartProvider,
languageVersionSettings: LanguageVersionSettings
): StorageComponentContainer = createContainer("ResolveCommonCode", CommonPlatformCompilerServices) {
configureModule(moduleContext, DefaultBuiltInPlatforms.commonPlatform, CommonPlatformCompilerServices, bindingTrace, languageVersionSettings)
private fun createContainerToResolveCommonCode(
moduleContext: ModuleContext,
bindingTrace: BindingTrace,
declarationProviderFactory: DeclarationProviderFactory,
moduleContentScope: GlobalSearchScope,
targetEnvironment: TargetEnvironment,
metadataPartProvider: MetadataPartProvider,
languageVersionSettings: LanguageVersionSettings,
platform: TargetPlatform,
compilerServices: PlatformDependentCompilerServices
): StorageComponentContainer =
createContainer("ResolveCommonCode", compilerServices) {
configureModule(moduleContext, platform, compilerServices, bindingTrace, languageVersionSettings)
useInstance(moduleContentScope)
useInstance(LookupTracker.DO_NOTHING)
useInstance(ExpectActualTracker.DoNothing)
useImpl<ResolveSession>()
useImpl<LazyTopDownAnalyzer>()
useImpl<AnnotationResolverImpl>()
useImpl<CompilerDeserializationConfiguration>()
useInstance(metadataPartProvider)
useInstance(declarationProviderFactory)
useImpl<MetadataPackageFragmentProvider>()
useImpl<ContractDeserializerImpl>()
configureStandardResolveComponents()
configureCommonSpecificComponents()
useInstance(metadataPartProvider)
useImpl<SubstitutingScopeProviderImpl>()
val metadataFinderFactory = ServiceManager.getService(moduleContext.project, MetadataFinderFactory::class.java)
?: error("No MetadataFinderFactory in project")
val metadataFinderFactory = ServiceManager.getService(
moduleContext.project,
MetadataFinderFactory::class.java
)
?: error("No MetadataFinderFactory in project")
useInstance(metadataFinderFactory.create(moduleContentScope))
targetEnvironment.configure(this)
}
fun StorageComponentContainer.configureCommonSpecificComponents() {
useImpl<MetadataPackageFragmentProvider>()
}
@@ -24,9 +24,10 @@ import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.container.*
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.contracts.ContractDeserializerImpl
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.frontend.di.configureIncrementalCompilation
import org.jetbrains.kotlin.frontend.di.configureModule
import org.jetbrains.kotlin.frontend.di.configureStandardResolveComponents
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.load.java.AbstractJavaClassFinder
@@ -44,7 +45,6 @@ import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformCompilerServices
import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
import org.jetbrains.kotlin.types.SubstitutingScopeProviderImpl
@@ -66,21 +66,46 @@ fun createContainerForLazyResolveWithJava(
): StorageComponentContainer = createContainer("LazyResolveWithJava", JvmPlatformCompilerServices) {
configureModule(moduleContext, jvmPlatform, JvmPlatformCompilerServices, bindingTrace, languageVersionSettings)
configureIncrementalCompilation(lookupTracker, expectActualTracker)
configureStandardResolveComponents()
useInstance(moduleContentScope)
useInstance(lookupTracker)
useInstance(expectActualTracker)
useImpl<ResolveSession>()
useImpl<LazyTopDownAnalyzer>()
useInstance(packagePartProvider)
useInstance(declarationProviderFactory)
useInstance(VirtualFileFinderFactory.getInstance(moduleContext.project).create(moduleContentScope))
configureJavaSpecificComponents(
moduleContext, moduleClassResolver, languageVersionSettings, configureJavaClassFinder,
javaClassTracker, useBuiltInsProvider
)
targetEnvironment.configure(this)
}.apply {
initializeJavaSpecificComponents(bindingTrace)
}
fun StorageComponentContainer.initializeJavaSpecificComponents(bindingTrace: BindingTrace) {
get<AbstractJavaClassFinder>().initialize(bindingTrace, get<KotlinCodeAnalyzer>())
}
fun StorageComponentContainer.configureJavaSpecificComponents(
moduleContext: ModuleContext,
moduleClassResolver: ModuleClassResolver,
languageVersionSettings: LanguageVersionSettings,
configureJavaClassFinder: (StorageComponentContainer.() -> Unit)?,
javaClassTracker: JavaClassesTracker?,
useBuiltInsProvider: Boolean
) {
useImpl<JavaDescriptorResolver>()
useImpl<DeserializationComponentsForJava>()
useInstance(VirtualFileFinderFactory.getInstance(moduleContext.project).create(moduleContentScope))
useInstance(JavaPropertyInitializerEvaluatorImpl)
useImpl<AnnotationResolverImpl>()
useImpl<SignaturePropagatorImpl>()
useImpl<TraceBasedErrorReporter>()
useInstance(InternalFlexibleTypeTransformer)
useImpl<CompilerDeserializationConfiguration>()
useInstance(JavaDeprecationSettings)
useInstance(moduleClassResolver)
if (configureJavaClassFinder != null) {
configureJavaClassFinder()
@@ -90,10 +115,6 @@ fun createContainerForLazyResolveWithJava(
useImpl<JavaSourceElementFactoryImpl>()
}
useInstance(packagePartProvider)
useInstance(moduleClassResolver)
useInstance(declarationProviderFactory)
useInstance(languageVersionSettings.getFlag(JvmAnalysisFlags.jsr305))
if (useBuiltInsProvider) {
@@ -106,16 +127,10 @@ fun createContainerForLazyResolveWithJava(
JavaResolverSettings.create(isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines))
)
targetEnvironment.configure(this)
useImpl<ContractDeserializerImpl>()
useImpl<FilesByFacadeFqNameIndexer>()
useImpl<SubstitutingScopeProviderImpl>()
}.apply {
get<AbstractJavaClassFinder>().initialize(bindingTrace, get<KotlinCodeAnalyzer>())
}
fun ComponentProvider.initJvmBuiltInsForTopDownAnalysis() {
get<JvmBuiltIns>().initialize(get<ModuleDescriptor>(), get<LanguageVersionSettings>())
}
@@ -22,11 +22,10 @@ import org.jetbrains.kotlin.container.StorageComponentContainer
import org.jetbrains.kotlin.container.useImpl
import org.jetbrains.kotlin.container.useInstance
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.contracts.ContractDeserializerImpl
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.platform.subplatformOfType
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.platform.TargetPlatformVersion
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.components.ClassicTypeSystemContextForCS
@@ -35,7 +34,6 @@ import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionStatelessCallbac
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
import org.jetbrains.kotlin.resolve.lazy.*
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
import org.jetbrains.kotlin.types.SubstitutingScopeProviderImpl
import org.jetbrains.kotlin.types.expressions.DeclarationScopeProviderForLocalClassifierAnalyzer
import org.jetbrains.kotlin.types.expressions.LocalClassDescriptorHolder
@@ -78,9 +76,32 @@ private fun StorageComponentContainer.configurePlatformIndependentComponents() {
useImpl<ExperimentalUsageChecker>()
useImpl<ExperimentalUsageChecker.Overrides>()
useImpl<ExperimentalUsageChecker.ClassifierUsage>()
useImpl<ContractDeserializerImpl>()
useImpl<CompilerDeserializationConfiguration>()
useImpl<ClassicTypeSystemContextForCS>()
}
/**
* Actually, those should be present in 'configurePlatformIndependentComponents',
* but, unfortunately, this is currently impossible, because in some lightweight
* containers (see [createContainerForBodyResolve] and similar) some dependencies
* are missing
*
* If you're not doing some trickery with containers, you should use them.
*/
fun StorageComponentContainer.configureStandardResolveComponents() {
useImpl<ResolveSession>()
useImpl<LazyTopDownAnalyzer>()
useImpl<AnnotationResolverImpl>()
}
fun StorageComponentContainer.configureIncrementalCompilation(lookupTracker: LookupTracker, expectActualTracker: ExpectActualTracker) {
useInstance(lookupTracker)
useInstance(expectActualTracker)
}
fun createContainerForBodyResolve(
moduleContext: ModuleContext,
bindingTrace: BindingTrace,
@@ -163,13 +184,11 @@ fun createContainerForLazyResolve(
): StorageComponentContainer = createContainer("LazyResolve", compilerServices) {
configureModule(moduleContext, platform, compilerServices, bindingTrace, languageVersionSettings)
useInstance(declarationProviderFactory)
configureStandardResolveComponents()
useInstance(declarationProviderFactory)
useImpl<SubstitutingScopeProviderImpl>()
useImpl<AnnotationResolverImpl>()
useImpl<CompilerDeserializationConfiguration>()
targetEnvironment.configure(this)
useImpl<ResolveSession>()
useImpl<LazyTopDownAnalyzer>()
useImpl<SubstitutingScopeProviderImpl>()
}
}
@@ -66,15 +66,24 @@ private val DEFAULT_CLASH_RESOLVERS = listOf<PlatformExtensionsClashResolver<*>>
PlatformExtensionsClashResolver.FallbackToDefault(DynamicTypesSettings(), DynamicTypesSettings::class.java)
)
fun StorageComponentContainer.configureDefaultCheckers() {
DEFAULT_DECLARATION_CHECKERS.forEach { useInstance(it) }
DEFAULT_CALL_CHECKERS.forEach { useInstance(it) }
DEFAULT_TYPE_CHECKERS.forEach { useInstance(it) }
DEFAULT_CLASSIFIER_USAGE_CHECKERS.forEach { useInstance(it) }
DEFAULT_ANNOTATION_CHECKERS.forEach { useInstance(it) }
DEFAULT_CLASH_RESOLVERS.forEach { useClashResolver(it) }
}
abstract class PlatformConfiguratorBase(
private val dynamicTypesSettings: DynamicTypesSettings? = null,
additionalDeclarationCheckers: List<DeclarationChecker> = emptyList(),
additionalCallCheckers: List<CallChecker> = emptyList(),
additionalTypeCheckers: List<AdditionalTypeChecker> = emptyList(),
additionalClassifierUsageCheckers: List<ClassifierUsageChecker> = emptyList(),
additionalAnnotationCheckers: List<AdditionalAnnotationChecker> = emptyList(),
additionalClashResolvers: List<PlatformExtensionsClashResolver<*>> = emptyList(),
private val additionalDeclarationCheckers: List<DeclarationChecker> = emptyList(),
private val additionalCallCheckers: List<CallChecker> = emptyList(),
private val additionalTypeCheckers: List<AdditionalTypeChecker> = emptyList(),
private val additionalClassifierUsageCheckers: List<ClassifierUsageChecker> = emptyList(),
private val additionalAnnotationCheckers: List<AdditionalAnnotationChecker> = emptyList(),
private val additionalClashResolvers: List<PlatformExtensionsClashResolver<*>> = emptyList(),
private val identifierChecker: IdentifierChecker? = null,
private val overloadFilter: OverloadFilter? = null,
private val platformToKotlinClassMap: PlatformToKotlinClassMap? = null,
@@ -82,33 +91,32 @@ abstract class PlatformConfiguratorBase(
private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper? = null,
private val declarationReturnTypeSanitizer: DeclarationReturnTypeSanitizer? = null
) : PlatformConfigurator {
private val declarationCheckers: List<DeclarationChecker> = DEFAULT_DECLARATION_CHECKERS + additionalDeclarationCheckers
private val callCheckers: List<CallChecker> = DEFAULT_CALL_CHECKERS + additionalCallCheckers
private val typeCheckers: List<AdditionalTypeChecker> = DEFAULT_TYPE_CHECKERS + additionalTypeCheckers
private val classifierUsageCheckers: List<ClassifierUsageChecker> =
DEFAULT_CLASSIFIER_USAGE_CHECKERS + additionalClassifierUsageCheckers
private val annotationCheckers: List<AdditionalAnnotationChecker> = DEFAULT_ANNOTATION_CHECKERS + additionalAnnotationCheckers
private val clashResolvers: List<PlatformExtensionsClashResolver<*>> = DEFAULT_CLASH_RESOLVERS + additionalClashResolvers
override val platformSpecificContainer = composeContainer(this::class.java.simpleName) {
useInstanceIfNotNull(dynamicTypesSettings)
declarationCheckers.forEach { useInstance(it) }
callCheckers.forEach { useInstance(it) }
typeCheckers.forEach { useInstance(it) }
classifierUsageCheckers.forEach { useInstance(it) }
annotationCheckers.forEach { useInstance(it) }
clashResolvers.forEach { useClashResolver(it) }
useInstanceIfNotNull(identifierChecker)
useInstanceIfNotNull(overloadFilter)
useInstanceIfNotNull(platformToKotlinClassMap)
useInstanceIfNotNull(delegationFilter)
useInstanceIfNotNull(overridesBackwardCompatibilityHelper)
useInstanceIfNotNull(declarationReturnTypeSanitizer)
configureDefaultCheckers()
configureExtensionsAndCheckers(this)
}
override fun configureModuleDependentCheckers(container: StorageComponentContainer) {
container.useImpl<ExperimentalMarkerDeclarationAnnotationChecker>()
}
private fun configureExtensionsAndCheckers(container: StorageComponentContainer) {
with(container) {
useInstanceIfNotNull(dynamicTypesSettings)
additionalDeclarationCheckers.forEach { useInstance(it) }
additionalCallCheckers.forEach { useInstance(it) }
additionalTypeCheckers.forEach { useInstance(it) }
additionalClassifierUsageCheckers.forEach { useInstance(it) }
additionalAnnotationCheckers.forEach { useInstance(it) }
additionalClashResolvers.forEach { useClashResolver(it) }
useInstanceIfNotNull(identifierChecker)
useInstanceIfNotNull(overloadFilter)
useInstanceIfNotNull(platformToKotlinClassMap)
useInstanceIfNotNull(delegationFilter)
useInstanceIfNotNull(overridesBackwardCompatibilityHelper)
useInstanceIfNotNull(declarationReturnTypeSanitizer)
}
}
}
fun createContainer(id: String, compilerServices: PlatformDependentCompilerServices, init: StorageComponentContainer.() -> Unit) =
@@ -24,7 +24,9 @@ import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.frontend.di.configureIncrementalCompilation
import org.jetbrains.kotlin.frontend.di.configureModule
import org.jetbrains.kotlin.frontend.di.configureStandardResolveComponents
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.js.resolve.JsPlatformCompilerServices
@@ -53,16 +55,13 @@ fun createTopDownAnalyzerForJs(
languageVersionSettings
)
useInstance(declarationProviderFactory)
useImpl<AnnotationResolverImpl>()
CompilerEnvironment.configure(this)
useInstance(lookupTracker)
useInstance(expectActualTracker)
useImpl<ResolveSession>()
useImpl<LazyTopDownAnalyzer>()
configureIncrementalCompilation(lookupTracker, expectActualTracker)
configureStandardResolveComponents()
useImpl<SubstitutingScopeProviderImpl>()
useInstance(declarationProviderFactory)
CompilerEnvironment.configure(this)
}.apply {
val packagePartProviders = mutableListOf(get<KotlinCodeAnalyzer>().packageFragmentProvider)
val moduleDescriptor = get<ModuleDescriptorImpl>()