[FIR] Don't recalculate argumentVariables for the same node
`knownVariables` can't be moved to the outer function, because it's specific to the current path: we want to check that the contract condition is approved along the current path. For example, in the `FirPsiDiagnosticTestGenerated.testPropertyGetter` test when analyzing the function, we want to check if we can derive the `d1 == Any` type statement (where `d1` is the receiver). If we can't, the flow won't contain `d1` among `knownVariables`
This commit is contained in:
committed by
Space Team
parent
1c446151e7
commit
bb8d3a0f80
+19
-14
@@ -54,11 +54,25 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
|
||||
if (function !is FirContractDescriptionOwner || function.contractDescription.source == null) return
|
||||
val effects = function.contractDescription.effects ?: return
|
||||
val dataFlowInfo = function.controlFlowGraphReference?.dataFlowInfo ?: return
|
||||
|
||||
val argumentIdentifiers = Array(function.valueParameters.size + 1) { i ->
|
||||
val parameterSymbol = if (i > 0) {
|
||||
function.valueParameters[i - 1].symbol
|
||||
} else {
|
||||
if (function.symbol is FirPropertyAccessorSymbol) {
|
||||
context.containingProperty?.symbol
|
||||
} else {
|
||||
null
|
||||
} ?: function.symbol
|
||||
}
|
||||
Identifier(parameterSymbol, null, null)
|
||||
}
|
||||
|
||||
for (firEffect in effects) {
|
||||
val coneEffect = firEffect.effect as? ConeConditionalEffectDeclaration ?: continue
|
||||
val returnValue = coneEffect.effect as? ConeReturnsEffectDeclaration ?: continue
|
||||
val wrongCondition = graph.exitNode.previousCfgNodes.any {
|
||||
isWrongConditionOnNode(it, coneEffect, returnValue, function, logicSystem, dataFlowInfo, context)
|
||||
isWrongConditionOnNode(it, coneEffect, returnValue, function, logicSystem, dataFlowInfo, argumentIdentifiers, context)
|
||||
}
|
||||
if (wrongCondition) {
|
||||
// TODO, KT-59813: reportOn(firEffect.source, ...)
|
||||
@@ -74,6 +88,7 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
|
||||
function: FirFunction,
|
||||
logicSystem: LogicSystem,
|
||||
dataFlowInfo: DataFlowInfo,
|
||||
argumentIdentifiers: Array<Identifier>,
|
||||
context: CheckerContext
|
||||
): Boolean {
|
||||
val builtinTypes = context.session.builtinTypes
|
||||
@@ -87,7 +102,7 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
|
||||
|
||||
if (isReturn && resultExpression is FirWhenExpression) {
|
||||
return node.collectBranchExits().any {
|
||||
isWrongConditionOnNode(it, effectDeclaration, effect, function, logicSystem, dataFlowInfo, context)
|
||||
isWrongConditionOnNode(it, effectDeclaration, effect, function, logicSystem, dataFlowInfo, argumentIdentifiers, context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,18 +128,8 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
|
||||
// TODO, KT-59814: if this is not a top-level function, `FirDataFlowAnalyzer` has erased its value parameters
|
||||
// from `dataFlowInfo.variableStorage` for some reason, so its `getLocalVariable` doesn't work.
|
||||
val knownVariables = flow.knownVariables.associateBy { it.identifier }
|
||||
// TODO, KT-59815: these should be the same on all return paths, so maybe don't recompute them every time?
|
||||
val argumentVariables = Array(function.valueParameters.size + 1) { i ->
|
||||
val parameterSymbol = if (i > 0) {
|
||||
function.valueParameters[i - 1].symbol
|
||||
} else {
|
||||
if (function.symbol is FirPropertyAccessorSymbol) {
|
||||
context.containingProperty?.symbol
|
||||
} else {
|
||||
null
|
||||
} ?: function.symbol
|
||||
}
|
||||
val identifier = Identifier(parameterSymbol, null, null)
|
||||
val argumentVariables = Array(argumentIdentifiers.size) { i ->
|
||||
val identifier = argumentIdentifiers[i]
|
||||
// Might be unknown if there are no statements made about that parameter, but it's still possible that trivial
|
||||
// contracts are valid. E.g. `returns() implies (x is String)` when `x`'s *original type* is already `String`.
|
||||
knownVariables[identifier] ?: RealVariable(identifier, i == 0, null, i, PropertyStability.STABLE_VALUE)
|
||||
|
||||
Reference in New Issue
Block a user