Extract Function: Support implicit abnormal exits via Nothing-typed expressions
This commit is contained in:
@@ -242,6 +242,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
|
|||||||
- [`KT-14128`](https://youtrack.jetbrains.com/issue/KT-14128), [`KT-13862`](https://youtrack.jetbrains.com/issue/KT-13862) Rename: Use qualified class name when looking for occurrences in non-code files
|
- [`KT-14128`](https://youtrack.jetbrains.com/issue/KT-14128), [`KT-13862`](https://youtrack.jetbrains.com/issue/KT-13862) Rename: Use qualified class name when looking for occurrences in non-code files
|
||||||
- [`KT-6199`](https://youtrack.jetbrains.com/issue/KT-6199) Rename: Replace non-code class occurrences with new qualified name
|
- [`KT-6199`](https://youtrack.jetbrains.com/issue/KT-6199) Rename: Replace non-code class occurrences with new qualified name
|
||||||
- [`KT-14182`](https://youtrack.jetbrains.com/issue/KT-14182) Move: Show error message on applying to enum entries
|
- [`KT-14182`](https://youtrack.jetbrains.com/issue/KT-14182) Move: Show error message on applying to enum entries
|
||||||
|
- Extract Function: Support implicit abnormal exits via Nothing-typed expressions
|
||||||
|
|
||||||
##### New features
|
##### New features
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ interface Pseudocode {
|
|||||||
|
|
||||||
val exitInstruction: SubroutineExitInstruction
|
val exitInstruction: SubroutineExitInstruction
|
||||||
|
|
||||||
|
val errorInstruction: SubroutineExitInstruction
|
||||||
|
|
||||||
val sinkInstruction: SubroutineSinkInstruction
|
val sinkInstruction: SubroutineSinkInstruction
|
||||||
|
|
||||||
val enterInstruction: SubroutineEnterInstruction
|
val enterInstruction: SubroutineEnterInstruction
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class PseudocodeImpl(override val correspondingElement: KtElement) : Pseudocode
|
|||||||
|
|
||||||
private var internalErrorInstruction: SubroutineExitInstruction? = null
|
private var internalErrorInstruction: SubroutineExitInstruction? = null
|
||||||
|
|
||||||
private val errorInstruction: SubroutineExitInstruction
|
override val errorInstruction: SubroutineExitInstruction
|
||||||
get() = internalErrorInstruction ?: throw AssertionError("Error instruction is read before initialization")
|
get() = internalErrorInstruction ?: throw AssertionError("Error instruction is read before initialization")
|
||||||
|
|
||||||
private var postPrecessed = false
|
private var postPrecessed = false
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ package org.jetbrains.kotlin.cfg.pseudocode
|
|||||||
|
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.cfg.Label
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind.*
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind.*
|
||||||
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.AbstractJumpInstruction
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ConditionalJumpInstruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ConditionalJumpInstruction
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ReturnValueInstruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ReturnValueInstruction
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ThrowExceptionInstruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ThrowExceptionInstruction
|
||||||
@@ -307,4 +309,7 @@ fun Pseudocode.getPseudocodeByElement(element: KtElement): Pseudocode? {
|
|||||||
|
|
||||||
localDeclarations.forEach { decl -> decl.body.getPseudocodeByElement(element)?.let { return it } }
|
localDeclarations.forEach { decl -> decl.body.getPseudocodeByElement(element)?.let { return it } }
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val Label.isJumpToError: Boolean
|
||||||
|
get() = resolveToInstruction() == pseudocode.errorInstruction
|
||||||
+3
-1
@@ -243,6 +243,8 @@ private fun ExtractionData.analyzeControlFlow(
|
|||||||
when {
|
when {
|
||||||
it !is ReturnValueInstruction && it !is ReturnNoValueInstruction && it.owner != pseudocode ->
|
it !is ReturnValueInstruction && it !is ReturnNoValueInstruction && it.owner != pseudocode ->
|
||||||
null
|
null
|
||||||
|
it is UnconditionalJumpInstruction && it.targetLabel.isJumpToError ->
|
||||||
|
it
|
||||||
e != null && e !is KtBreakExpression && e !is KtContinueExpression ->
|
e != null && e !is KtBreakExpression && e !is KtContinueExpression ->
|
||||||
it.previousInstructions.firstOrNull()
|
it.previousInstructions.firstOrNull()
|
||||||
else ->
|
else ->
|
||||||
@@ -268,7 +270,7 @@ private fun ExtractionData.analyzeControlFlow(
|
|||||||
|| element is KtContinueExpression) {
|
|| element is KtContinueExpression) {
|
||||||
jumpExits.add(inst)
|
jumpExits.add(inst)
|
||||||
}
|
}
|
||||||
else if (element !is KtThrowExpression) {
|
else if (element !is KtThrowExpression && !inst.targetLabel.isJumpToError) {
|
||||||
defaultExits.add(inst)
|
defaultExits.add(inst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
// PARAM_DESCRIPTOR: value-parameter a: kotlin.Int? defined in foo
|
||||||
|
// PARAM_TYPES: kotlin.Int?
|
||||||
|
fun foo(a: Int?): Int {
|
||||||
|
<selection>val n = a ?: error("")
|
||||||
|
return n + 1</selection>
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
// PARAM_DESCRIPTOR: value-parameter a: kotlin.Int? defined in foo
|
||||||
|
// PARAM_TYPES: kotlin.Int?
|
||||||
|
fun foo(a: Int?): Int {
|
||||||
|
return i(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun i(a: Int?): Int {
|
||||||
|
val n = a ?: error("")
|
||||||
|
return n + 1
|
||||||
|
}
|
||||||
+6
@@ -1682,6 +1682,12 @@ public class ExtractionTestGenerated extends AbstractExtractionTest {
|
|||||||
doExtractFunctionTest(fileName);
|
doExtractFunctionTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("implicitThrow.kt")
|
||||||
|
public void testImplicitThrow() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/throws/implicitThrow.kt");
|
||||||
|
doExtractFunctionTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nonValuedReturnWithThrow.kt")
|
@TestMetadata("nonValuedReturnWithThrow.kt")
|
||||||
public void testNonValuedReturnWithThrow() throws Exception {
|
public void testNonValuedReturnWithThrow() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/controlFlow/throws/nonValuedReturnWithThrow.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user