[FIR] Speed up CFA-checkers

This commit is contained in:
vldf
2020-08-07 17:10:23 +03:00
parent 638a0d3b82
commit ac07438489
8 changed files with 38 additions and 22 deletions
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.fir.analysis
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirCfaPropertyAssignmentChecker
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirPropertyInitializationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
import org.jetbrains.kotlin.fir.analysis.checkers.expression.*
@@ -71,7 +71,7 @@ private class ComposedDeclarationCheckers : DeclarationCheckers() {
get() = _constructorCheckers
override val controlFlowAnalyserCheckers: List<FirControlFlowChecker>
get() = _controlFlowAnalyserCheckers
override val variableAssignmentCfaBasedCheckers: List<AbstractFirCfaPropertyAssignmentChecker>
override val variableAssignmentCfaBasedCheckers: List<AbstractFirPropertyInitializationChecker>
get() = _variableAssignmentCfaBasedCheckers
private val _fileCheckers: MutableList<FirFileChecker> = mutableListOf()
@@ -80,7 +80,7 @@ private class ComposedDeclarationCheckers : DeclarationCheckers() {
private val _regularClassCheckers: MutableList<FirRegularClassChecker> = mutableListOf()
private val _constructorCheckers: MutableList<FirConstructorChecker> = mutableListOf()
private val _controlFlowAnalyserCheckers: MutableList<FirControlFlowChecker> = mutableListOf()
private val _variableAssignmentCfaBasedCheckers: MutableList<AbstractFirCfaPropertyAssignmentChecker> = mutableListOf()
private val _variableAssignmentCfaBasedCheckers: MutableList<AbstractFirPropertyInitializationChecker> = mutableListOf()
fun register(checkers: DeclarationCheckers) {
_fileCheckers += checkers.allFileCheckers
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
abstract class AbstractFirCfaPropertyAssignmentChecker {
abstract class AbstractFirPropertyInitializationChecker {
abstract fun analyze(
graph: ControlFlowGraph,
reporter: DiagnosticReporter,
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph
class FirControlFlowAnalyzer(session: FirSession) {
@@ -20,23 +21,35 @@ class FirControlFlowAnalyzer(session: FirSession) {
fun analyzeClassInitializer(klass: FirClass<*>, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) {
if (graph.owner != null) return
checkers.forEach { it.analyze(graph, reporter) }
cfaCheckers.forEach { it.analyze(graph, reporter) }
}
fun analyzeFunction(function: FirFunction<*>, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) {
if (graph.owner != null) return
cfaCheckers.forEach { it.analyze(graph, reporter) }
val properties = AbstractFirCfaPropertyAssignmentChecker.LocalPropertyCollector.collect(graph)
if (properties.isEmpty()) return
val data = AbstractFirCfaPropertyAssignmentChecker.DataCollector(properties).getData(graph)
variableAssignmentCheckers.forEach { it.analyze(graph, reporter, data, properties) }
if (context.containingDeclarations.any { it is FirProperty || it is FirFunction<*> }) return
runAssignmentCfaCheckers(graph, reporter)
}
fun analyzePropertyInitializer(property: FirProperty, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) {
if (graph.owner != null) return
checkers.forEach { it.analyze(graph, reporter) }
cfaCheckers.forEach { it.analyze(graph, reporter) }
runAssignmentCfaCheckers(graph, reporter)
}
fun analyzePropertyAccessor(accessor: FirPropertyAccessor, graph: ControlFlowGraph, context: CheckerContext, reporter: DiagnosticReporter) {
if (graph.owner != null) return
cfaCheckers.forEach { it.analyze(graph, reporter) }
runAssignmentCfaCheckers(graph, reporter)
}
private fun runAssignmentCfaCheckers(graph: ControlFlowGraph, reporter: DiagnosticReporter) {
val properties = AbstractFirPropertyInitializationChecker.LocalPropertyCollector.collect(graph)
if (properties.isEmpty()) return
val data = AbstractFirPropertyInitializationChecker.DataCollector(properties).getData(graph)
variableAssignmentCheckers.forEach { it.analyze(graph, reporter, data, properties) }
}
}
@@ -18,14 +18,13 @@ import org.jetbrains.kotlin.fir.resolve.dfa.cfg.QualifiedAccessNode
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
object FirPropertyInitializationAnalyzer : AbstractFirCfaPropertyAssignmentChecker() {
object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChecker() {
override fun analyze(
graph: ControlFlowGraph,
reporter: DiagnosticReporter,
data: Map<CFGNode<*>, PropertyInitializationInfo>,
properties: Set<FirPropertySymbol>
) {
// getting symbols of properties without initializers and non-variable symbols
val localData = data.filter {
val symbolFir = (it.key.fir as? FirVariableSymbol<*>)?.fir
symbolFir == null || symbolFir.initializer == null && symbolFir.delegate == null
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirCfaPropertyAssignmentChecker
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirPropertyInitializationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
abstract class DeclarationCheckers {
@@ -19,7 +19,7 @@ abstract class DeclarationCheckers {
open val regularClassCheckers: List<FirRegularClassChecker> = emptyList()
open val constructorCheckers: List<FirConstructorChecker> = emptyList()
open val controlFlowAnalyserCheckers: List<FirControlFlowChecker> = emptyList()
open val variableAssignmentCfaBasedCheckers: List<AbstractFirCfaPropertyAssignmentChecker> = emptyList()
open val variableAssignmentCfaBasedCheckers: List<AbstractFirPropertyInitializationChecker> = emptyList()
internal val allFileCheckers: List<FirFileChecker> get() = fileCheckers + declarationCheckers
internal val allMemberDeclarationCheckers: List<FirMemberDeclarationChecker> get() = memberDeclarationCheckers + declarationCheckers
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirPropertyInitializationChecker
import org.jetbrains.kotlin.fir.analysis.cfa.FirCallsEffectAnalyzer
import org.jetbrains.kotlin.fir.analysis.cfa.FirPropertyInitializationAnalyzer
import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer
@@ -49,8 +50,11 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
)
override val controlFlowAnalyserCheckers: List<FirControlFlowChecker> = listOf(
FirPropertyInitializationAnalyzer,
FirCallsEffectAnalyzer,
FirReturnsImpliesAnalyzer
)
override val variableAssignmentCfaBasedCheckers: List<AbstractFirPropertyInitializationChecker> = listOf(
FirPropertyInitializationAnalyzer
)
}
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirCfaPropertyAssignmentChecker
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirPropertyInitializationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.extended.*
object ExtendedDeclarationCheckers : DeclarationCheckers() {
@@ -20,7 +20,7 @@ object ExtendedDeclarationCheckers : DeclarationCheckers() {
RedundantSetterParameterTypeChecker
)
override val variableAssignmentCfaBasedCheckers: List<AbstractFirCfaPropertyAssignmentChecker> = listOf(
override val variableAssignmentCfaBasedCheckers: List<AbstractFirPropertyInitializationChecker> = listOf(
VariableAssignmentChecker
)
}
@@ -9,7 +9,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.extended
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.FirFakeSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirCfaPropertyAssignmentChecker
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirPropertyInitializationChecker
import org.jetbrains.kotlin.fir.analysis.cfa.TraverseDirection
import org.jetbrains.kotlin.fir.analysis.cfa.traverse
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.fir.toFirPsiSourceElement
import org.jetbrains.kotlin.psi.KtProperty
object VariableAssignmentChecker : AbstractFirCfaPropertyAssignmentChecker() {
object VariableAssignmentChecker : AbstractFirPropertyInitializationChecker() {
override fun analyze(
graph: ControlFlowGraph,
reporter: DiagnosticReporter,
@@ -64,7 +64,7 @@ object VariableAssignmentChecker : AbstractFirCfaPropertyAssignmentChecker() {
destructuringCanBeVal = false
}
lastDestructuredVariables--
} else if (canBeVal(symbol, value) && symbol.fir.delegate == null) {
} else if (canBeVal(symbol, value) && symbol.fir.delegate == null ) {
reporter.report(source, FirErrors.CAN_BE_VAL)
}
}