CFA merge for definition / initialization : more accurate handling of unknown variables #KT-13969 Fixed

(cherry picked from commit 4a96589)
This commit is contained in:
Mikhail Glukhikh
2016-09-26 12:51:24 +03:00
committed by Mikhail Glukhikh
parent 797f7ab28e
commit 436b0ec873
28 changed files with 167 additions and 91 deletions
@@ -63,7 +63,6 @@ fun <I : ControlFlowInfo<*>> Pseudocode.collectData(
initialInfo: I
): Map<Instruction, Edges<I>> {
val edgesMap = LinkedHashMap<Instruction, Edges<I>>()
initializeEdgesMap(edgesMap, initialInfo)
edgesMap.put(getStartInstruction(traversalOrder), Edges(initialInfo, initialInfo))
val changed = BooleanArray(1)
@@ -77,20 +76,6 @@ fun <I : ControlFlowInfo<*>> Pseudocode.collectData(
return edgesMap
}
private fun <I> Pseudocode.initializeEdgesMap(
edgesMap: MutableMap<Instruction, Edges<I>>,
initialInfo: I
) {
val instructions = instructions
val initialEdge = Edges(initialInfo, initialInfo)
for (instruction in instructions) {
edgesMap.put(instruction, initialEdge)
if (instruction is LocalFunctionDeclarationInstruction) {
instruction.body.initializeEdgesMap(edgesMap, initialInfo)
}
}
}
private fun <I : ControlFlowInfo<*>> Pseudocode.collectDataFromSubgraph(
traversalOrder: TraversalOrder,
mergeDataWithLocalDeclarations: Boolean,
@@ -221,12 +221,10 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
var initState: InitState? = null
var isDeclared = true
for (edgeData in incomingEdgesData) {
val varControlFlowState = edgeData[variable]
if (varControlFlowState != null) {
initState = initState?.merge(varControlFlowState.initState) ?: varControlFlowState.initState
if (!varControlFlowState.isDeclared) {
isDeclared = false
}
val varControlFlowState = edgeData[variable] ?: VariableControlFlowState.create(isInitialized = false)
initState = initState?.merge(varControlFlowState.initState) ?: varControlFlowState.initState
if (!varControlFlowState.isDeclared) {
isDeclared = false
}
}
if (initState == null) {
@@ -22,7 +22,7 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {EAST=ID, NORTH=ID, SOUTH=ID, WEST=ID} out: {EAST=ID, NORTH=ID, SOUTH=ID, WEST=ID} USE: in: {} out: {}
<SINK> INIT: in: {EAST=I?, NORTH=I?, SOUTH=I?, WEST=I?} out: {EAST=I?, NORTH=I?, SOUTH=I?, WEST=I?} USE: in: {} out: {}
=====================
== foo ==
fun foo(dir: Direction): Int {
@@ -99,5 +99,5 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {dir=ID} out: {dir=ID} USE: in: {} out: {}
<SINK> INIT: in: {dir=I?} out: {dir=I?} USE: in: {} out: {}
=====================
@@ -52,5 +52,5 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {a=ID} out: {a=ID} USE: in: {} out: {}
<SINK> INIT: in: {a=I?} out: {a=I?} USE: in: {} out: {}
=====================
@@ -18,5 +18,5 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {}
<SINK> INIT: in: {x=I?} out: {x=I?} USE: in: {} out: {}
=====================
@@ -16,9 +16,9 @@ L0:
v(val f = { x: Int -> val y = x + a use(a) }) INIT: in: {a=ID} out: {a=ID, f=D}
mark({ x: Int -> val y = x + a use(a) }) INIT: in: {a=ID, f=D} out: {a=ID, f=D}
jmp?(L2)
d({ x: Int -> val y = x + a use(a) }) USE: in: {a=READ} out: {a=READ}
d({ x: Int -> val y = x + a use(a) }) INIT: in: {a=I?, f=-} out: {a=I?, f=-} USE: in: {a=READ} out: {a=READ}
L2 [after local declaration]:
r({ x: Int -> val y = x + a use(a) }) -> <v1>
r({ x: Int -> val y = x + a use(a) }) -> <v1> INIT: in: {a=ID, f=D} out: {a=ID, f=D}
w(f|<v1>) INIT: in: {a=ID, f=D} out: {a=ID, f=ID}
L1:
1 <END> INIT: in: {} out: {}
@@ -54,7 +54,7 @@ L4:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {a=ID, f=D, x=ID} out: {a=ID, f=D, x=ID} USE: in: {} out: {}
<SINK> INIT: in: {a=I?, f=-, x=I?} out: {a=I?, f=-, x=I?} USE: in: {} out: {}
=====================
== use ==
fun use(vararg a: Any?) = a
@@ -71,5 +71,5 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {a=ID} out: {a=ID} USE: in: {} out: {}
<SINK> INIT: in: {a=I?} out: {a=I?} USE: in: {} out: {}
=====================
@@ -15,7 +15,7 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {f=ID} out: {f=ID} USE: in: {} out: {}
<SINK> INIT: in: {f=I?} out: {f=I?} USE: in: {} out: {}
=====================
== foo ==
fun foo() {
@@ -29,9 +29,9 @@ L0:
v(var v: Any) INIT: in: {} out: {v=D}
mark({ v.hashCode() }) INIT: in: {v=D} out: {v=D}
jmp?(L2)
d({ v.hashCode() }) USE: in: {v=READ} out: {v=READ}
d({ v.hashCode() }) INIT: in: {v=-} out: {v=-} USE: in: {v=READ} out: {v=READ}
L2 [after local declaration]:
r({ v.hashCode() }) -> <v0>
r({ v.hashCode() }) -> <v0> INIT: in: {v=D} out: {v=D}
mark(bar { v.hashCode() })
call(bar { v.hashCode() }, bar|<v0>) -> <v1>
L1:
@@ -56,5 +56,5 @@ L4:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {v=D} out: {v=D} USE: in: {} out: {}
<SINK> INIT: in: {v=-} out: {v=-} USE: in: {} out: {}
=====================
@@ -48,7 +48,7 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {foo=ID} out: {foo=ID} USE: in: {} out: {}
<SINK> INIT: in: {foo=I?} out: {foo=I?} USE: in: {} out: {}
=====================
== Foo ==
interface Foo {
@@ -63,5 +63,5 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {c=D} out: {c=D} USE: in: {} out: {}
<SINK> INIT: in: {c=-} out: {c=-} USE: in: {} out: {}
=====================
@@ -61,5 +61,5 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {a=ID} out: {a=ID} USE: in: {} out: {}
<SINK> INIT: in: {a=I?} out: {a=I?} USE: in: {} out: {}
=====================
@@ -0,0 +1,43 @@
== test ==
fun test(cond1: Boolean) {
do {
if (cond1) continue
val cond2 = false
} while (cond2)
}
---------------------
L0:
1 <START> INIT: in: {} out: {}
v(cond1: Boolean) INIT: in: {} out: {cond1=D}
magic[FAKE_INITIALIZER](cond1: Boolean) -> <v0> INIT: in: {cond1=D} out: {cond1=D}
w(cond1|<v0>) INIT: in: {cond1=D} out: {cond1=ID}
2 mark({ do { if (cond1) continue val cond2 = false } while (cond2) }) INIT: in: {cond1=ID} out: {cond1=ID} USE: in: {cond1=READ} out: {cond1=READ}
3 mark(do { if (cond1) continue val cond2 = false } while (cond2))
L2 [loop entry point]:
L4 [body entry point]:
mark({ if (cond1) continue val cond2 = false }) INIT: in: {cond1=ID, cond2=I?} out: {cond1=ID, cond2=I?}
mark(if (cond1) continue)
r(cond1) -> <v1>
jf(L7|<v1>)
jmp(L6) USE: in: {cond1=READ, cond2=READ} out: {cond1=READ, cond2=READ}
- jmp(L8)
L7 [else branch]:
read (Unit) INIT: in: {cond1=ID, cond2=I?} out: {cond1=ID, cond2=I?}
L8 ['if' expression result]:
merge(if (cond1) continue|!<v2>) -> <v3>
v(val cond2 = false) INIT: in: {cond1=ID, cond2=I?} out: {cond1=ID, cond2=ID}
r(false) -> <v4> INIT: in: {cond1=ID, cond2=ID} out: {cond1=ID, cond2=ID}
w(cond2|<v4>)
L5 [body exit point]:
L6 [condition entry point]:
r(cond2) -> <v5> INIT: in: {cond1=ID, cond2=I?} out: {cond1=ID, cond2=I?}
jt(L2|<v5>) USE: in: {cond1=READ, cond2=READ} out: {cond1=READ, cond2=READ}
L3 [loop exit point]:
read (Unit)
L1:
1 <END> INIT: in: {cond1=ID} out: {cond1=ID}
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {cond1=I?} out: {cond1=I?} USE: in: {} out: {}
=====================
@@ -0,0 +1,6 @@
fun test(cond1: Boolean) {
do {
if (cond1) continue
val cond2 = false
} while (cond2)
}
@@ -0,0 +1,17 @@
== test ==
fun test(cond1: Boolean) {
do {
if (cond1) continue
val cond2 = false
} while (cond2)
}
---------------------
<v0>: Boolean NEW: magic[FAKE_INITIALIZER](cond1: Boolean) -> <v0>
cond1 <v1>: Boolean NEW: r(cond1) -> <v1>
continue !<v2>: *
if (cond1) continue <v3>: * NEW: merge(if (cond1) continue|!<v2>) -> <v3>
false <v4>: Boolean NEW: r(false) -> <v4>
cond2 <v5>: Boolean NEW: r(cond2) -> <v5>
do { if (cond1) continue val cond2 = false } while (cond2) !<v6>: *
{ do { if (cond1) continue val cond2 = false } while (cond2) } !<v6>: * COPY
=====================
+15 -15
View File
@@ -9,7 +9,7 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {x=D} out: {x=D} USE: in: {} out: {}
<SINK> INIT: in: {x=-} out: {x=-} USE: in: {} out: {}
=====================
== foo ==
fun foo(f: Boolean) {
@@ -32,46 +32,46 @@ L0:
mark(try { if (f) { x = 0 } } finally { fun bar() {} })
jmp?(L2)
3 mark({ if (f) { x = 0 } })
mark(if (f) { x = 0 }) USE: in: {f=READ, x=ONLY_WRITTEN_NEVER_READ} out: {f=READ, x=ONLY_WRITTEN_NEVER_READ}
r(f) -> <v1> USE: in: {x=ONLY_WRITTEN_NEVER_READ} out: {f=READ, x=ONLY_WRITTEN_NEVER_READ}
mark(if (f) { x = 0 }) USE: in: {f=READ, x=ONLY_WRITTEN_NEVER_READ} out: {f=READ, x=ONLY_WRITTEN_NEVER_READ}
r(f) -> <v1> USE: in: {x=ONLY_WRITTEN_NEVER_READ} out: {f=READ, x=ONLY_WRITTEN_NEVER_READ}
jf(L3|<v1>)
4 mark({ x = 0 })
r(0) -> <v2> USE: in: {x=ONLY_WRITTEN_NEVER_READ} out: {x=ONLY_WRITTEN_NEVER_READ}
w(x|<v2>) INIT: in: {f=ID} out: {f=ID, x=I} USE: in: {} out: {x=ONLY_WRITTEN_NEVER_READ}
r(0) -> <v2> USE: in: {x=ONLY_WRITTEN_NEVER_READ} out: {x=ONLY_WRITTEN_NEVER_READ}
w(x|<v2>) INIT: in: {f=ID} out: {f=ID, x=I} USE: in: {} out: {x=ONLY_WRITTEN_NEVER_READ}
3 jmp(L4) INIT: in: {f=ID, x=I} out: {f=ID, x=I}
L3 [else branch]:
read (Unit) INIT: in: {f=ID} out: {f=ID}
L4 ['if' expression result]:
merge(if (f) { x = 0 }|!<v3>) -> <v4> INIT: in: {f=ID, x=I} out: {f=ID, x=I}
merge(if (f) { x = 0 }|!<v3>) -> <v4> INIT: in: {f=ID, x=I?} out: {f=ID, x=I?}
2 jmp?(L2)
jmp(L5)
L2 [onExceptionToFinallyBlock]:
L6 [start finally]:
3 mark({ fun bar() {} })
jmp?(L7)
d(fun bar() {})
d(fun bar() {}) INIT: in: {f=I?, x=I?} out: {f=I?, x=I?}
L7 [after local declaration]:
L10 [finish finally]:
2 jmp(error)
2 jmp(error) INIT: in: {f=ID, x=I?} out: {f=ID, x=I?}
L5 [skipFinallyToErrorBlock]:
L11 [copy of L2, onExceptionToFinallyBlock]:
3 mark({ fun bar() {} })
jmp?(L12)
d(fun bar() {})
d(fun bar() {}) INIT: in: {f=I?, x=I?} out: {f=I?, x=I?}
L12 [copy of L7, after local declaration]:
2 merge(try { if (f) { x = 0 } } finally { fun bar() {} }|<v4>) -> <v5>
2 merge(try { if (f) { x = 0 } } finally { fun bar() {} }|<v4>) -> <v5> INIT: in: {f=ID, x=I?} out: {f=ID, x=I?}
L1:
1 <END>
error:
<ERROR>
sink:
<SINK> USE: in: {} out: {}
<SINK> INIT: in: {f=I?, x=I?} out: {f=I?, x=I?} USE: in: {} out: {}
=====================
== bar ==
fun bar() {}
---------------------
L8:
4 <START> INIT: in: {f=ID, x=I} out: {f=ID, x=I}
4 <START> INIT: in: {f=ID, x=I?} out: {f=ID, x=I?}
5 mark({})
read (Unit)
L9:
@@ -79,13 +79,13 @@ L9:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {f=ID, x=I} out: {f=ID, x=I} USE: in: {} out: {}
<SINK> INIT: in: {f=I?, x=I?} out: {f=I?, x=I?} USE: in: {} out: {}
=====================
== bar ==
fun bar() {}
---------------------
L2 [copy of L8, null]:
4 <START> INIT: in: {f=ID, x=I} out: {f=ID, x=I}
4 <START> INIT: in: {f=ID, x=I?} out: {f=ID, x=I?}
5 mark({})
read (Unit)
L3 [copy of L9, null]:
@@ -93,5 +93,5 @@ L3 [copy of L9, null]:
L0 [copy of error, null]:
<ERROR> INIT: in: {} out: {}
L1 [copy of sink, null]:
<SINK> INIT: in: {f=ID, x=I} out: {f=ID, x=I} USE: in: {} out: {}
<SINK> INIT: in: {f=I?, x=I?} out: {f=I?, x=I?} USE: in: {} out: {}
=====================
@@ -10,16 +10,16 @@ L0:
v(val sum: (Int)->Int = { x: Int -> sum(x - 1) + x }) INIT: in: {} out: {sum=D}
mark({ x: Int -> sum(x - 1) + x }) INIT: in: {sum=D} out: {sum=D}
jmp?(L2)
d({ x: Int -> sum(x - 1) + x }) USE: in: {sum=READ} out: {sum=READ}
d({ x: Int -> sum(x - 1) + x }) INIT: in: {sum=-} out: {sum=-} USE: in: {sum=READ} out: {sum=READ}
L2 [after local declaration]:
r({ x: Int -> sum(x - 1) + x }) -> <v0>
r({ x: Int -> sum(x - 1) + x }) -> <v0> INIT: in: {sum=D} out: {sum=D}
w(sum|<v0>) INIT: in: {sum=D} out: {sum=ID}
L1:
<END> INIT: in: {sum=ID} out: {sum=ID}
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {sum=I?D} out: {sum=I?D} USE: in: {} out: {}
<SINK> INIT: in: {sum=I?} out: {sum=I?} USE: in: {} out: {}
=====================
== anonymous_0 ==
{ x: Int ->
@@ -49,7 +49,7 @@ L4:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {sum=D, x=ID} out: {sum=D, x=ID} USE: in: {} out: {}
<SINK> INIT: in: {sum=-, x=I?} out: {sum=-, x=I?} USE: in: {} out: {}
=====================
== A ==
open class A(val a: A)
@@ -64,7 +64,7 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {a=ID} out: {a=ID} USE: in: {} out: {}
<SINK> INIT: in: {a=I?} out: {a=I?} USE: in: {} out: {}
=====================
== TestObjectLiteral ==
class TestObjectLiteral {
@@ -92,16 +92,16 @@ L0:
r(obj|<v3>) -> <v4>
w(x|<v4>) INIT: in: {obj=D, x=D} out: {obj=D, x=ID}
1 jmp?(L2) INIT: in: {obj=D} out: {obj=D}
d(fun foo() { val y = obj }) USE: in: {obj=READ} out: {obj=READ}
d(fun foo() { val y = obj }) INIT: in: {obj=-} out: {obj=-} USE: in: {obj=READ} out: {obj=READ}
L2 [after local declaration]:
r(object: A(obj) { init { val x = obj } fun foo() { val y = obj } }) -> <v5>
r(object: A(obj) { init { val x = obj } fun foo() { val y = obj } }) -> <v5> INIT: in: {obj=D} out: {obj=D}
w(obj|<v5>) INIT: in: {obj=D} out: {obj=ID}
L1:
<END> INIT: in: {obj=ID} out: {obj=ID}
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {obj=I?D} out: {obj=I?D} USE: in: {} out: {}
<SINK> INIT: in: {obj=I?} out: {obj=I?} USE: in: {} out: {}
=====================
== foo ==
fun foo() {
@@ -120,7 +120,7 @@ L4:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {obj=D} out: {obj=D} USE: in: {} out: {}
<SINK> INIT: in: {obj=-} out: {obj=-} USE: in: {} out: {}
=====================
== TestOther ==
class TestOther {
@@ -141,5 +141,5 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {}
<SINK> INIT: in: {x=I?} out: {x=I?} USE: in: {} out: {}
=====================
@@ -59,7 +59,7 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {numbers=ID} out: {numbers=ID} USE: in: {} out: {}
<SINK> INIT: in: {numbers=I?} out: {numbers=I?} USE: in: {} out: {}
=====================
== use ==
fun use(vararg a: Any?) = a
@@ -76,5 +76,5 @@ L1:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {a=ID} out: {a=ID} USE: in: {} out: {}
<SINK> INIT: in: {a=I?} out: {a=I?} USE: in: {} out: {}
=====================
@@ -15,9 +15,9 @@ L0:
3 mark(do { var a = 2 } while (a > 0))
L2 [loop entry point]:
L4 [body entry point]:
mark({ var a = 2 }) INIT: in: {a=ID} out: {a=ID}
v(var a = 2)
r(2) -> <v1>
mark({ var a = 2 }) INIT: in: {a=I?} out: {a=I?}
v(var a = 2) INIT: in: {a=I?} out: {a=ID}
r(2) -> <v1> INIT: in: {a=ID} out: {a=ID}
w(a|<v1>)
L5 [body exit point]:
L6 [condition entry point]:
@@ -19,9 +19,9 @@ L0:
v(val f = { x: Int -> val a = x + b }) INIT: in: {b=ID} out: {b=ID, f=D}
mark({ x: Int -> val a = x + b }) INIT: in: {b=ID, f=D} out: {b=ID, f=D}
jmp?(L2)
d({ x: Int -> val a = x + b }) USE: in: {b=READ} out: {b=READ}
d({ x: Int -> val a = x + b }) INIT: in: {b=I?, f=-} out: {b=I?, f=-} USE: in: {b=READ} out: {b=READ}
L2 [after local declaration]:
r({ x: Int -> val a = x + b }) -> <v2>
r({ x: Int -> val a = x + b }) -> <v2> INIT: in: {b=ID, f=D} out: {b=ID, f=D}
w(f|<v2>) INIT: in: {b=ID, f=D} out: {b=ID, f=ID}
mark("after") INIT: in: {b=ID, f=ID} out: {b=ID, f=ID}
r("after") -> <v3>
@@ -54,5 +54,5 @@ L4:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {b=ID, f=D, x=ID} out: {b=ID, f=D, x=ID} USE: in: {} out: {}
<SINK> INIT: in: {b=I?, f=-, x=I?} out: {b=I?, f=-, x=I?} USE: in: {} out: {}
=====================
@@ -27,7 +27,7 @@ L0:
r(x|<v2>) -> <v3>
w(a|<v3>) INIT: in: {a=D, x=ID} out: {a=ID, x=ID}
2 jmp?(L3) INIT: in: {x=ID} out: {x=ID}
d(fun foo() { val b = x }) USE: in: {x=READ} out: {x=READ}
d(fun foo() { val b = x }) INIT: in: {x=I?} out: {x=I?} USE: in: {x=READ} out: {x=READ}
L2 [after local class]:
L3 [after local declaration]:
mark("after")
@@ -56,5 +56,5 @@ L5:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {}
<SINK> INIT: in: {x=I?} out: {x=I?} USE: in: {} out: {}
=====================
@@ -17,9 +17,9 @@ L0:
r(1) -> <v1> INIT: in: {b=D} out: {b=D}
w(b|<v1>) INIT: in: {b=D} out: {b=ID}
jmp?(L2) INIT: in: {b=ID} out: {b=ID}
d(fun local(x: Int) { val a = x + b }) USE: in: {b=READ} out: {b=READ}
d(fun local(x: Int) { val a = x + b }) INIT: in: {b=I?} out: {b=I?} USE: in: {b=READ} out: {b=READ}
L2 [after local declaration]:
mark("after")
mark("after") INIT: in: {b=ID} out: {b=ID}
r("after") -> <v2>
L1:
1 <END> INIT: in: {} out: {}
@@ -50,5 +50,5 @@ L4:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {b=ID, x=ID} out: {b=ID, x=ID} USE: in: {} out: {}
<SINK> INIT: in: {b=I?, x=I?} out: {b=I?, x=I?} USE: in: {} out: {}
=====================
@@ -15,9 +15,9 @@ L0:
r(1) -> <v1> INIT: in: {b=D} out: {b=D}
w(b|<v1>) INIT: in: {b=D} out: {b=ID}
jmp?(L2) INIT: in: {b=ID} out: {b=ID}
d(fun local(x: Int) = x + b) USE: in: {b=READ} out: {b=READ}
d(fun local(x: Int) = x + b) INIT: in: {b=I?} out: {b=I?} USE: in: {b=READ} out: {b=READ}
L2 [after local declaration]:
mark("after")
mark("after") INIT: in: {b=ID} out: {b=ID}
r("after") -> <v2>
L1:
1 <END> INIT: in: {} out: {}
@@ -44,5 +44,5 @@ L4:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {b=ID, x=ID} out: {b=ID, x=ID} USE: in: {} out: {}
<SINK> INIT: in: {b=I?, x=I?} out: {b=I?, x=I?} USE: in: {} out: {}
=====================
@@ -24,9 +24,9 @@ L0:
r(1) -> <v1> INIT: in: {bar=D, x=D} out: {bar=D, x=D}
w(x|<v1>) INIT: in: {bar=D, x=D} out: {bar=D, x=ID}
2 jmp?(L2) INIT: in: {bar=D} out: {bar=D}
d(fun foo() { val a = 2 })
d(fun foo() { val a = 2 }) INIT: in: {bar=-} out: {bar=-}
L2 [after local declaration]:
r(object { init { val x = 1 } fun foo() { val a = 2 } }) -> <v2>
r(object { init { val x = 1 } fun foo() { val a = 2 } }) -> <v2> INIT: in: {bar=D} out: {bar=D}
w(bar|<v2>) INIT: in: {bar=D} out: {bar=ID}
mark("after") INIT: in: {bar=ID} out: {bar=ID}
r("after") -> <v3>
@@ -53,5 +53,5 @@ L4:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {bar=D} out: {bar=D} USE: in: {} out: {}
<SINK> INIT: in: {bar=-} out: {bar=-} USE: in: {} out: {}
=====================
@@ -16,11 +16,11 @@ L0:
2 mark({ class A { var a : Int get() { return field } set(v: Int) { field = v } } })
jmp?(L2)
v(var a : Int get() { return field } set(v: Int) { field = v }) INIT: in: {} out: {a=D}
jmp?(L3) INIT: in: {a=D} out: {a=D} USE: in: {field=ONLY_WRITTEN_NEVER_READ, field=READ} out: {field=ONLY_WRITTEN_NEVER_READ, field=READ}
d(get() { return field }) USE: in: {field=READ} out: {field=READ}
jmp?(L3) INIT: in: {a=D} out: {a=D} USE: in: {field=ONLY_WRITTEN_NEVER_READ, field=READ} out: {field=ONLY_WRITTEN_NEVER_READ, field=READ}
d(get() { return field }) INIT: in: {a=-} out: {a=-} USE: in: {field=READ} out: {field=READ}
L3 [after local declaration]:
jmp?(L6)
d(set(v: Int) { field = v }) INIT: in: {a=D, field=I} out: {a=D, field=I} USE: in: {field=ONLY_WRITTEN_NEVER_READ} out: {field=ONLY_WRITTEN_NEVER_READ}
jmp?(L6) INIT: in: {a=D} out: {a=D}
d(set(v: Int) { field = v }) INIT: in: {a=-, field=I?} out: {a=-, field=I?} USE: in: {field=ONLY_WRITTEN_NEVER_READ} out: {field=ONLY_WRITTEN_NEVER_READ}
L1:
L2 [after local class]:
L6 [after local declaration]:
@@ -28,7 +28,7 @@ L6 [after local declaration]:
error:
<ERROR>
sink:
<SINK> INIT: in: {field=I} out: {field=I} USE: in: {} out: {}
<SINK> INIT: in: {field=I?} out: {field=I?} USE: in: {} out: {}
=====================
== get_a ==
get() {
@@ -45,7 +45,7 @@ L5:
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {a=D} out: {a=D} USE: in: {} out: {}
<SINK> INIT: in: {a=-} out: {a=-} USE: in: {} out: {}
=====================
== set_a ==
set(v: Int) {
@@ -57,13 +57,13 @@ L7:
v(v: Int) INIT: in: {a=D} out: {a=D, v=D}
magic[FAKE_INITIALIZER](v: Int) -> <v0> INIT: in: {a=D, v=D} out: {a=D, v=D}
w(v|<v0>) INIT: in: {a=D, v=D} out: {a=D, v=ID}
4 mark({ field = v }) INIT: in: {a=D, v=ID} out: {a=D, v=ID} USE: in: {field=ONLY_WRITTEN_NEVER_READ, v=READ} out: {field=ONLY_WRITTEN_NEVER_READ, v=READ}
r(v) -> <v1> USE: in: {field=ONLY_WRITTEN_NEVER_READ} out: {field=ONLY_WRITTEN_NEVER_READ, v=READ}
w(field|<v1>) INIT: in: {a=D, v=ID} out: {a=D, field=I, v=ID} USE: in: {} out: {field=ONLY_WRITTEN_NEVER_READ}
4 mark({ field = v }) INIT: in: {a=D, v=ID} out: {a=D, v=ID} USE: in: {field=ONLY_WRITTEN_NEVER_READ, v=READ} out: {field=ONLY_WRITTEN_NEVER_READ, v=READ}
r(v) -> <v1> USE: in: {field=ONLY_WRITTEN_NEVER_READ} out: {field=ONLY_WRITTEN_NEVER_READ, v=READ}
w(field|<v1>) INIT: in: {a=D, v=ID} out: {a=D, field=I, v=ID} USE: in: {} out: {field=ONLY_WRITTEN_NEVER_READ}
L8:
3 <END> INIT: in: {a=D, field=I, v=ID} out: {a=D, field=I, v=ID}
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {a=D, field=I, v=ID} out: {a=D, field=I, v=ID} USE: in: {} out: {}
<SINK> INIT: in: {a=-, field=I?, v=I?} out: {a=-, field=I?, v=I?} USE: in: {} out: {}
=====================
@@ -0,0 +1,6 @@
fun test(cond1: Boolean) {
do {
if (cond1) continue
val cond2 = false
} while (<!UNINITIALIZED_VARIABLE!>cond2<!>) // cond2 may be not defined here
}
@@ -0,0 +1,3 @@
package
public fun test(/*0*/ cond1: kotlin.Boolean): kotlin.Unit
+1 -1
View File
@@ -5,7 +5,7 @@ fun foo() {
FOO,
BAR
}
val foo = A.FOO
val foo = A.<!UNINITIALIZED_ENUM_ENTRY!>FOO<!>
val b = object {
<!WRONG_MODIFIER_TARGET!>enum<!> class B {}
}
@@ -94,6 +94,12 @@ public class DataFlowTestGenerated extends AbstractDataFlowTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/cfg-variables/bugs"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("doWhileNotDefined.kt")
public void testDoWhileNotDefined() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg-variables/bugs/doWhileNotDefined.kt");
doTest(fileName);
}
@TestMetadata("initializationInLocalClass.kt")
public void testInitializationInLocalClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg-variables/bugs/initializationInLocalClass.kt");
@@ -852,6 +852,12 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/cfg-variables/bugs"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("doWhileNotDefined.kt")
public void testDoWhileNotDefined() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg-variables/bugs/doWhileNotDefined.kt");
doTest(fileName);
}
@TestMetadata("initializationInLocalClass.kt")
public void testInitializationInLocalClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg-variables/bugs/initializationInLocalClass.kt");
@@ -3330,6 +3330,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("doWhileNotDefined.kt")
public void testDoWhileNotDefined() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/doWhileNotDefined.kt");
doTest(fileName);
}
@TestMetadata("elvisNotProcessed.kt")
public void testElvisNotProcessed() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/elvisNotProcessed.kt");