Fix KNPE caused by optimizations in control-flow analysis

The problem is that when performing full analysis we do it in
a backward order while result for trivial vals is filled
in a forward one.

It turns out that reversedInstuctions might return a superset of
forward traversed instructions, e.g. in case of dead code in lambda.

At the same time result for trivial vals is constant
for any instruction, thus we can just return its constant value
and use it in the full analysis

 #KT-20895 Fixed
This commit is contained in:
Denis Zharkov
2017-11-14 11:44:20 +03:00
parent 2a0b937aac
commit 1f9d56439a
5 changed files with 40 additions and 14 deletions
@@ -294,8 +294,14 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
val variableUseStatusData: Map<Instruction, Edges<ReadOnlyUseControlFlowInfo>>
get() {
val resultForTrivialVals = computeUseInfoForTrivialVals()
if (rootVariables.nonTrivialVariables.isEmpty()) return resultForTrivialVals
val edgesForTrivialVals = computeUseInfoForTrivialVals()
if (rootVariables.nonTrivialVariables.isEmpty()) {
return hashMapOf<Instruction, Edges<ReadOnlyUseControlFlowInfo>>().apply {
pseudocode.traverse(TraversalOrder.FORWARD) { instruction ->
put(instruction, edgesForTrivialVals)
}
}
}
return pseudocodeVariableDataCollector.collectData(TraversalOrder.BACKWARD, UseControlFlowInfo()) { instruction: Instruction, incomingEdgesData: Collection<UseControlFlowInfo> ->
@@ -336,17 +342,16 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
Edges(enterResult, exitResult)
}
}.mapValues {
(instruction, edges) ->
val edgeForTrivialVals = resultForTrivialVals[instruction]!!
(_, edges) ->
Edges(
edgeForTrivialVals.incoming.replaceDelegate(edges.incoming),
edgeForTrivialVals.outgoing.replaceDelegate(edges.outgoing)
edgesForTrivialVals.incoming.replaceDelegate(edges.incoming),
edgesForTrivialVals.outgoing.replaceDelegate(edges.outgoing)
)
}
}
private fun computeUseInfoForTrivialVals(): Map<Instruction, Edges<ReadOnlyUseControlFlowInfoImpl>> {
private fun computeUseInfoForTrivialVals(): Edges<ReadOnlyUseControlFlowInfoImpl> {
val used = hashSetOf<VariableDescriptor>()
pseudocode.traverse(TraversalOrder.FORWARD) { instruction ->
@@ -358,13 +363,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
}
val constantUseInfo = ReadOnlyUseControlFlowInfoImpl(used, null)
val constantEdges = Edges(constantUseInfo, constantUseInfo)
val result = hashMapOf<Instruction, Edges<ReadOnlyUseControlFlowInfoImpl>>()
pseudocode.traverse(TraversalOrder.FORWARD) { instruction ->
result[instruction] = constantEdges
}
return result
return Edges(constantUseInfo, constantUseInfo)
}
private fun extractValWithTrivialInitializer(instruction: Instruction): VariableDescriptor? {
@@ -0,0 +1,11 @@
inline fun myRun(b: () -> Unit) = b()
fun foo() {
var <!UNUSED_VARIABLE!>a<!>: Int
return
<!UNREACHABLE_CODE!>myRun {
return
}<!>
}
@@ -0,0 +1,4 @@
package
public fun foo(): kotlin.Unit
public inline fun myRun(/*0*/ b: () -> kotlin.Unit): kotlin.Unit
@@ -4397,6 +4397,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt5200DeadCodeInLambdas.kt");
doTest(fileName);
}
@TestMetadata("returnInDeadLambda.kt")
public void testReturnInDeadLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/returnInDeadLambda.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn")
@@ -4397,6 +4397,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt5200DeadCodeInLambdas.kt");
doTest(fileName);
}
@TestMetadata("returnInDeadLambda.kt")
public void testReturnInDeadLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/returnInDeadLambda.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn")