Minor: refactor FirPropertyInitializationAnalyzer
Still not sure how to implement visitUnionNode
This commit is contained in:
+15
-55
@@ -5,13 +5,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.analysis.cfa
|
package org.jetbrains.kotlin.fir.analysis.cfa
|
||||||
|
|
||||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
|
||||||
import org.jetbrains.kotlin.contracts.description.canBeRevisited
|
import org.jetbrains.kotlin.contracts.description.canBeRevisited
|
||||||
import org.jetbrains.kotlin.contracts.description.isDefinitelyVisited
|
import org.jetbrains.kotlin.contracts.description.isDefinitelyVisited
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.analysis.cfa.util.PathAwarePropertyInitializationInfo
|
import org.jetbrains.kotlin.fir.analysis.cfa.util.PathAwarePropertyInitializationInfo
|
||||||
import org.jetbrains.kotlin.fir.analysis.cfa.util.PropertyInitializationInfo
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.cfa.util.TraverseDirection
|
import org.jetbrains.kotlin.fir.analysis.cfa.util.TraverseDirection
|
||||||
import org.jetbrains.kotlin.fir.analysis.cfa.util.traverse
|
import org.jetbrains.kotlin.fir.analysis.cfa.util.traverse
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
@@ -37,14 +35,8 @@ object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChec
|
|||||||
capturedWrites: Set<FirVariableAssignment>,
|
capturedWrites: Set<FirVariableAssignment>,
|
||||||
context: CheckerContext
|
context: CheckerContext
|
||||||
) {
|
) {
|
||||||
val localData = data.filter {
|
|
||||||
val symbol = it.key.fir as? FirVariableSymbol<*>
|
|
||||||
symbol == null || !symbol.isInitialized()
|
|
||||||
}
|
|
||||||
|
|
||||||
val localProperties = properties.filterNotTo(mutableSetOf()) { it.isInitialized() }
|
val localProperties = properties.filterNotTo(mutableSetOf()) { it.isInitialized() }
|
||||||
|
val reporterVisitor = PropertyReporter(data, localProperties, capturedWrites, reporter, context)
|
||||||
val reporterVisitor = PropertyReporter(localData, localProperties, capturedWrites, reporter, context)
|
|
||||||
graph.traverse(TraverseDirection.Forward, reporterVisitor)
|
graph.traverse(TraverseDirection.Forward, reporterVisitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,68 +55,36 @@ object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChec
|
|||||||
) : ControlFlowGraphVisitorVoid() {
|
) : ControlFlowGraphVisitorVoid() {
|
||||||
override fun visitNode(node: CFGNode<*>) {}
|
override fun visitNode(node: CFGNode<*>) {}
|
||||||
|
|
||||||
override fun <T> visitUnionNode(node: T) where T : CFGNode<*>, T : UnionNodeMarker {}
|
override fun <T> visitUnionNode(node: T) where T : CFGNode<*>, T : UnionNodeMarker {
|
||||||
|
// TODO: f({ x = 1 }, { x = 2 }) - which to report?
|
||||||
private fun getPropertySymbol(node: CFGNode<*>): FirPropertySymbol? {
|
// Also this is currently indistinguishable from x = 1; f({}, {}).
|
||||||
return (node.fir as? FirQualifiedAccess)?.referredPropertySymbol
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val CFGNode<*>.propertySymbol: FirPropertySymbol?
|
||||||
|
get() = (fir as? FirQualifiedAccess)?.referredPropertySymbol
|
||||||
|
|
||||||
override fun visitVariableAssignmentNode(node: VariableAssignmentNode) {
|
override fun visitVariableAssignmentNode(node: VariableAssignmentNode) {
|
||||||
val symbol = getPropertySymbol(node) ?: return
|
val symbol = node.propertySymbol ?: return
|
||||||
val pathAwareInfo = data.getValue(node)
|
if (!symbol.fir.isVal) return
|
||||||
for (label in pathAwareInfo.keys) {
|
|
||||||
if (investigateVariableAssignment(pathAwareInfo[label]!!, symbol, node)) {
|
|
||||||
// To avoid duplicate reports, stop investigating remaining paths if the property is re-initialized at any path.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun investigateVariableAssignment(
|
if (node.fir in capturedWrites) {
|
||||||
info: PropertyInitializationInfo,
|
|
||||||
symbol: FirPropertySymbol,
|
|
||||||
node: VariableAssignmentNode
|
|
||||||
): Boolean {
|
|
||||||
if (symbol.fir.isVal && node.fir in capturedWrites) {
|
|
||||||
if (symbol.fir.isLocal) {
|
if (symbol.fir.isLocal) {
|
||||||
reporter.reportOn(node.fir.lValue.source, FirErrors.CAPTURED_VAL_INITIALIZATION, symbol, context)
|
reporter.reportOn(node.fir.lValue.source, FirErrors.CAPTURED_VAL_INITIALIZATION, symbol, context)
|
||||||
} else {
|
} else {
|
||||||
reporter.reportOn(node.fir.lValue.source, FirErrors.CAPTURED_MEMBER_VAL_INITIALIZATION, symbol, context)
|
reporter.reportOn(node.fir.lValue.source, FirErrors.CAPTURED_MEMBER_VAL_INITIALIZATION, symbol, context)
|
||||||
}
|
}
|
||||||
return true
|
} else if (symbol is FirSyntheticPropertySymbol || data.getValue(node).values.any { it[symbol]?.canBeRevisited() == true }) {
|
||||||
}
|
|
||||||
val kind = info[symbol] ?: EventOccurrencesRange.ZERO
|
|
||||||
if (symbol.fir.isVal && (symbol is FirSyntheticPropertySymbol || kind.canBeRevisited())) {
|
|
||||||
reporter.reportOn(node.fir.lValue.source, FirErrors.VAL_REASSIGNMENT, symbol, context)
|
reporter.reportOn(node.fir.lValue.source, FirErrors.VAL_REASSIGNMENT, symbol, context)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitQualifiedAccessNode(node: QualifiedAccessNode) {
|
override fun visitQualifiedAccessNode(node: QualifiedAccessNode) {
|
||||||
val symbol = getPropertySymbol(node) ?: return
|
val symbol = node.propertySymbol ?: return
|
||||||
if (symbol !in localProperties) return
|
if (symbol in localProperties && !symbol.fir.isLateInit && symbol !is FirSyntheticPropertySymbol &&
|
||||||
if (symbol.fir.isLateInit) return
|
!data.getValue(node).values.all { it[symbol]?.isDefinitelyVisited() == true }
|
||||||
val pathAwareInfo = data.getValue(node)
|
) {
|
||||||
for (info in pathAwareInfo.values) {
|
|
||||||
if (investigateVariableAccess(info, symbol, node)) {
|
|
||||||
// To avoid duplicate reports, stop investigating remaining paths if the property is not initialized at any path.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun investigateVariableAccess(
|
|
||||||
info: PropertyInitializationInfo,
|
|
||||||
symbol: FirPropertySymbol,
|
|
||||||
node: QualifiedAccessNode
|
|
||||||
): Boolean {
|
|
||||||
val kind = info[symbol] ?: EventOccurrencesRange.ZERO
|
|
||||||
if (symbol !is FirSyntheticPropertySymbol && !kind.isDefinitelyVisited()) {
|
|
||||||
reporter.reportOn(node.fir.source, FirErrors.UNINITIALIZED_VARIABLE, symbol, context)
|
reporter.reportOn(node.fir.source, FirErrors.UNINITIALIZED_VARIABLE, symbol, context)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user