[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
@@ -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) =