[FIR] Split CfaUtils to multiple files
This commit is contained in:
committed by
teamcityserver
parent
bdb61ec5d7
commit
bce62430ce
+86
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.fir.analysis.cfa
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirDoWhileLoop
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirLoop
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirWhileLoop
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
|
import org.jetbrains.kotlin.fir.util.SetMultimap
|
||||||
|
import org.jetbrains.kotlin.fir.util.setMultimapOf
|
||||||
|
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||||
|
|
||||||
|
// Note that [PreliminaryLoopVisitor] in FIR DFA collects assigned variable names.
|
||||||
|
// This one collects declared variable symbols per capturing statements.
|
||||||
|
class DeclaredVariableCollector {
|
||||||
|
val declaredVariablesPerElement: SetMultimap<FirStatement, FirPropertySymbol> = setMultimapOf()
|
||||||
|
|
||||||
|
fun enterCapturingStatement(statement: FirStatement): Set<FirPropertySymbol> {
|
||||||
|
assert(statement is FirLoop || statement is FirClass || statement is FirFunction)
|
||||||
|
if (statement !in declaredVariablesPerElement) {
|
||||||
|
statement.accept(visitor, null)
|
||||||
|
}
|
||||||
|
return declaredVariablesPerElement[statement]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun exitCapturingStatement(statement: FirStatement) {
|
||||||
|
assert(statement is FirLoop || statement is FirClass || statement is FirFunction)
|
||||||
|
declaredVariablesPerElement.removeKey(statement)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resetState() {
|
||||||
|
declaredVariablesPerElement.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FirStatement -- closest statement (loop/lambda/local declaration) which may contain reassignments
|
||||||
|
private val visitor = object : FirVisitor<Unit, FirStatement?>() {
|
||||||
|
override fun visitElement(element: FirElement, data: FirStatement?) {
|
||||||
|
element.acceptChildren(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitProperty(property: FirProperty, data: FirStatement?) {
|
||||||
|
if (property.isLocal) {
|
||||||
|
requireNotNull(data)
|
||||||
|
declaredVariablesPerElement.put(data, property.symbol)
|
||||||
|
}
|
||||||
|
visitElement(property, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitWhileLoop(whileLoop: FirWhileLoop, data: FirStatement?) {
|
||||||
|
visitCapturingStatement(whileLoop, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDoWhileLoop(doWhileLoop: FirDoWhileLoop, data: FirStatement?) {
|
||||||
|
visitCapturingStatement(doWhileLoop, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: FirStatement?) {
|
||||||
|
visitCapturingStatement(anonymousFunction, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: FirStatement?) {
|
||||||
|
visitCapturingStatement(simpleFunction, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitRegularClass(regularClass: FirRegularClass, data: FirStatement?) {
|
||||||
|
visitCapturingStatement(regularClass, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: FirStatement?) {
|
||||||
|
visitCapturingStatement(anonymousObject, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun visitCapturingStatement(statement: FirStatement, parent: FirStatement?) {
|
||||||
|
visitElement(statement, statement)
|
||||||
|
if (parent != null) {
|
||||||
|
declaredVariablesPerElement.putAll(parent, declaredVariablesPerElement[statement])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.fir.analysis.cfa
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.referredPropertySymbol
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
|
|
||||||
|
class LocalPropertyAndCapturedWriteCollector private constructor() : ControlFlowGraphVisitorVoid() {
|
||||||
|
companion object {
|
||||||
|
fun collect(graph: ControlFlowGraph): Pair<Set<FirPropertySymbol>, Set<FirVariableAssignment>> {
|
||||||
|
val collector = LocalPropertyAndCapturedWriteCollector()
|
||||||
|
graph.traverse(TraverseDirection.Forward, collector)
|
||||||
|
return collector.symbols.keys to collector.capturedWrites
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mapping from a property symbol to its declaration context
|
||||||
|
// `true` if the (local) property is declared in the currently visited function.
|
||||||
|
// `false` if it is declared in a lambda or a local function (inside the currently visited function).
|
||||||
|
private val symbols: MutableMap<FirPropertySymbol, Boolean> = mutableMapOf()
|
||||||
|
|
||||||
|
private val lambdaOrLocalFunctionStack: MutableList<FirFunction> = mutableListOf()
|
||||||
|
private val capturedWrites: MutableSet<FirVariableAssignment> = mutableSetOf()
|
||||||
|
|
||||||
|
override fun visitNode(node: CFGNode<*>) {}
|
||||||
|
|
||||||
|
override fun visitVariableDeclarationNode(node: VariableDeclarationNode) {
|
||||||
|
symbols[node.fir.symbol] = lambdaOrLocalFunctionStack.lastOrNull() == null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitPostponedLambdaEnterNode(node: PostponedLambdaEnterNode) {
|
||||||
|
lambdaOrLocalFunctionStack.add(node.fir)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitPostponedLambdaExitNode(node: PostponedLambdaExitNode) {
|
||||||
|
lambdaOrLocalFunctionStack.remove(node.fir.anonymousFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLocalFunctionDeclarationNode(node: LocalFunctionDeclarationNode, data: Nothing?) {
|
||||||
|
lambdaOrLocalFunctionStack.add(node.fir)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunctionExitNode(node: FunctionExitNode) {
|
||||||
|
lambdaOrLocalFunctionStack.remove(node.fir)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitVariableAssignmentNode(node: VariableAssignmentNode) {
|
||||||
|
// Check if this variable assignment is inside a lambda or a local function.
|
||||||
|
if (lambdaOrLocalFunctionStack.isEmpty()) return
|
||||||
|
|
||||||
|
// Check if the assigned variable doesn't belong to any lambda or local function.
|
||||||
|
val symbol = node.fir.referredPropertySymbol ?: return
|
||||||
|
if (symbol !in symbols || symbols[symbol] == false) return
|
||||||
|
|
||||||
|
// If all nested declarations are lambdas that are invoked in-place (according to the contract),
|
||||||
|
// this variable assignment is not a captured write.
|
||||||
|
if (lambdaOrLocalFunctionStack.all { it is FirAnonymousFunction && it.invocationKind.isInPlace }) return
|
||||||
|
|
||||||
|
capturedWrites.add(node.fir)
|
||||||
|
}
|
||||||
|
}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.fir.analysis.cfa
|
||||||
|
|
||||||
|
import kotlinx.collections.immutable.PersistentMap
|
||||||
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
|
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.EdgeLabel
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.NormalPath
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
|
|
||||||
|
abstract class EventOccurrencesRangeInfo<E : EventOccurrencesRangeInfo<E, K>, K : Any>(
|
||||||
|
map: PersistentMap<K, EventOccurrencesRange> = persistentMapOf()
|
||||||
|
) : ControlFlowInfo<E, K, EventOccurrencesRange>(map) {
|
||||||
|
|
||||||
|
override fun merge(other: E): E =
|
||||||
|
operation(other, EventOccurrencesRange::or)
|
||||||
|
|
||||||
|
fun plus(other: E): E =
|
||||||
|
when {
|
||||||
|
isEmpty() -> other
|
||||||
|
other.isEmpty() ->
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
this as E
|
||||||
|
else -> operation(other, EventOccurrencesRange::plus)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun operation(other: E, op: (EventOccurrencesRange, EventOccurrencesRange) -> EventOccurrencesRange): E {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
var result = this as E
|
||||||
|
for (symbol in keys.union(other.keys)) {
|
||||||
|
val kind1 = this[symbol] ?: EventOccurrencesRange.ZERO
|
||||||
|
val kind2 = other[symbol] ?: EventOccurrencesRange.ZERO
|
||||||
|
result = result.put(symbol, op.invoke(kind1, kind2))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PropertyInitializationInfo(
|
||||||
|
map: PersistentMap<FirPropertySymbol, EventOccurrencesRange> = persistentMapOf()
|
||||||
|
) : EventOccurrencesRangeInfo<PropertyInitializationInfo, FirPropertySymbol>(map) {
|
||||||
|
companion object {
|
||||||
|
val EMPTY = PropertyInitializationInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val constructor: (PersistentMap<FirPropertySymbol, EventOccurrencesRange>) -> PropertyInitializationInfo =
|
||||||
|
::PropertyInitializationInfo
|
||||||
|
|
||||||
|
override val empty: () -> PropertyInitializationInfo =
|
||||||
|
::EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
class PathAwarePropertyInitializationInfo(
|
||||||
|
map: PersistentMap<EdgeLabel, PropertyInitializationInfo> = persistentMapOf()
|
||||||
|
) : PathAwareControlFlowInfo<PathAwarePropertyInitializationInfo, PropertyInitializationInfo>(map) {
|
||||||
|
companion object {
|
||||||
|
val EMPTY = PathAwarePropertyInitializationInfo(persistentMapOf(NormalPath to PropertyInitializationInfo.EMPTY))
|
||||||
|
}
|
||||||
|
|
||||||
|
override val constructor: (PersistentMap<EdgeLabel, PropertyInitializationInfo>) -> PathAwarePropertyInitializationInfo =
|
||||||
|
::PathAwarePropertyInitializationInfo
|
||||||
|
|
||||||
|
override val empty: () -> PathAwarePropertyInitializationInfo =
|
||||||
|
::EMPTY
|
||||||
|
}
|
||||||
+3
-188
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2021 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -8,126 +8,10 @@ package org.jetbrains.kotlin.fir.analysis.cfa
|
|||||||
import kotlinx.collections.immutable.PersistentMap
|
import kotlinx.collections.immutable.PersistentMap
|
||||||
import kotlinx.collections.immutable.persistentMapOf
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||||
import org.jetbrains.kotlin.fir.FirElement
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.referredPropertySymbol
|
import org.jetbrains.kotlin.fir.declarations.utils.referredPropertySymbol
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||||
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
|
||||||
import org.jetbrains.kotlin.fir.util.SetMultimap
|
|
||||||
import org.jetbrains.kotlin.fir.util.setMultimapOf
|
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
|
||||||
|
|
||||||
abstract class EventOccurrencesRangeInfo<E : EventOccurrencesRangeInfo<E, K>, K : Any>(
|
|
||||||
map: PersistentMap<K, EventOccurrencesRange> = persistentMapOf()
|
|
||||||
) : ControlFlowInfo<E, K, EventOccurrencesRange>(map) {
|
|
||||||
|
|
||||||
override fun merge(other: E): E =
|
|
||||||
operation(other, EventOccurrencesRange::or)
|
|
||||||
|
|
||||||
fun plus(other: E): E =
|
|
||||||
when {
|
|
||||||
isEmpty() -> other
|
|
||||||
other.isEmpty() ->
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
this as E
|
|
||||||
else -> operation(other, EventOccurrencesRange::plus)
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun operation(other: E, op: (EventOccurrencesRange, EventOccurrencesRange) -> EventOccurrencesRange): E {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
var result = this as E
|
|
||||||
for (symbol in keys.union(other.keys)) {
|
|
||||||
val kind1 = this[symbol] ?: EventOccurrencesRange.ZERO
|
|
||||||
val kind2 = other[symbol] ?: EventOccurrencesRange.ZERO
|
|
||||||
result = result.put(symbol, op.invoke(kind1, kind2))
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PropertyInitializationInfo(
|
|
||||||
map: PersistentMap<FirPropertySymbol, EventOccurrencesRange> = persistentMapOf()
|
|
||||||
) : EventOccurrencesRangeInfo<PropertyInitializationInfo, FirPropertySymbol>(map) {
|
|
||||||
companion object {
|
|
||||||
val EMPTY = PropertyInitializationInfo()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val constructor: (PersistentMap<FirPropertySymbol, EventOccurrencesRange>) -> PropertyInitializationInfo =
|
|
||||||
::PropertyInitializationInfo
|
|
||||||
|
|
||||||
override val empty: () -> PropertyInitializationInfo =
|
|
||||||
::EMPTY
|
|
||||||
}
|
|
||||||
|
|
||||||
class LocalPropertyAndCapturedWriteCollector private constructor() : ControlFlowGraphVisitorVoid() {
|
|
||||||
companion object {
|
|
||||||
fun collect(graph: ControlFlowGraph): Pair<Set<FirPropertySymbol>, Set<FirVariableAssignment>> {
|
|
||||||
val collector = LocalPropertyAndCapturedWriteCollector()
|
|
||||||
graph.traverse(TraverseDirection.Forward, collector)
|
|
||||||
return collector.symbols.keys to collector.capturedWrites
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mapping from a property symbol to its declaration context
|
|
||||||
// `true` if the (local) property is declared in the currently visited function.
|
|
||||||
// `false` if it is declared in a lambda or a local function (inside the currently visited function).
|
|
||||||
private val symbols: MutableMap<FirPropertySymbol, Boolean> = mutableMapOf()
|
|
||||||
|
|
||||||
private val lambdaOrLocalFunctionStack: MutableList<FirFunction> = mutableListOf()
|
|
||||||
private val capturedWrites: MutableSet<FirVariableAssignment> = mutableSetOf()
|
|
||||||
|
|
||||||
override fun visitNode(node: CFGNode<*>) {}
|
|
||||||
|
|
||||||
override fun visitVariableDeclarationNode(node: VariableDeclarationNode) {
|
|
||||||
symbols[node.fir.symbol] = lambdaOrLocalFunctionStack.lastOrNull() == null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitPostponedLambdaEnterNode(node: PostponedLambdaEnterNode) {
|
|
||||||
lambdaOrLocalFunctionStack.add(node.fir)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitPostponedLambdaExitNode(node: PostponedLambdaExitNode) {
|
|
||||||
lambdaOrLocalFunctionStack.remove(node.fir.anonymousFunction)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitLocalFunctionDeclarationNode(node: LocalFunctionDeclarationNode, data: Nothing?) {
|
|
||||||
lambdaOrLocalFunctionStack.add(node.fir)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitFunctionExitNode(node: FunctionExitNode) {
|
|
||||||
lambdaOrLocalFunctionStack.remove(node.fir)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitVariableAssignmentNode(node: VariableAssignmentNode) {
|
|
||||||
// Check if this variable assignment is inside a lambda or a local function.
|
|
||||||
if (lambdaOrLocalFunctionStack.isEmpty()) return
|
|
||||||
|
|
||||||
// Check if the assigned variable doesn't belong to any lambda or local function.
|
|
||||||
val symbol = node.fir.referredPropertySymbol ?: return
|
|
||||||
if (symbol !in symbols || symbols[symbol] == false) return
|
|
||||||
|
|
||||||
// If all nested declarations are lambdas that are invoked in-place (according to the contract),
|
|
||||||
// this variable assignment is not a captured write.
|
|
||||||
if (lambdaOrLocalFunctionStack.all { it is FirAnonymousFunction && it.invocationKind.isInPlace }) return
|
|
||||||
|
|
||||||
capturedWrites.add(node.fir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PathAwarePropertyInitializationInfo(
|
|
||||||
map: PersistentMap<EdgeLabel, PropertyInitializationInfo> = persistentMapOf()
|
|
||||||
) : PathAwareControlFlowInfo<PathAwarePropertyInitializationInfo, PropertyInitializationInfo>(map) {
|
|
||||||
companion object {
|
|
||||||
val EMPTY = PathAwarePropertyInitializationInfo(persistentMapOf(NormalPath to PropertyInitializationInfo.EMPTY))
|
|
||||||
}
|
|
||||||
|
|
||||||
override val constructor: (PersistentMap<EdgeLabel, PropertyInitializationInfo>) -> PathAwarePropertyInitializationInfo =
|
|
||||||
::PathAwarePropertyInitializationInfo
|
|
||||||
|
|
||||||
override val empty: () -> PathAwarePropertyInitializationInfo =
|
|
||||||
::EMPTY
|
|
||||||
}
|
|
||||||
|
|
||||||
class PropertyInitializationInfoCollector(
|
class PropertyInitializationInfoCollector(
|
||||||
private val localProperties: Set<FirPropertySymbol>,
|
private val localProperties: Set<FirPropertySymbol>,
|
||||||
@@ -260,75 +144,6 @@ class PropertyInitializationInfoCollector(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that [PreliminaryLoopVisitor] in FIR DFA collects assigned variable names.
|
|
||||||
// This one collects declared variable symbols per capturing statements.
|
|
||||||
class DeclaredVariableCollector {
|
|
||||||
val declaredVariablesPerElement: SetMultimap<FirStatement, FirPropertySymbol> = setMultimapOf()
|
|
||||||
|
|
||||||
fun enterCapturingStatement(statement: FirStatement): Set<FirPropertySymbol> {
|
|
||||||
assert(statement is FirLoop || statement is FirClass || statement is FirFunction)
|
|
||||||
if (statement !in declaredVariablesPerElement) {
|
|
||||||
statement.accept(visitor, null)
|
|
||||||
}
|
|
||||||
return declaredVariablesPerElement[statement]
|
|
||||||
}
|
|
||||||
|
|
||||||
fun exitCapturingStatement(statement: FirStatement) {
|
|
||||||
assert(statement is FirLoop || statement is FirClass || statement is FirFunction)
|
|
||||||
declaredVariablesPerElement.removeKey(statement)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun resetState() {
|
|
||||||
declaredVariablesPerElement.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
// FirStatement -- closest statement (loop/lambda/local declaration) which may contain reassignments
|
|
||||||
private val visitor = object : FirVisitor<Unit, FirStatement?>() {
|
|
||||||
override fun visitElement(element: FirElement, data: FirStatement?) {
|
|
||||||
element.acceptChildren(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitProperty(property: FirProperty, data: FirStatement?) {
|
|
||||||
if (property.isLocal) {
|
|
||||||
requireNotNull(data)
|
|
||||||
declaredVariablesPerElement.put(data, property.symbol)
|
|
||||||
}
|
|
||||||
visitElement(property, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitWhileLoop(whileLoop: FirWhileLoop, data: FirStatement?) {
|
|
||||||
visitCapturingStatement(whileLoop, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDoWhileLoop(doWhileLoop: FirDoWhileLoop, data: FirStatement?) {
|
|
||||||
visitCapturingStatement(doWhileLoop, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: FirStatement?) {
|
|
||||||
visitCapturingStatement(anonymousFunction, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: FirStatement?) {
|
|
||||||
visitCapturingStatement(simpleFunction, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitRegularClass(regularClass: FirRegularClass, data: FirStatement?) {
|
|
||||||
visitCapturingStatement(regularClass, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: FirStatement?) {
|
|
||||||
visitCapturingStatement(anonymousObject, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitCapturingStatement(statement: FirStatement, parent: FirStatement?) {
|
|
||||||
visitElement(statement, statement)
|
|
||||||
if (parent != null) {
|
|
||||||
declaredVariablesPerElement.putAll(parent, declaredVariablesPerElement[statement])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun <P : PathAwareControlFlowInfo<P, S>, S : ControlFlowInfo<S, K, EventOccurrencesRange>, K : Any> addRange(
|
internal fun <P : PathAwareControlFlowInfo<P, S>, S : ControlFlowInfo<S, K, EventOccurrencesRange>, K : Any> addRange(
|
||||||
pathAwareInfo: P,
|
pathAwareInfo: P,
|
||||||
key: K,
|
key: K,
|
||||||
@@ -341,7 +156,7 @@ internal fun <P : PathAwareControlFlowInfo<P, S>, S : ControlFlowInfo<S, K, Even
|
|||||||
return updateRange(pathAwareInfo, key, { existingKind -> existingKind + range }, constructor)
|
return updateRange(pathAwareInfo, key, { existingKind -> existingKind + range }, constructor)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun <P : PathAwareControlFlowInfo<P, S>, S : ControlFlowInfo<S, K, EventOccurrencesRange>, K : Any> overwriteRange(
|
private fun <P : PathAwareControlFlowInfo<P, S>, S : ControlFlowInfo<S, K, EventOccurrencesRange>, K : Any> overwriteRange(
|
||||||
pathAwareInfo: P,
|
pathAwareInfo: P,
|
||||||
key: K,
|
key: K,
|
||||||
range: EventOccurrencesRange,
|
range: EventOccurrencesRange,
|
||||||
+1
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.test.runners
|
package org.jetbrains.kotlin.test.runners
|
||||||
|
|
||||||
import org.jetbrains.kotlin.config.ExplicitApiMode
|
import org.jetbrains.kotlin.config.ExplicitApiMode
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||||
import org.jetbrains.kotlin.test.TestJdkKind
|
import org.jetbrains.kotlin.test.TestJdkKind
|
||||||
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
||||||
|
|||||||
Reference in New Issue
Block a user