Extract control flow analysis to separate module

Extract a service interface out of ControlFlowInformationProviderImpl
and register its implementation in two "leaf" modules: 'cli',
'idea-core'.

This improves parallel build, since a lot of modules depend on
'frontend' but only these two modules reference the implementation and
thus depend on the full CFA implementation now.
This commit is contained in:
Alexander Udalov
2020-03-16 01:13:51 +01:00
committed by Alexander Udalov
parent c744515832
commit 2e2caae05c
70 changed files with 113 additions and 29 deletions
+1
View File
@@ -8,6 +8,7 @@ dependencies {
compile(project(":compiler:cli-common"))
compile(project(":compiler:frontend"))
compile(project(":compiler:frontend.java"))
compile(project(":compiler:frontend:cfg"))
compile(project(":compiler:backend-common"))
compile(project(":compiler:backend"))
compile(project(":compiler:backend.jvm"))
@@ -5,10 +5,13 @@
package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.cfg.ControlFlowInformationProviderImpl
import org.jetbrains.kotlin.container.StorageComponentContainer
import org.jetbrains.kotlin.container.useInstance
object CompilerEnvironment : TargetEnvironment("Compiler") {
override fun configure(container: StorageComponentContainer) {
configureCompilerEnvironment(container)
container.useInstance(ControlFlowInformationProviderImpl.Factory)
}
}
+15
View File
@@ -0,0 +1,15 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compile(project(":compiler:frontend"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
compileOnly(intellijDep()) { includeJars("guava", rootProject = rootProject) }
}
sourceSets {
"main" { projectDefault() }
"test" {}
}
@@ -63,14 +63,13 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
import org.jetbrains.kotlin.types.isFlexible
import org.jetbrains.kotlin.util.OperatorNameConventions
class ControlFlowInformationProvider private constructor(
class ControlFlowInformationProviderImpl private constructor(
private val subroutine: KtElement,
private val trace: BindingTrace,
private val pseudocode: Pseudocode,
private val languageVersionSettings: LanguageVersionSettings,
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
) {
) : ControlFlowInformationProvider {
private val pseudocodeVariablesData by lazy {
PseudocodeVariablesData(pseudocode, trace.bindingContext)
}
@@ -88,14 +87,14 @@ class ControlFlowInformationProvider private constructor(
diagnosticSuppressor
)
fun checkForLocalClassOrObjectMode() {
override fun checkForLocalClassOrObjectMode() {
// Local classes and objects are analyzed twice: when TopDownAnalyzer processes it and as a part of its container.
// Almost all checks can be done when the container is analyzed
// except recording initialized variables (this information is needed for DeclarationChecker).
recordInitializedVariables()
}
fun checkDeclaration() {
override fun checkDeclaration() {
recordInitializedVariables()
@@ -123,7 +122,7 @@ class ControlFlowInformationProvider private constructor(
checkConstructorConsistency()
}
fun checkFunction(expectedReturnType: KotlinType?) {
override fun checkFunction(expectedReturnType: KotlinType?) {
val unreachableCode = collectUnreachableCode()
reportUnreachableCode(unreachableCode)
@@ -235,7 +234,7 @@ class ControlFlowInformationProvider private constructor(
val functionDescriptor = trace.bindingContext.get(DECLARATION_TO_DESCRIPTOR, element) as? CallableDescriptor
val expectedType = functionDescriptor?.returnType
val providerForLocalDeclaration = ControlFlowInformationProvider(
val providerForLocalDeclaration = ControlFlowInformationProviderImpl(
element, trace, localDeclarationInstruction.body, languageVersionSettings, diagnosticSuppressor
)
@@ -1122,7 +1121,7 @@ class ControlFlowInformationProvider private constructor(
KtTryExpression::class.java, KtFunction::class.java, KtAnonymousInitializer::class.java
) is KtTryExpression
private fun CallInstruction.isTailCall(subroutine: KtElement = this@ControlFlowInformationProvider.subroutine): Boolean {
private fun CallInstruction.isTailCall(subroutine: KtElement = this@ControlFlowInformationProviderImpl.subroutine): Boolean {
val tailInstructionDetector = TailInstructionDetector(subroutine)
return traverseFollowingInstructions(
this,
@@ -1221,6 +1220,16 @@ class ControlFlowInformationProvider private constructor(
map: MutableMap<Instruction, DiagnosticFactory<*>>
) : VariableContext(instruction, map)
object Factory : ControlFlowInformationProvider.Factory {
override fun createControlFlowInformationProvider(
declaration: KtElement,
trace: BindingTrace,
languageVersionSettings: LanguageVersionSettings,
diagnosticSuppressor: PlatformDiagnosticSuppressor
): ControlFlowInformationProvider =
ControlFlowInformationProviderImpl(declaration, trace, languageVersionSettings, diagnosticSuppressor)
}
companion object {
private fun isUsedAsResultOfLambda(usages: List<Instruction>): Boolean {
for (usage in usages) {
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2020 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.cfg
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.checkers.PlatformDiagnosticSuppressor
import org.jetbrains.kotlin.types.KotlinType
interface ControlFlowInformationProvider {
fun checkForLocalClassOrObjectMode()
fun checkDeclaration()
fun checkFunction(expectedReturnType: KotlinType?)
interface Factory {
fun createControlFlowInformationProvider(
declaration: KtElement,
trace: BindingTrace,
languageVersionSettings: LanguageVersionSettings,
diagnosticSuppressor: PlatformDiagnosticSuppressor,
): ControlFlowInformationProvider
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.frontend.di
import org.jetbrains.kotlin.cfg.ControlFlowInformationProvider
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.isTypeRefinementEnabled
import org.jetbrains.kotlin.container.StorageComponentContainer
@@ -136,6 +137,7 @@ fun createContainerForBodyResolve(
languageVersionSettings: LanguageVersionSettings,
moduleStructureOracle: ModuleStructureOracle,
sealedProvider: SealedClassInheritorsProvider,
controlFlowInformationProviderFactory: ControlFlowInformationProvider.Factory,
): StorageComponentContainer = createContainer("BodyResolve", analyzerServices) {
configureModule(moduleContext, platform, analyzerServices, bindingTrace, languageVersionSettings, sealedProvider)
@@ -146,6 +148,7 @@ fun createContainerForBodyResolve(
useImpl<BodyResolver>()
useInstance(moduleStructureOracle)
useInstance(controlFlowInformationProviderFactory)
}
fun createContainerForLazyBodyResolve(
@@ -159,6 +162,7 @@ fun createContainerForLazyBodyResolve(
moduleStructureOracle: ModuleStructureOracle,
mainFunctionDetectorFactory: MainFunctionDetector.Factory,
sealedProvider: SealedClassInheritorsProvider,
controlFlowInformationProviderFactory: ControlFlowInformationProvider.Factory,
): StorageComponentContainer = createContainer("LazyBodyResolve", analyzerServices) {
configureModule(moduleContext, platform, analyzerServices, bindingTrace, languageVersionSettings, sealedProvider)
useInstance(mainFunctionDetectorFactory)
@@ -169,6 +173,7 @@ fun createContainerForLazyBodyResolve(
useImpl<LazyTopDownAnalyzer>()
useImpl<BasicAbsentDescriptorHandler>()
useInstance(moduleStructureOracle)
useInstance(controlFlowInformationProviderFactory)
// All containers except common inject ExpectedActualDeclarationChecker, so for common we do that
// explicitly.
@@ -185,7 +190,8 @@ fun createContainerForLazyLocalClassifierAnalyzer(
languageVersionSettings: LanguageVersionSettings,
statementFilter: StatementFilter,
localClassDescriptorHolder: LocalClassDescriptorHolder,
analyzerServices: PlatformDependentAnalyzerServices
analyzerServices: PlatformDependentAnalyzerServices,
controlFlowInformationProviderFactory: ControlFlowInformationProvider.Factory,
): StorageComponentContainer = createContainer("LocalClassifierAnalyzer", analyzerServices) {
configureModule(moduleContext, platform, analyzerServices, bindingTrace, languageVersionSettings)
@@ -198,6 +204,7 @@ fun createContainerForLazyLocalClassifierAnalyzer(
useInstance(NoTopLevelDescriptorProvider)
TargetEnvironment.configureCompilerEnvironment(this)
useInstance(controlFlowInformationProviderFactory)
useInstance(FileScopeProvider.ThrowException)
useImpl<AnnotationResolverImpl>()
@@ -37,17 +37,20 @@ public class ControlFlowAnalyzer {
private final KotlinBuiltIns builtIns;
private final LanguageVersionSettings languageVersionSettings;
private final PlatformDiagnosticSuppressor diagnosticSuppressor;
private final ControlFlowInformationProvider.Factory controlFlowInformationProviderFactory;
public ControlFlowAnalyzer(
@NotNull BindingTrace trace,
@NotNull KotlinBuiltIns builtIns,
@NotNull LanguageVersionSettings languageVersionSettings,
@NotNull PlatformDiagnosticSuppressor diagnosticSuppressor
@NotNull PlatformDiagnosticSuppressor diagnosticSuppressor,
@NotNull ControlFlowInformationProvider.Factory controlFlowInformationProviderFactory
) {
this.trace = trace;
this.builtIns = builtIns;
this.languageVersionSettings = languageVersionSettings;
this.diagnosticSuppressor = diagnosticSuppressor;
this.controlFlowInformationProviderFactory = controlFlowInformationProviderFactory;
}
public void process(@NotNull BodiesResolveContext c) {
@@ -80,7 +83,9 @@ public class ControlFlowAnalyzer {
private void checkSecondaryConstructor(@NotNull KtSecondaryConstructor constructor) {
ControlFlowInformationProvider controlFlowInformationProvider =
new ControlFlowInformationProvider(constructor, trace, languageVersionSettings, diagnosticSuppressor);
controlFlowInformationProviderFactory.createControlFlowInformationProvider(
constructor, trace, languageVersionSettings, diagnosticSuppressor
);
controlFlowInformationProvider.checkDeclaration();
controlFlowInformationProvider.checkFunction(builtIns.getUnitType());
}
@@ -88,9 +93,10 @@ public class ControlFlowAnalyzer {
private void checkDeclarationContainer(@NotNull BodiesResolveContext c, KtDeclarationContainer declarationContainer) {
// A pseudocode of class/object initialization corresponds to a class/object
// or initialization of properties corresponds to a package declared in a file
ControlFlowInformationProvider controlFlowInformationProvider = new ControlFlowInformationProvider(
(KtElement) declarationContainer, trace, languageVersionSettings, diagnosticSuppressor
);
ControlFlowInformationProvider controlFlowInformationProvider =
controlFlowInformationProviderFactory.createControlFlowInformationProvider(
(KtElement) declarationContainer, trace, languageVersionSettings, diagnosticSuppressor
);
if (c.getTopDownAnalysisMode().isLocalDeclarations()) {
controlFlowInformationProvider.checkForLocalClassOrObjectMode();
return;
@@ -113,7 +119,9 @@ public class ControlFlowAnalyzer {
@NotNull BodiesResolveContext c, @NotNull KtDeclarationWithBody function, @Nullable KotlinType expectedReturnType
) {
ControlFlowInformationProvider controlFlowInformationProvider =
new ControlFlowInformationProvider(function, trace, languageVersionSettings, diagnosticSuppressor);
controlFlowInformationProviderFactory.createControlFlowInformationProvider(
function, trace, languageVersionSettings, diagnosticSuppressor
);
if (c.getTopDownAnalysisMode().isLocalDeclarations()) {
controlFlowInformationProvider.checkForLocalClassOrObjectMode();
return;
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.types.expressions
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.cfg.ControlFlowInformationProvider
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.GlobalContext
@@ -71,7 +72,8 @@ class LocalClassifierAnalyzer(
private val kotlinTypeChecker: NewKotlinTypeChecker,
private val samConversionResolver: SamConversionResolver,
private val additionalClassPartsProvider: AdditionalClassPartsProvider,
private val sealedClassInheritorsProvider: SealedClassInheritorsProvider
private val sealedClassInheritorsProvider: SealedClassInheritorsProvider,
private val controlFlowInformationProviderFactory: ControlFlowInformationProvider.Factory,
) {
fun processClassOrObject(
scope: LexicalWritableScope?,
@@ -110,7 +112,8 @@ class LocalClassifierAnalyzer(
additionalClassPartsProvider,
sealedClassInheritorsProvider
),
analyzerServices
analyzerServices,
controlFlowInformationProviderFactory,
)
container.get<LazyTopDownAnalyzer>().analyzeDeclarations(
@@ -185,7 +188,8 @@ class LocalClassDescriptorHolder(
override val samConversionResolver: SamConversionResolver = this@LocalClassDescriptorHolder.samConversionResolver
override val additionalClassPartsProvider: AdditionalClassPartsProvider =
this@LocalClassDescriptorHolder.additionalClassPartsProvider
override val sealedClassInheritorsProvider: SealedClassInheritorsProvider = this@LocalClassDescriptorHolder.sealedClassInheritorsProvider
override val sealedClassInheritorsProvider: SealedClassInheritorsProvider =
this@LocalClassDescriptorHolder.sealedClassInheritorsProvider
},
containingDeclaration,
classOrObject.nameAsSafeName,
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.tests.di
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.cfg.ControlFlowInformationProviderImpl
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.container.StorageComponentContainer
import org.jetbrains.kotlin.container.getValue
@@ -43,6 +44,7 @@ fun createContainerForTests(project: Project, module: ModuleDescriptor): Contain
)
useImpl<AnnotationResolverImpl>()
useInstance(ModuleStructureOracle.SingleModule)
useInstance(ControlFlowInformationProviderImpl.Factory)
})
}