[FIR] Fix data-flow after while loops

This commit is contained in:
simon.ogorodnik
2020-01-31 15:20:19 +03:00
committed by Mikhail Glukhikh
parent 91b432b4a1
commit 645602b675
15 changed files with 34 additions and 19 deletions
@@ -392,6 +392,19 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
// ----------------------------------- While Loop ----------------------------------- // ----------------------------------- While Loop -----------------------------------
private fun exitCommonLoop(exitNode: LoopExitNode) {
val singlePreviousNode = exitNode.previousNodes.singleOrNull { !it.isDead }
if (singlePreviousNode is LoopConditionExitNode) {
val variable = variableStorage.getOrCreateVariable(singlePreviousNode.fir)
exitNode.flow = logicSystem.approveStatementsInsideFlow(
exitNode.flow,
variable eq false,
shouldForkFlow = false,
shouldRemoveSynthetics = true
)
}
}
fun enterWhileLoop(loop: FirLoop) { fun enterWhileLoop(loop: FirLoop) {
val (loopEnterNode, loopConditionEnterNode) = graphBuilder.enterWhileLoop(loop) val (loopEnterNode, loopConditionEnterNode) = graphBuilder.enterWhileLoop(loop)
loopEnterNode.mergeIncomingFlow() loopEnterNode.mergeIncomingFlow()
@@ -407,7 +420,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
loopBlockEnterNode.flow, loopBlockEnterNode.flow,
conditionVariable eq true, conditionVariable eq true,
shouldForkFlow = false, shouldForkFlow = false,
shouldRemoveSynthetics = true shouldRemoveSynthetics = false
) )
} }
} }
@@ -416,6 +429,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val (blockExitNode, exitNode) = graphBuilder.exitWhileLoop(loop) val (blockExitNode, exitNode) = graphBuilder.exitWhileLoop(loop)
blockExitNode.mergeIncomingFlow() blockExitNode.mergeIncomingFlow()
exitNode.mergeIncomingFlow() exitNode.mergeIncomingFlow()
exitCommonLoop(exitNode)
} }
// ----------------------------------- Do while Loop ----------------------------------- // ----------------------------------- Do while Loop -----------------------------------
@@ -436,6 +450,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val (loopConditionExitNode, loopExitNode) = graphBuilder.exitDoWhileLoop(loop) val (loopConditionExitNode, loopExitNode) = graphBuilder.exitDoWhileLoop(loop)
loopConditionExitNode.mergeIncomingFlow() loopConditionExitNode.mergeIncomingFlow()
loopExitNode.mergeIncomingFlow() loopExitNode.mergeIncomingFlow()
exitCommonLoop(loopExitNode)
} }
// ----------------------------------- Try-catch-finally ----------------------------------- // ----------------------------------- Try-catch-finally -----------------------------------
+3 -3
View File
@@ -38,7 +38,7 @@ class C {
break; break;
} }
} }
a.<!INAPPLICABLE_CANDIDATE!>compareTo<!>("2") a.compareTo("2")
} }
fun containsBreakWithLabel(a: String?) { fun containsBreakWithLabel(a: String?) {
@@ -52,7 +52,7 @@ class C {
loop@ while(a == null) { loop@ while(a == null) {
break@label break@label
} }
a.<!INAPPLICABLE_CANDIDATE!>compareTo<!>("2") a.compareTo("2")
} }
fun containsBreakToOuterLoop(a: String?, b: String?) { fun containsBreakToOuterLoop(a: String?, b: String?) {
@@ -60,7 +60,7 @@ class C {
while(a == null) { while(a == null) {
break@loop break@loop
} }
a.<!INAPPLICABLE_CANDIDATE!>compareTo<!>("2") a.compareTo("2")
} }
} }
+2 -2
View File
@@ -151,7 +151,7 @@ fun test() {
out2?.println(); out2?.println();
out2.<!INAPPLICABLE_CANDIDATE!>println<!>(); out2.<!INAPPLICABLE_CANDIDATE!>println<!>();
} }
out2.<!INAPPLICABLE_CANDIDATE!>println<!>() out2.println()
} }
@@ -228,7 +228,7 @@ fun f6(s : String?) {
do { do {
s?.get(0) s?.get(0)
} while (s == null) } while (s == null)
s.<!INAPPLICABLE_CANDIDATE!>get<!>(0) s.get(0)
} }
fun f7(s : String?, t : String?) { fun f7(s : String?, t : String?) {
@@ -127,12 +127,12 @@ fun f13(a : A?) {
fun f14(a : A?) { fun f14(a : A?) {
while (!(a is B)) { while (!(a is B)) {
} }
a.<!UNRESOLVED_REFERENCE!>bar<!>() a.bar()
} }
fun f15(a : A?) { fun f15(a : A?) {
do { do {
} while (!(a is B)) } while (!(a is B))
a.<!UNRESOLVED_REFERENCE!>bar<!>() a.bar()
} }
fun getStringLength(obj : Any) : Char? { fun getStringLength(obj : Any) : Char? {
@@ -1,5 +1,5 @@
fun foo(s: String?): Int { fun foo(s: String?): Int {
do { do {
} while (s==null) } while (s==null)
return s.<!INAPPLICABLE_CANDIDATE!>length<!> return s.length
} }
@@ -7,7 +7,7 @@ public fun foo(p: String?, r: String?): Int {
} while (r == null) } while (r == null)
} while (!x()) } while (!x())
// Auto cast possible // Auto cast possible
r.<!INAPPLICABLE_CANDIDATE!>length<!> r.length
// Auto cast possible // Auto cast possible
return p.length return p.length
} }
@@ -8,7 +8,7 @@ public fun foo(p: String?, r: String?): Int {
} while (r == null) } while (r == null)
} while (!x()) } while (!x())
// Auto cast NOT possible due to long continue // Auto cast NOT possible due to long continue
r.<!INAPPLICABLE_CANDIDATE!>length<!> r.length
// Auto cast possible // Auto cast possible
return p.length return p.length
} }
@@ -11,7 +11,7 @@ public fun foo(p: String?, r: String?, q: String?): Int {
if (!x()) break if (!x()) break
} }
// Smart cast is possible everywhere // Smart cast is possible everywhere
r.<!INAPPLICABLE_CANDIDATE!>length<!> r.length
q.length q.length
return p.length return p.length
} }
@@ -9,7 +9,7 @@ public fun foo(p: String?, r: String?, q: String?): Int {
if (!x()) break if (!x()) break
} }
// Smart cast is possible everywhere // Smart cast is possible everywhere
r.<!INAPPLICABLE_CANDIDATE!>length<!> r.length
q.length q.length
return p.length return p.length
} }
@@ -12,7 +12,7 @@ public fun foo(p: String?, r: String?, q: String?): Int {
if (!x()) break if (!x()) break
} }
// Smart cast is possible everywhere // Smart cast is possible everywhere
r.<!INAPPLICABLE_CANDIDATE!>length<!> r.length
q.length q.length
return p.length return p.length
} }
@@ -14,6 +14,6 @@ public fun foo(p: String?, r: String?, q: String?): Int {
// Smart cast is possible only for q // Smart cast is possible only for q
q.length q.length
// But not possible for the others // But not possible for the others
r.<!INAPPLICABLE_CANDIDATE!>length<!> r.length
return p.length return p.length
} }
@@ -1,5 +1,5 @@
fun foo(s: String?): Int { fun foo(s: String?): Int {
while (s==null) { while (s==null) {
} }
return s.<!INAPPLICABLE_CANDIDATE!>length<!> return s.length
} }
@@ -5,5 +5,5 @@ fun main() {
if (i == 10) result = "non null" if (i == 10) result = "non null"
else i++ else i++
} }
result.<!INAPPLICABLE_CANDIDATE!>length<!> result.length
} }
@@ -11,5 +11,5 @@ public fun foo(xx: Any): Int {
// y!! in both branches // y!! in both branches
y.length y.length
} while (!(x is String)) } while (!(x is String))
return x.<!UNRESOLVED_REFERENCE!>length<!> return x.length
} }
@@ -9,7 +9,7 @@ public fun foo(pp: String?, rr: String?): Int {
} while (r == null) } while (r == null)
} while (!x()) } while (!x())
// Auto cast possible // Auto cast possible
r.<!INAPPLICABLE_CANDIDATE!>length<!> r.length
// Auto cast possible // Auto cast possible
return p.length return p.length
} }