From ea3a65d0b8f96fd4742bfb5ad832f96b6292781e Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 1 Dec 2015 20:53:39 +0300 Subject: [PATCH] Additional tests for KT-10243 --- .../kotlin/cfg/pseudocode/PseudocodeImpl.java | 1 + .../cfg-variables/bugs/kt10243.instructions | 96 +++++++++++++++++++ .../testData/cfg-variables/bugs/kt10243.kt | 11 +++ .../cfg-variables/bugs/kt10243.values | 34 +++++++ .../localFunctionInFinally.instructions | 78 +++++++++++++++ .../localFunctionInFinally.kt | 10 ++ .../localFunctionInFinally.values | 30 ++++++ .../diagnostics/tests/regressions/kt10243a.kt | 11 +++ .../tests/regressions/kt10243a.txt | 4 + .../kotlin/cfg/AbstractPseudocodeTest.java | 8 +- .../kotlin/cfg/ControlFlowTestGenerated.java | 6 ++ .../kotlin/cfg/DataFlowTestGenerated.java | 6 ++ .../kotlin/cfg/PseudoValueTestGenerated.java | 12 +++ .../checkers/DiagnosticsTestGenerated.java | 6 ++ 14 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/cfg-variables/bugs/kt10243.instructions create mode 100644 compiler/testData/cfg-variables/bugs/kt10243.kt create mode 100644 compiler/testData/cfg-variables/bugs/kt10243.values create mode 100644 compiler/testData/cfg/controlStructures/localFunctionInFinally.instructions create mode 100644 compiler/testData/cfg/controlStructures/localFunctionInFinally.kt create mode 100644 compiler/testData/cfg/controlStructures/localFunctionInFinally.values create mode 100644 compiler/testData/diagnostics/tests/regressions/kt10243a.kt create mode 100644 compiler/testData/diagnostics/tests/regressions/kt10243a.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeImpl.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeImpl.java index 91aa44a7055..24bada89db6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeImpl.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeImpl.java @@ -465,6 +465,7 @@ public class PseudocodeImpl implements Pseudocode { return result; } + // TODO: extract common part from repeatWhole and repeatPart private void repeatWhole(PseudocodeImpl originalPseudocode) { Map originalToCopy = Maps.newLinkedHashMap(); Multimap originalLabelsForInstruction = HashMultimap.create(); diff --git a/compiler/testData/cfg-variables/bugs/kt10243.instructions b/compiler/testData/cfg-variables/bugs/kt10243.instructions new file mode 100644 index 00000000000..fd17f37087d --- /dev/null +++ b/compiler/testData/cfg-variables/bugs/kt10243.instructions @@ -0,0 +1,96 @@ +== x == +var x: Int +--------------------- +L0: + 1 INIT: in: {} out: {} + v(var x: Int) INIT: in: {} out: {x=D} +L1: + INIT: in: {x=D} out: {x=D} +error: + INIT: in: {} out: {} +sink: + INIT: in: {x=D} out: {x=D} USE: in: {} out: {} +===================== +== foo == +fun foo(f: Boolean) { + try { + if (f) { + x = 0 + } + } + finally { + fun bar() {} + } +} +--------------------- +L0: + 1 INIT: in: {} out: {} + v(f: Boolean) INIT: in: {} out: {f=D} + magic[FAKE_INITIALIZER](f: Boolean) -> INIT: in: {f=D} out: {f=D} + w(f|) INIT: in: {f=D} out: {f=ID} + 2 mark({ try { if (f) { x = 0 } } finally { fun bar() {} } }) INIT: in: {f=ID} out: {f=ID} + 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) -> USE: in: {x=ONLY_WRITTEN_NEVER_READ} out: {f=READ, x=ONLY_WRITTEN_NEVER_READ} + jf(L3|) + 4 mark({ x = 0 }) + r(0) -> USE: in: {x=ONLY_WRITTEN_NEVER_READ} out: {x=ONLY_WRITTEN_NEVER_READ} + w(x|) 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 }|!) -> INIT: in: {f=ID, x=I} out: {f=ID, x=I} + 2 jmp(L5) +L2 [onExceptionToFinallyBlock]: +L6 [start finally]: + 3 mark({ fun bar() {} }) INIT: in: {f=ID} out: {f=ID} + jmp?(L7) + d(fun bar() {}) +L7 [after local declaration]: +L10 [finish finally]: + 2 jmp(error) +L5 [skipFinallyToErrorBlock]: +L11 [copy of L2, onExceptionToFinallyBlock]: + 3 mark({ fun bar() {} }) INIT: in: {f=ID, x=I} out: {f=ID, x=I} + jmp?(L12) + d(fun bar() {}) +L12 [copy of L7, after local declaration]: + 2 merge(try { if (f) { x = 0 } } finally { fun bar() {} }|) -> +L1: + 1 +error: + INIT: in: {f=ID} out: {f=ID} +sink: + INIT: in: {f=ID, x=I} out: {f=ID, x=I} USE: in: {} out: {} +===================== +== bar == +fun bar() {} +--------------------- +L8: + 4 INIT: in: {f=ID} out: {f=ID} + 5 mark({}) + read (Unit) +L9: + 4 +error: + INIT: in: {} out: {} +sink: + INIT: in: {f=ID} out: {f=ID} USE: in: {} out: {} +===================== +== bar == +fun bar() {} +--------------------- +L2 [copy of L8, null]: + 4 INIT: in: {f=ID, x=I} out: {f=ID, x=I} + 5 mark({}) + read (Unit) +L3 [copy of L9, null]: + 4 +L0 [copy of error, null]: + INIT: in: {} out: {} +L1 [copy of sink, null]: + INIT: in: {f=ID, x=I} out: {f=ID, x=I} USE: in: {} out: {} +===================== diff --git a/compiler/testData/cfg-variables/bugs/kt10243.kt b/compiler/testData/cfg-variables/bugs/kt10243.kt new file mode 100644 index 00000000000..e710a2b9cf8 --- /dev/null +++ b/compiler/testData/cfg-variables/bugs/kt10243.kt @@ -0,0 +1,11 @@ +var x: Int +fun foo(f: Boolean) { + try { + if (f) { + x = 0 + } + } + finally { + fun bar() {} + } +} \ No newline at end of file diff --git a/compiler/testData/cfg-variables/bugs/kt10243.values b/compiler/testData/cfg-variables/bugs/kt10243.values new file mode 100644 index 00000000000..d0e1a059bc8 --- /dev/null +++ b/compiler/testData/cfg-variables/bugs/kt10243.values @@ -0,0 +1,34 @@ +== x == +var x: Int +--------------------- +===================== +== foo == +fun foo(f: Boolean) { + try { + if (f) { + x = 0 + } + } + finally { + fun bar() {} + } +} +--------------------- + : Boolean NEW: magic[FAKE_INITIALIZER](f: Boolean) -> +f : Boolean NEW: r(f) -> +0 : Int NEW: r(0) -> +x = 0 !: * +{ x = 0 } !: * COPY +if (f) { x = 0 } : * NEW: merge(if (f) { x = 0 }|!) -> +{ if (f) { x = 0 } } : * COPY +try { if (f) { x = 0 } } finally { fun bar() {} } : * NEW: merge(try { if (f) { x = 0 } } finally { fun bar() {} }|) -> +{ try { if (f) { x = 0 } } finally { fun bar() {} } } : * COPY +===================== +== bar == +fun bar() {} +--------------------- +===================== +== bar == +fun bar() {} +--------------------- +===================== diff --git a/compiler/testData/cfg/controlStructures/localFunctionInFinally.instructions b/compiler/testData/cfg/controlStructures/localFunctionInFinally.instructions new file mode 100644 index 00000000000..7a60ed97322 --- /dev/null +++ b/compiler/testData/cfg/controlStructures/localFunctionInFinally.instructions @@ -0,0 +1,78 @@ +== foo == +fun foo(): Int { + var i = 0 + try { + i = 1 + } + finally { + fun bar() {} + return i + } +} +--------------------- +L0: + 1 + 2 mark({ var i = 0 try { i = 1 } finally { fun bar() {} return i } }) + v(var i = 0) + r(0) -> + w(i|) + mark(try { i = 1 } finally { fun bar() {} return i }) + jmp?(L2) NEXT:[mark({ fun bar() {} return i }), mark({ i = 1 })] + 3 mark({ i = 1 }) + r(1) -> + w(i|) + 2 jmp(L3) NEXT:[mark({ fun bar() {} return i })] +L2 [onExceptionToFinallyBlock]: +L4 [start finally]: + 3 mark({ fun bar() {} return i }) PREV:[jmp?(L2)] + jmp?(L5) NEXT:[r(i) -> , d(fun bar() {})] + d(fun bar() {}) NEXT:[] +L5 [after local declaration]: + r(i) -> PREV:[jmp?(L5)] + ret(*|) L1 NEXT:[] +L8 [finish finally]: +- 2 jmp(error) NEXT:[] PREV:[] +L3 [skipFinallyToErrorBlock]: +L9 [copy of L2, onExceptionToFinallyBlock]: + 3 mark({ fun bar() {} return i }) PREV:[jmp(L3)] + jmp?(L10) NEXT:[r(i) -> , d(fun bar() {})] + d(fun bar() {}) NEXT:[] +L10 [copy of L5, after local declaration]: + r(i) -> PREV:[jmp?(L10)] + ret(*|) L1 NEXT:[] +- 2 merge(try { i = 1 } finally { fun bar() {} return i }|!) -> PREV:[] +L1: + 1 NEXT:[] PREV:[ret(*|) L1, ret(*|) L1] +error: + PREV:[] +sink: + PREV:[, , d(fun bar() {}), d(fun bar() {})] +===================== +== bar == +fun bar() {} +--------------------- +L6: + 4 + 5 mark({}) + read (Unit) +L7: + 4 NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== bar == +fun bar() {} +--------------------- +L2 [copy of L6, null]: + 4 + 5 mark({}) + read (Unit) +L3 [copy of L7, null]: + 4 NEXT:[] +L0 [copy of error, null]: + PREV:[] +L1 [copy of sink, null]: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/controlStructures/localFunctionInFinally.kt b/compiler/testData/cfg/controlStructures/localFunctionInFinally.kt new file mode 100644 index 00000000000..a4e04f39f19 --- /dev/null +++ b/compiler/testData/cfg/controlStructures/localFunctionInFinally.kt @@ -0,0 +1,10 @@ +fun foo(): Int { + var i = 0 + try { + i = 1 + } + finally { + fun bar() {} + return i + } +} \ No newline at end of file diff --git a/compiler/testData/cfg/controlStructures/localFunctionInFinally.values b/compiler/testData/cfg/controlStructures/localFunctionInFinally.values new file mode 100644 index 00000000000..b518b46496c --- /dev/null +++ b/compiler/testData/cfg/controlStructures/localFunctionInFinally.values @@ -0,0 +1,30 @@ +== foo == +fun foo(): Int { + var i = 0 + try { + i = 1 + } + finally { + fun bar() {} + return i + } +} +--------------------- +0 : Int NEW: r(0) -> +1 : Int NEW: r(1) -> +i = 1 !: * +{ i = 1 } !: * COPY +i : Int NEW: r(i) -> +return i !: * +{ fun bar() {} return i } !: * COPY +try { i = 1 } finally { fun bar() {} return i } : * NEW: merge(try { i = 1 } finally { fun bar() {} return i }|!) -> +{ var i = 0 try { i = 1 } finally { fun bar() {} return i } } : * COPY +===================== +== bar == +fun bar() {} +--------------------- +===================== +== bar == +fun bar() {} +--------------------- +===================== diff --git a/compiler/testData/diagnostics/tests/regressions/kt10243a.kt b/compiler/testData/diagnostics/tests/regressions/kt10243a.kt new file mode 100644 index 00000000000..0cab799bdb5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/regressions/kt10243a.kt @@ -0,0 +1,11 @@ +var x: Int +fun foo(f: Boolean) { + try { + if (f) { + x = 0 + } + } + finally { + fun bar() {} + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/kt10243a.txt b/compiler/testData/diagnostics/tests/regressions/kt10243a.txt new file mode 100644 index 00000000000..cffbfdc289b --- /dev/null +++ b/compiler/testData/diagnostics/tests/regressions/kt10243a.txt @@ -0,0 +1,4 @@ +package + +public var x: kotlin.Int +public fun foo(/*0*/ f: kotlin.Boolean): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/cfg/AbstractPseudocodeTest.java b/compiler/tests/org/jetbrains/kotlin/cfg/AbstractPseudocodeTest.java index 68462045b3e..e159d1bb0a6 100644 --- a/compiler/tests/org/jetbrains/kotlin/cfg/AbstractPseudocodeTest.java +++ b/compiler/tests/org/jetbrains/kotlin/cfg/AbstractPseudocodeTest.java @@ -16,6 +16,8 @@ package org.jetbrains.kotlin.cfg; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.SetMultimap; import com.google.common.collect.Sets; import com.intellij.openapi.util.text.StringUtil; import kotlin.jvm.functions.Function3; @@ -53,7 +55,7 @@ public abstract class AbstractPseudocodeTest extends KotlinTestWithEnvironment { File file = new File(fileName); KtFile jetFile = KotlinTestUtils.loadJetFile(getProject(), file); - Map data = new LinkedHashMap(); + SetMultimap data = LinkedHashMultimap.create(); AnalysisResult analysisResult = KotlinTestUtils.analyzeFile(jetFile, getEnvironment()); List declarations = jetFile.getDeclarations(); BindingContext bindingContext = analysisResult.getBindingContext(); @@ -83,7 +85,7 @@ public abstract class AbstractPseudocodeTest extends KotlinTestWithEnvironment { } } - private static void addDeclaration(Map data, BindingContext bindingContext, KtDeclaration declaration) { + private static void addDeclaration(SetMultimap data, BindingContext bindingContext, KtDeclaration declaration) { Pseudocode pseudocode = PseudocodeUtil.generatePseudocode(declaration, bindingContext); data.put(declaration, pseudocode); for (LocalFunctionDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) { @@ -92,7 +94,7 @@ public abstract class AbstractPseudocodeTest extends KotlinTestWithEnvironment { } } - private void processCFData(File file, Map data, BindingContext bindingContext) throws IOException { + private void processCFData(File file, SetMultimap data, BindingContext bindingContext) throws IOException { Collection pseudocodes = data.values(); StringBuilder instructionDump = new StringBuilder(); diff --git a/compiler/tests/org/jetbrains/kotlin/cfg/ControlFlowTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cfg/ControlFlowTestGenerated.java index d5b16b9b813..d8fddda8dbb 100644 --- a/compiler/tests/org/jetbrains/kotlin/cfg/ControlFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cfg/ControlFlowTestGenerated.java @@ -214,6 +214,12 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest { doTest(fileName); } + @TestMetadata("localFunctionInFinally.kt") + public void testLocalFunctionInFinally() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/controlStructures/localFunctionInFinally.kt"); + doTest(fileName); + } + @TestMetadata("OnlyWhileInFunctionBody.kt") public void testOnlyWhileInFunctionBody() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/controlStructures/OnlyWhileInFunctionBody.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/cfg/DataFlowTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cfg/DataFlowTestGenerated.java index c7fe10fd59f..61591e740c5 100644 --- a/compiler/tests/org/jetbrains/kotlin/cfg/DataFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cfg/DataFlowTestGenerated.java @@ -88,6 +88,12 @@ public class DataFlowTestGenerated extends AbstractDataFlowTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/cfg-variables/bugs"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("kt10243.kt") + public void testKt10243() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg-variables/bugs/kt10243.kt"); + doTest(fileName); + } + @TestMetadata("referenceToPropertyInitializer.kt") public void testReferenceToPropertyInitializer() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/cfg/PseudoValueTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cfg/PseudoValueTestGenerated.java index 238df968b82..c0a1969335d 100644 --- a/compiler/tests/org/jetbrains/kotlin/cfg/PseudoValueTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cfg/PseudoValueTestGenerated.java @@ -216,6 +216,12 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest { doTest(fileName); } + @TestMetadata("localFunctionInFinally.kt") + public void testLocalFunctionInFinally() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/controlStructures/localFunctionInFinally.kt"); + doTest(fileName); + } + @TestMetadata("OnlyWhileInFunctionBody.kt") public void testOnlyWhileInFunctionBody() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/controlStructures/OnlyWhileInFunctionBody.kt"); @@ -810,6 +816,12 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/cfg-variables/bugs"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("kt10243.kt") + public void testKt10243() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg-variables/bugs/kt10243.kt"); + doTest(fileName); + } + @TestMetadata("referenceToPropertyInitializer.kt") public void testReferenceToPropertyInitializer() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index f0aec570e1b..3f1e36c6578 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -12558,6 +12558,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("kt10243a.kt") + public void testKt10243a() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/regressions/kt10243a.kt"); + doTest(fileName); + } + @TestMetadata("kt127.kt") public void testKt127() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/regressions/kt127.kt");