Checking for unsupported return's
This commit is contained in:
+18
-2
@@ -23,19 +23,21 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.refactoring.RefactoringBundle
|
import com.intellij.refactoring.RefactoringBundle
|
||||||
|
import com.intellij.refactoring.util.CommonRefactoringUtil
|
||||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
|
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
import org.jetbrains.kotlin.idea.core.copied
|
|
||||||
import org.jetbrains.kotlin.idea.codeInliner.CallableUsageReplacementStrategy
|
import org.jetbrains.kotlin.idea.codeInliner.CallableUsageReplacementStrategy
|
||||||
import org.jetbrains.kotlin.idea.codeInliner.CodeToInlineBuilder
|
import org.jetbrains.kotlin.idea.codeInliner.CodeToInlineBuilder
|
||||||
import org.jetbrains.kotlin.idea.codeInliner.replaceUsagesInWholeProject
|
import org.jetbrains.kotlin.idea.codeInliner.replaceUsagesInWholeProject
|
||||||
|
import org.jetbrains.kotlin.idea.core.copied
|
||||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||||
import org.jetbrains.kotlin.psi.KtBlockExpression
|
import org.jetbrains.kotlin.psi.KtBlockExpression
|
||||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||||
import org.jetbrains.kotlin.psi.KtReturnExpression
|
import org.jetbrains.kotlin.psi.KtReturnExpression
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
|
||||||
@@ -71,8 +73,22 @@ class KotlinInlineFunctionHandler: InlineActionHandler() {
|
|||||||
val replacement = if (element.hasBlockBody()) {
|
val replacement = if (element.hasBlockBody()) {
|
||||||
bodyCopy as KtBlockExpression
|
bodyCopy as KtBlockExpression
|
||||||
val statements = bodyCopy.statements
|
val statements = bodyCopy.statements
|
||||||
//TODO: check no other return's!
|
|
||||||
|
val returnStatements = bodyCopy.collectDescendantsOfType<KtReturnExpression> {
|
||||||
|
it.getLabelName().let { it == null || it == element.name }
|
||||||
|
}
|
||||||
|
|
||||||
val lastReturn = statements.lastOrNull() as? KtReturnExpression
|
val lastReturn = statements.lastOrNull() as? KtReturnExpression
|
||||||
|
if (returnStatements.any { it != lastReturn }) {
|
||||||
|
val message = RefactoringBundle.getCannotRefactorMessage(
|
||||||
|
if (returnStatements.size > 1)
|
||||||
|
"Inline Function is not supported for functions with multiple return statements."
|
||||||
|
else
|
||||||
|
"Inline Function is not supported for functions with return statements not at the end of the body."
|
||||||
|
)
|
||||||
|
CommonRefactoringUtil.showErrorHint(project, editor, message, "Inline Function", null)
|
||||||
|
}
|
||||||
|
|
||||||
if (lastReturn != null) {
|
if (lastReturn != null) {
|
||||||
replacementBuilder.prepareCodeToInline(lastReturn.returnedExpression, statements.dropLast(1), ::analyzeBodyCopy)
|
replacementBuilder.prepareCodeToInline(lastReturn.returnedExpression, statements.dropLast(1), ::analyzeBodyCopy)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// ERROR: Cannot perform refactoring.\nInline Function is not supported for functions with multiple return statements.
|
||||||
|
|
||||||
|
fun <caret>f(p1: Int, p2: Int): Int {
|
||||||
|
if (p1 > 0) {
|
||||||
|
return p2
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun g() {
|
||||||
|
f(1, 2)
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// ERROR: Cannot perform refactoring.\nInline Function is not supported for functions with return statements not at the end of the body.
|
||||||
|
|
||||||
|
fun <caret>f(p1: Int, p2: Int): Int {
|
||||||
|
while (true) {
|
||||||
|
if (x() > p1) return@f p2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun x(): Int = TODO()
|
||||||
|
|
||||||
|
fun g() {
|
||||||
|
f(1, 2)
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
fun <caret>f(list: List<String>): Boolean {
|
||||||
|
return list.any {
|
||||||
|
if (it.isEmpty()) return@any false
|
||||||
|
it.length < 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun g() {
|
||||||
|
println(f(listOf("a", "b")))
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
fun g() {
|
||||||
|
println(listOf("a", "b").any {
|
||||||
|
if (it.isEmpty()) return@any false
|
||||||
|
it.length < 10
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -49,6 +49,18 @@ public class InlineTestGenerated extends AbstractInlineTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("MultipleReturns.kt")
|
||||||
|
public void testMultipleReturns() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/MultipleReturns.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ReturnNotInTheEnd.kt")
|
||||||
|
public void testReturnNotInTheEnd() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/ReturnNotInTheEnd.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("UnitReturnType.kt")
|
@TestMetadata("UnitReturnType.kt")
|
||||||
public void testUnitReturnType() throws Exception {
|
public void testUnitReturnType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/UnitReturnType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/UnitReturnType.kt");
|
||||||
@@ -150,6 +162,12 @@ public class InlineTestGenerated extends AbstractInlineTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ReturnFromLambda.kt")
|
||||||
|
public void testReturnFromLambda() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/returnAtEnd/ReturnFromLambda.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("SafeCall.kt")
|
@TestMetadata("SafeCall.kt")
|
||||||
public void testSafeCall() throws Exception {
|
public void testSafeCall() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/returnAtEnd/SafeCall.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/returnAtEnd/SafeCall.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user