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