"Change to return with label" quick fix: apply for type mismatch
#KT-32280 Fixed
This commit is contained in:
committed by
Yan Zhulanow
parent
016e78e483
commit
f76e98868c
@@ -9,15 +9,19 @@ import com.intellij.codeInsight.intention.IntentionAction
|
|||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.util.findLabelAndCall
|
import org.jetbrains.kotlin.idea.util.findLabelAndCall
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||||
import org.jetbrains.kotlin.renderer.render
|
import org.jetbrains.kotlin.renderer.render
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
|
|
||||||
class ChangeToLabeledReturnFix(
|
class ChangeToLabeledReturnFix(
|
||||||
element: KtReturnExpression, val labeledReturn: String
|
element: KtReturnExpression, val labeledReturn: String
|
||||||
@@ -56,9 +60,24 @@ class ChangeToLabeledReturnFix(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
|
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
|
||||||
val expression = diagnostic.psiElement as? KtReturnExpression ?: return emptyList()
|
val element = diagnostic.psiElement as? KtElement ?: return emptyList()
|
||||||
return findAccessibleLabels(expression.analyze(), expression).map {
|
val context by lazy { element.analyze() }
|
||||||
ChangeToLabeledReturnFix(expression, labeledReturn = "return@${it.render()}")
|
val returnExpression = when (diagnostic.factory) {
|
||||||
|
Errors.RETURN_NOT_ALLOWED -> {
|
||||||
|
diagnostic.psiElement as? KtReturnExpression
|
||||||
|
}
|
||||||
|
Errors.TYPE_MISMATCH, Errors.CONSTANT_EXPECTED_TYPE_MISMATCH, Errors.NULL_FOR_NONNULL_TYPE -> {
|
||||||
|
val returnExpression = diagnostic.psiElement.getStrictParentOfType<KtReturnExpression>() ?: return emptyList()
|
||||||
|
val lambda = returnExpression.getStrictParentOfType<KtLambdaExpression>() ?: return emptyList()
|
||||||
|
val lambdaReturnType = context[BindingContext.FUNCTION, lambda.functionLiteral]?.returnType ?: return emptyList()
|
||||||
|
val returnType = returnExpression.returnedExpression?.getType(context) ?: return emptyList()
|
||||||
|
if (!returnType.isSubtypeOf(lambdaReturnType)) return emptyList()
|
||||||
|
returnExpression
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
} ?: return emptyList()
|
||||||
|
return findAccessibleLabels(context, returnExpression).map {
|
||||||
|
ChangeToLabeledReturnFix(returnExpression, labeledReturn = "return@${it.render()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -570,6 +570,9 @@ class QuickFixRegistrar : QuickFixContributor {
|
|||||||
MUST_BE_INITIALIZED_OR_BE_ABSTRACT.registerFactory(AddModifierFix.AddLateinitFactory)
|
MUST_BE_INITIALIZED_OR_BE_ABSTRACT.registerFactory(AddModifierFix.AddLateinitFactory)
|
||||||
|
|
||||||
RETURN_NOT_ALLOWED.registerFactory(ChangeToLabeledReturnFix)
|
RETURN_NOT_ALLOWED.registerFactory(ChangeToLabeledReturnFix)
|
||||||
|
TYPE_MISMATCH.registerFactory(ChangeToLabeledReturnFix)
|
||||||
|
CONSTANT_EXPECTED_TYPE_MISMATCH.registerFactory(ChangeToLabeledReturnFix)
|
||||||
|
NULL_FOR_NONNULL_TYPE.registerFactory(ChangeToLabeledReturnFix)
|
||||||
|
|
||||||
WRONG_ANNOTATION_TARGET.registerFactory(AddAnnotationTargetFix)
|
WRONG_ANNOTATION_TARGET.registerFactory(AddAnnotationTargetFix)
|
||||||
WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET.registerFactory(MoveReceiverAnnotationFix, AddAnnotationTargetFix)
|
WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET.registerFactory(MoveReceiverAnnotationFix, AddAnnotationTargetFix)
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// "Change to 'return@foo'" "true"
|
||||||
|
inline fun foo(f: (Int) -> Int) {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo { i ->
|
||||||
|
if (i == 1) return 1<caret>
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// "Change to 'return@foo'" "true"
|
||||||
|
inline fun foo(f: (Int) -> Int) {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo { i ->
|
||||||
|
if (i == 1) return@foo 1
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// "Change to 'return@foo'" "true"
|
||||||
|
inline fun foo(f: (Int) -> Int?) {}
|
||||||
|
|
||||||
|
fun baz(): Int = 0
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo { i ->
|
||||||
|
if (i == 1) return null<caret>
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// "Change to 'return@foo'" "true"
|
||||||
|
inline fun foo(f: (Int) -> Int?) {}
|
||||||
|
|
||||||
|
fun baz(): Int = 0
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo { i ->
|
||||||
|
if (i == 1) return@foo null
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// "Change to 'return@foo'" "false"
|
||||||
|
// ACTION: Add braces to 'if' statement
|
||||||
|
// ACTION: Change return type of enclosing function 'test' to 'Unit?'
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
inline fun foo(f: (Int) -> Int) {}
|
||||||
|
|
||||||
|
fun baz(): Int = 0
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo { i ->
|
||||||
|
if (i == 1) return null<caret>
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// "Change to 'return@foo'" "true"
|
||||||
|
inline fun foo(f: (Int) -> Int) {}
|
||||||
|
|
||||||
|
fun baz(): Int = 0
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo { i ->
|
||||||
|
if (i == 1) return baz()<caret>
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// "Change to 'return@foo'" "true"
|
||||||
|
inline fun foo(f: (Int) -> Int) {}
|
||||||
|
|
||||||
|
fun baz(): Int = 0
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo { i ->
|
||||||
|
if (i == 1) return@foo baz()
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// "Change to 'return@foo'" "false"
|
||||||
|
// ACTION: Add braces to 'if' statement
|
||||||
|
// ACTION: Change parameter 'f' type of function 'foo' to '(Int) -> Unit'
|
||||||
|
// ACTION: Change return type of called function 'baz' to 'Unit'
|
||||||
|
// ACTION: Change return type of enclosing function 'test' to 'String'
|
||||||
|
// ACTION: Convert to single-line lambda
|
||||||
|
// ACTION: Enable a trailing comma by default in the formatter
|
||||||
|
// ACTION: Move lambda argument into parentheses
|
||||||
|
// ACTION: Specify explicit lambda signature
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
inline fun foo(f: (Int) -> Int) {}
|
||||||
|
|
||||||
|
fun baz(): String = ""
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo { i ->
|
||||||
|
if (i == 1) return baz()<caret>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2687,6 +2687,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/changeToLabeledReturn"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/changeToLabeledReturn"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("constantExpectedTypeMismatch.kt")
|
||||||
|
public void testConstantExpectedTypeMismatch() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/changeToLabeledReturn/constantExpectedTypeMismatch.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("multipleInner.kt")
|
@TestMetadata("multipleInner.kt")
|
||||||
public void testMultipleInner() throws Exception {
|
public void testMultipleInner() throws Exception {
|
||||||
runTest("idea/testData/quickfix/changeToLabeledReturn/multipleInner.kt");
|
runTest("idea/testData/quickfix/changeToLabeledReturn/multipleInner.kt");
|
||||||
@@ -2706,6 +2711,26 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
public void testNormal() throws Exception {
|
public void testNormal() throws Exception {
|
||||||
runTest("idea/testData/quickfix/changeToLabeledReturn/normal.kt");
|
runTest("idea/testData/quickfix/changeToLabeledReturn/normal.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nullForNonnullType.kt")
|
||||||
|
public void testNullForNonnullType() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/changeToLabeledReturn/nullForNonnullType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nullForNonnullType2.kt")
|
||||||
|
public void testNullForNonnullType2() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/changeToLabeledReturn/nullForNonnullType2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeMismatch.kt")
|
||||||
|
public void testTypeMismatch() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/changeToLabeledReturn/typeMismatch.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("typeMismatch2.kt")
|
||||||
|
public void testTypeMismatch2() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/changeToLabeledReturn/typeMismatch2.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/changeToMutableCollection")
|
@TestMetadata("idea/testData/quickfix/changeToMutableCollection")
|
||||||
|
|||||||
Reference in New Issue
Block a user