diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ExtractableCodeDescriptor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ExtractableCodeDescriptor.kt index f339e24266c..852d6fefabd 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ExtractableCodeDescriptor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/ExtractableCodeDescriptor.kt @@ -132,7 +132,7 @@ trait OutputValue { class Jump( val elementsToReplace: List, - val elementToInsertAfterCall: JetElement, + val elementToInsertAfterCall: JetElement?, val conditional: Boolean ): OutputValue { override val originalExpressions: List get() = elementsToReplace diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractableAnalysisUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractableAnalysisUtil.kt index 092692052f7..df028d4ac3d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractableAnalysisUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractableAnalysisUtil.kt @@ -32,7 +32,6 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver import org.jetbrains.kotlin.cfg.pseudocode.* import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.cfg.Label import org.jetbrains.kotlin.idea.refactoring.JetNameValidatorImpl import org.jetbrains.kotlin.idea.codeInsight.DescriptorToDeclarationUtil import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport @@ -45,7 +44,7 @@ import com.intellij.util.containers.MultiMap import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.idea.refactoring.extractFunction.AnalysisResult.Status import org.jetbrains.kotlin.idea.refactoring.extractFunction.AnalysisResult.ErrorMessage -import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction +import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.* import org.jetbrains.kotlin.cfg.pseudocode.instructions.* import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.* import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.* @@ -152,9 +151,37 @@ private fun List.getResultTypeAndExpressions( return resultType to expressions } -private fun List.checkEquivalence(checkPsi: Boolean): Boolean { - if (mapTo(HashSet()) { it.targetLabel }.size > 1) return false - return !checkPsi || mapTo(HashSet()) { it.element.getText() }.size <= 1 +private fun getCommonNonTrivialSuccessorIfAny(instructions: List): Instruction? { + val singleSuccessorCheckingVisitor = object: InstructionVisitorWithResult() { + var target: Instruction? = null + + override fun visitInstructionWithNext(instruction: InstructionWithNext): Boolean { + return when (instruction) { + is LoadUnitValueInstruction, + is MergeInstruction, + is MarkInstruction -> { + instruction.next?.accept(this) ?: true + } + else -> visitInstruction(instruction) + } + } + + override fun visitJump(instruction: AbstractJumpInstruction): Boolean { + return when (instruction) { + is ConditionalJumpInstruction -> visitInstruction(instruction) + else -> instruction.resolvedTarget?.accept(this) ?: true + } + } + + override fun visitInstruction(instruction: Instruction): Boolean { + if (target != null && target != instruction) return false + target = instruction + return true + } + } + + if (instructions.flatMap { it.nextInstructions }.any { !it.accept(singleSuccessorCheckingVisitor) }) return null + return singleSuccessorCheckingVisitor.target ?: instructions.firstOrNull()?.owner?.getSinkInstruction() } private fun JetType.isMeaningful(): Boolean { @@ -295,7 +322,7 @@ private fun ExtractionData.analyzeControlFlow( return controlFlow.copy(outputValues = Collections.singletonList(Jump(listOf(element), element, true))) to null } - if (!valuedReturnExits.checkEquivalence(false)) return multipleExitsError + if (getCommonNonTrivialSuccessorIfAny(valuedReturnExits) == null) return multipleExitsError outputValues.add(ExpressionValue(true, valuedReturnExpressions, returnValueType)) } @@ -326,12 +353,14 @@ private fun ExtractionData.analyzeControlFlow( } if (jumpExits.isNotEmpty()) { - if (!jumpExits.checkEquivalence(true)) return multipleExitsError + val jumpTarget = getCommonNonTrivialSuccessorIfAny(jumpExits) + if (jumpTarget == null) return multipleExitsError + val singleExit = getCommonNonTrivialSuccessorIfAny(defaultExits) == jumpTarget + val conditional = !singleExit && defaultExits.isNotEmpty() val elements = jumpExits.map { it.element as JetExpression } - return controlFlow.copy( - outputValues = Collections.singletonList(Jump(elements, elements.first(), defaultExits.isNotEmpty())) - ) to null + val elementToInsertAfterCall = if (singleExit) null else elements.first() + return controlFlow.copy(outputValues = Collections.singletonList(Jump(elements, elementToInsertAfterCall, conditional))) to null } return controlFlow to null diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractorUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractorUtil.kt index ff4295b869e..c5f9330d0a9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractorUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/extractFunction/extractorUtil.kt @@ -287,7 +287,10 @@ private fun makeCall( ) is Jump -> { - if (outputValue.conditional) { + if (outputValue.elementToInsertAfterCall == null) { + Collections.singletonList(psiFactory.createExpression(callText)) + } + else if (outputValue.conditional) { Collections.singletonList( psiFactory.createExpression("if ($callText) ${outputValue.elementToInsertAfterCall.getText()}") ) diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakAndReturn.kt b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakAndReturn.kt new file mode 100644 index 00000000000..db1acfa1b62 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakAndReturn.kt @@ -0,0 +1,14 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo +// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + for (n in 1..b) { + if (a > 0) throw Exception("") + if (a + b > 0) break + println(a - b) + return + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakAndReturn.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakAndReturn.kt.after new file mode 100644 index 00000000000..88a824237f8 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakAndReturn.kt.after @@ -0,0 +1,19 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo +// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + for (n in 1..b) { + __dummyTestFun__(a, b) + break + } +} + +private fun __dummyTestFun__(a: Int, b: Int) { + if (a > 0) throw Exception("") + if (a + b > 0) return + println(a - b) + return +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakContinueAndDefault.kt b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakContinueAndDefault.kt new file mode 100644 index 00000000000..2f5f2f30615 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakContinueAndDefault.kt @@ -0,0 +1,15 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo +// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + @loop1 for (p in 1..b) { + @loop2 for (n in 1..b) { + if (a > 0) throw Exception("") + if (a + b > 0) break@loop2 + if (a - b > 0) continue@loop1 + } + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakContinueAndDefault.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakContinueAndDefault.kt.after new file mode 100644 index 00000000000..f49703f051f --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakContinueAndDefault.kt.after @@ -0,0 +1,20 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo +// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + @loop1 for (p in 1..b) { + @loop2 for (n in 1..b) { + if (b(a, b)) break@loop2 + } + } +} + +private fun b(a: Int, b: Int): Boolean { + if (a > 0) throw Exception("") + if (a + b > 0) return true + if (a - b > 0) return true + return false +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/continueAndReturn.kt b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/continueAndReturn.kt new file mode 100644 index 00000000000..bdee91b779e --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/continueAndReturn.kt @@ -0,0 +1,10 @@ +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + for (n in 1..b) { + if (a > 0) throw Exception("") + if (a + b > 0) continue + println(a - b) + return + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/continueAndReturn.kt.conflicts b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/continueAndReturn.kt.conflicts new file mode 100644 index 00000000000..dfc6ea81584 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/continueAndReturn.kt.conflicts @@ -0,0 +1 @@ +Selected code fragment has multiple exit points \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndBreak.kt b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndBreak.kt new file mode 100644 index 00000000000..cd3772b65b6 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndBreak.kt @@ -0,0 +1,13 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo +// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + for (n in 1..b) { + if (a > 0) throw Exception("") + if (a + b > 0) break + println(a - b) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndBreak.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndBreak.kt.after new file mode 100644 index 00000000000..c0f7d6a6c73 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndBreak.kt.after @@ -0,0 +1,18 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo +// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + for (n in 1..b) { + if (b(a, b)) break + } +} + +private fun b(a: Int, b: Int): Boolean { + if (a > 0) throw Exception("") + if (a + b > 0) return true + println(a - b) + return false +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndContinue.kt b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndContinue.kt new file mode 100644 index 00000000000..165a75896b1 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndContinue.kt @@ -0,0 +1,13 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo +// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + for (n in 1..b) { + if (a > 0) throw Exception("") + if (a + b > 0) continue + println(a - b) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndContinue.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndContinue.kt.after new file mode 100644 index 00000000000..6a399dd0635 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndContinue.kt.after @@ -0,0 +1,17 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo +// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + for (n in 1..b) { + __dummyTestFun__(a, b) + } +} + +private fun __dummyTestFun__(a: Int, b: Int) { + if (a > 0) throw Exception("") + if (a + b > 0) return + println(a - b) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturn.kt b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturn.kt new file mode 100644 index 00000000000..e6acca1d183 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturn.kt @@ -0,0 +1,12 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo +// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + + if (a > 0) throw Exception("") + if (b + a > 0) return + println(a - b) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturn.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturn.kt.after new file mode 100644 index 00000000000..84ce5827e8f --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturn.kt.after @@ -0,0 +1,16 @@ +// PARAM_TYPES: kotlin.Int +// PARAM_TYPES: kotlin.Int +// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo +// PARAM_DESCRIPTOR: val b: kotlin.Int defined in foo +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + + __dummyTestFun__(a, b) +} + +private fun __dummyTestFun__(a: Int, b: Int) { + if (a > 0) throw Exception("") + if (b + a > 0) return + println(a - b) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturnInWhen.kt b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturnInWhen.kt new file mode 100644 index 00000000000..65ddd32a15f --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturnInWhen.kt @@ -0,0 +1,17 @@ +// WITH_RUNTIME +// PARAM_TYPES: kotlin.Int, Comparable +// PARAM_DESCRIPTOR: value-parameter val i: kotlin.Int defined in example +fun example(i: Int) { + when (i) { + 1 -> { + if (i > 5) { + println("true") + } + else { + println("false") + return + } + println("!!") + } + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturnInWhen.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturnInWhen.kt.after new file mode 100644 index 00000000000..9e7a203693b --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturnInWhen.kt.after @@ -0,0 +1,20 @@ +// WITH_RUNTIME +// PARAM_TYPES: kotlin.Int, Comparable +// PARAM_DESCRIPTOR: value-parameter val i: kotlin.Int defined in example +fun example(i: Int) { + when (i) { + 1 -> { + __dummyTestFun__(i) + } + } +} + +private fun __dummyTestFun__(i: Int) { + if (i > 5) { + println("true") + } else { + println("false") + return + } + println("!!") +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/multipleBreaks.kt b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/multipleBreaks.kt new file mode 100644 index 00000000000..dcfd5220f11 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/multipleBreaks.kt @@ -0,0 +1,12 @@ +// SIBLING: +fun foo(a: Int) { + val b: Int = 1 + @loop1 for (p in 1..b) { + @loop2 for (n in 1..b) { + if (a > 0) throw Exception("") + if (a + b > 0) break@loop1 + println(a - b) + break@loop2 + } + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/multipleBreaks.kt.conflicts b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/multipleBreaks.kt.conflicts new file mode 100644 index 00000000000..dfc6ea81584 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/multipleBreaks.kt.conflicts @@ -0,0 +1 @@ +Selected code fragment has multiple exit points \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt b/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt index fa1a256555f..f0f8f6fe7e3 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt @@ -9,5 +9,6 @@ fun foo(a: Int): Int { if (a > 0) throw Exception("") if (a + b > 0) continue println(a - b) + println(a + b) } } \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt.after index 33044b59d60..d2244a72a5d 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/continueWithThrow.kt.after @@ -7,6 +7,7 @@ fun foo(a: Int): Int { val b: Int = 1 for (n in 1..b) { if (b(a, b)) continue + println(a + b) } } diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt b/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt index e6acca1d183..f583e0ab567 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt @@ -9,4 +9,5 @@ fun foo(a: Int) { if (a > 0) throw Exception("") if (b + a > 0) return println(a - b) + println(a + b) } \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt.after index ab7a315973e..9873db4bc6f 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt.after @@ -7,6 +7,7 @@ fun foo(a: Int) { val b: Int = 1 if (b(a, b)) return + println(a + b) } private fun b(a: Int, b: Int): Boolean { diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java index 4bab4d610d5..20800b0e4bf 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java @@ -501,7 +501,7 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { @TestMetadata("idea/testData/refactoring/extractFunction/controlFlow") @TestDataPath("$PROJECT_ROOT") - @InnerTestClasses({ControlFlow.ConditionalJumps.class, ControlFlow.Default.class, ControlFlow.DefiniteReturns.class, ControlFlow.EvaluateExpression.class, ControlFlow.Initializer.class, ControlFlow.OutputValues.class, ControlFlow.Throws.class, ControlFlow.Unextractable.class}) + @InnerTestClasses({ControlFlow.ConditionalJumps.class, ControlFlow.Default.class, ControlFlow.DefiniteReturns.class, ControlFlow.EvaluateExpression.class, ControlFlow.ExitPointEquivalence.class, ControlFlow.Initializer.class, ControlFlow.OutputValues.class, ControlFlow.Throws.class, ControlFlow.Unextractable.class}) @RunWith(JUnit3RunnerWithInners.class) public static class ControlFlow extends AbstractJetExtractionTest { public void testAllFilesPresentInControlFlow() throws Exception { @@ -748,6 +748,63 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { } } + @TestMetadata("idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ExitPointEquivalence extends AbstractJetExtractionTest { + public void testAllFilesPresentInExitPointEquivalence() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("breakAndReturn.kt") + public void testBreakAndReturn() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakAndReturn.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("breakContinueAndDefault.kt") + public void testBreakContinueAndDefault() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/breakContinueAndDefault.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("continueAndReturn.kt") + public void testContinueAndReturn() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/continueAndReturn.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("defaultAndBreak.kt") + public void testDefaultAndBreak() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndBreak.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("defaultAndContinue.kt") + public void testDefaultAndContinue() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndContinue.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("defaultAndReturn.kt") + public void testDefaultAndReturn() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturn.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("defaultAndReturnInWhen.kt") + public void testDefaultAndReturnInWhen() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/defaultAndReturnInWhen.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("multipleBreaks.kt") + public void testMultipleBreaks() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/exitPointEquivalence/multipleBreaks.kt"); + doExtractFunctionTest(fileName); + } + } + @TestMetadata("idea/testData/refactoring/extractFunction/controlFlow/initializer") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)