From c959ad7911f243835f20b412780256413ad313fd Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Fri, 4 Dec 2020 10:04:27 -0800 Subject: [PATCH] FIR checker: revisit per-label iterations to avoid !! --- .../jetbrains/kotlin/fir/analysis/cfa/CfaUtils.kt | 5 ++--- .../fir/analysis/cfa/FirCallsEffectAnalyzer.kt | 6 +++--- .../cfa/FirPropertyInitializationAnalyzer.kt | 4 ++-- .../analysis/checkers/extended/UnusedChecker.kt | 15 +++++++-------- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/CfaUtils.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/CfaUtils.kt index ce21e657581..c3057877df5 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/CfaUtils.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/CfaUtils.kt @@ -128,15 +128,14 @@ class PropertyInitializationInfoCollector(private val localProperties: Set, S : ControlFlowInfo, K : Any> addRange( - info: P, + pathAwareInfo: P, key: K, range: EventOccurrencesRange, constructor: (PersistentMap) -> P ): P { var resultMap = persistentMapOf() // before: { |-> { p1 |-> PI1 }, l1 |-> { p2 |-> PI2 } } - for (label in info.keys) { - val dataPerLabel = info[label]!! + for ((label, dataPerLabel) in pathAwareInfo) { val existingKind = dataPerLabel[key] ?: EventOccurrencesRange.ZERO val kind = existingKind + range resultMap = resultMap.put(label, dataPerLabel.put(key, kind)) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt index d2cec5c9d10..f4b495535a9 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirCallsEffectAnalyzer.kt @@ -89,9 +89,9 @@ object FirCallsEffectAnalyzer : FirControlFlowChecker() { for ((symbol, effectDeclaration) in functionalTypeEffects) { graph.exitNode.previousCfgNodes.forEach { node -> val requiredRange = effectDeclaration.kind - val info = invocationData.getValue(node) - for (label in info.keys) { - if (investigate(info.getValue(label), symbol, requiredRange, function, reporter)) { + val pathAwareInfo = invocationData.getValue(node) + for (info in pathAwareInfo.values) { + if (investigate(info, symbol, requiredRange, function, reporter)) { // To avoid duplicate reports, stop investigating remaining paths once reported. break } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirPropertyInitializationAnalyzer.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirPropertyInitializationAnalyzer.kt index f42b1564e7f..8a1fffdccf5 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirPropertyInitializationAnalyzer.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/cfa/FirPropertyInitializationAnalyzer.kt @@ -49,8 +49,8 @@ object FirPropertyInitializationAnalyzer : AbstractFirPropertyInitializationChec if (symbol !in localProperties) return if (symbol.fir.isLateInit) return val pathAwareInfo = data.getValue(node) - for (label in pathAwareInfo.keys) { - if (investigate(pathAwareInfo[label]!!, symbol, node)) { + for (info in pathAwareInfo.values) { + if (investigate(info, symbol, node)) { // To avoid duplicate reports, stop investigating remaining paths if the property is not initialized at any path. break } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnusedChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnusedChecker.kt index f60f9936b1f..19f5dc3c62c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnusedChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/UnusedChecker.kt @@ -44,8 +44,8 @@ object UnusedChecker : FirControlFlowChecker() { override fun visitVariableAssignmentNode(node: VariableAssignmentNode) { val variableSymbol = (node.fir.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol ?: return val dataPerNode = data[node] ?: return - for (label in dataPerNode.keys) { - val data = dataPerNode[label]!![variableSymbol] ?: continue + for (dataPerLabel in dataPerNode.values) { + val data = dataPerLabel[variableSymbol] ?: continue if (data == VariableStatus.ONLY_WRITTEN_NEVER_READ) { // todo: report case like "a += 1" where `a` `doesn't writes` different way (special for Idea) val source = node.fir.lValue.source @@ -60,8 +60,8 @@ object UnusedChecker : FirControlFlowChecker() { val variableSymbol = node.fir.symbol if (variableSymbol.isLoopIterator) return val dataPerNode = data[node] ?: return - for (label in dataPerNode.keys) { - val data = dataPerNode[label]!![variableSymbol] ?: continue + for (dataPerLabel in dataPerNode.values) { + val data = dataPerLabel[variableSymbol] ?: continue val variableSource = variableSymbol.fir.source.takeIf { it?.elementType != KtNodeTypes.DESTRUCTURING_DECLARATION } when { @@ -242,14 +242,13 @@ object UnusedChecker : FirControlFlowChecker() { } private fun update( - info: PathAwareVariableStatusInfo, + pathAwareInfo: PathAwareVariableStatusInfo, symbol: FirPropertySymbol, updater: (VariableStatus?) -> VariableStatus?, ): PathAwareVariableStatusInfo { var resultMap = persistentMapOf() var changed = false - for (label in info.keys) { - val dataPerLabel = info[label]!! + for ((label, dataPerLabel) in pathAwareInfo) { val v = updater.invoke(dataPerLabel[symbol]) if (v != null) { resultMap = resultMap.put(label, dataPerLabel.put(symbol, v)) @@ -258,7 +257,7 @@ object UnusedChecker : FirControlFlowChecker() { resultMap = resultMap.put(label, dataPerLabel) } } - return if (changed) PathAwareVariableStatusInfo(resultMap) else info + return if (changed) PathAwareVariableStatusInfo(resultMap) else pathAwareInfo } }