From a08f55cf993d92144b6384815a7c125e04e7b916 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 20 Jul 2017 16:43:00 +0300 Subject: [PATCH] Cast to type quick-fix: handle case with qualified elements correctly Same fix for 'add !!' fix So #KT-18368 Fixed --- .../QuickFixFactoryForTypeMismatchError.kt | 14 ++++++++++++-- .../typeMismatch/addExclExclToQualifiedArgument.kt | 13 +++++++++++++ .../addExclExclToQualifiedArgument.kt.after | 13 +++++++++++++ .../typeMismatch/casts/castQualifiedArgument.kt | 12 ++++++++++++ .../casts/castQualifiedArgument.kt.after | 12 ++++++++++++ .../idea/quickfix/QuickFixTestGenerated.java | 12 ++++++++++++ 6 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 idea/testData/quickfix/typeMismatch/addExclExclToQualifiedArgument.kt create mode 100644 idea/testData/quickfix/typeMismatch/addExclExclToQualifiedArgument.kt.after create mode 100644 idea/testData/quickfix/typeMismatch/casts/castQualifiedArgument.kt create mode 100644 idea/testData/quickfix/typeMismatch/casts/castQualifiedArgument.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixFactoryForTypeMismatchError.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixFactoryForTypeMismatchError.kt index 354ec1d25b0..d82049a6892 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixFactoryForTypeMismatchError.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixFactoryForTypeMismatchError.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil import org.jetbrains.kotlin.idea.util.approximateWithResolvableType import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunction @@ -115,15 +116,24 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() { expressionTypeDeclaration?.let { actions.add(LetImplementInterfaceFix(it, expectedType, expressionType)) } } + fun KtExpression.getTopMostQualifiedForSelectorIfAny(): KtExpression { + var qualifiedOrThis = this + do { + val element = qualifiedOrThis + qualifiedOrThis = element.getQualifiedExpressionForSelectorOrThis() + } while (qualifiedOrThis !== element) + return qualifiedOrThis + } + // We don't want to cast a cast or type-asserted expression: if (diagnosticElement !is KtBinaryExpressionWithTypeRHS && diagnosticElement.parent !is KtBinaryExpressionWithTypeRHS) { - actions.add(CastExpressionFix(diagnosticElement, expectedType)) + actions.add(CastExpressionFix(diagnosticElement.getTopMostQualifiedForSelectorIfAny(), expectedType)) } if (!expectedType.isMarkedNullable && org.jetbrains.kotlin.types.TypeUtils.isNullableType(expressionType)) { val nullableExpected = expectedType.makeNullable() if (expressionType.isSubtypeOf(nullableExpected)) { - actions.add(AddExclExclCallFix(diagnosticElement)) + actions.add(AddExclExclCallFix(diagnosticElement.getTopMostQualifiedForSelectorIfAny())) } } diff --git a/idea/testData/quickfix/typeMismatch/addExclExclToQualifiedArgument.kt b/idea/testData/quickfix/typeMismatch/addExclExclToQualifiedArgument.kt new file mode 100644 index 00000000000..fd86e287eb0 --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/addExclExclToQualifiedArgument.kt @@ -0,0 +1,13 @@ +// "Add non-null asserted (!!) call" "true" +// WITH_RUNTIME + +class A { + fun foo(): List = listOf() + + fun bar(i : Int, s: String) = Unit + + fun use() { + val a = A() + a.bar(a.foo().single(), "Asd") + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeMismatch/addExclExclToQualifiedArgument.kt.after b/idea/testData/quickfix/typeMismatch/addExclExclToQualifiedArgument.kt.after new file mode 100644 index 00000000000..2d4dfc26a2d --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/addExclExclToQualifiedArgument.kt.after @@ -0,0 +1,13 @@ +// "Add non-null asserted (!!) call" "true" +// WITH_RUNTIME + +class A { + fun foo(): List = listOf() + + fun bar(i : Int, s: String) = Unit + + fun use() { + val a = A() + a.bar(a.foo().single()!!, "Asd") + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeMismatch/casts/castQualifiedArgument.kt b/idea/testData/quickfix/typeMismatch/casts/castQualifiedArgument.kt new file mode 100644 index 00000000000..3644e111ef3 --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/casts/castQualifiedArgument.kt @@ -0,0 +1,12 @@ +// "Cast expression 'a.foo().single()' to 'Int'" "true" +// WITH_RUNTIME +class A { + fun foo(): List = listOf() + + fun bar(i : Int, s: String) = Unit + + fun use() { + val a = A() + a.bar(a.foo().single(), "Asd") + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeMismatch/casts/castQualifiedArgument.kt.after b/idea/testData/quickfix/typeMismatch/casts/castQualifiedArgument.kt.after new file mode 100644 index 00000000000..0893d45ace1 --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/casts/castQualifiedArgument.kt.after @@ -0,0 +1,12 @@ +// "Cast expression 'a.foo().single()' to 'Int'" "true" +// WITH_RUNTIME +class A { + fun foo(): List = listOf() + + fun bar(i : Int, s: String) = Unit + + fun use() { + val a = A() + a.bar(a.foo().single() as Int, "Asd") + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index f61959b170f..05f6bd9633b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -10375,6 +10375,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("addExclExclToQualifiedArgument.kt") + public void testAddExclExclToQualifiedArgument() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/addExclExclToQualifiedArgument.kt"); + doTest(fileName); + } + @TestMetadata("addExclExclToRemoveNullability.kt") public void testAddExclExclToRemoveNullability() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/addExclExclToRemoveNullability.kt"); @@ -10741,6 +10747,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/typeMismatch/casts"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("castQualifiedArgument.kt") + public void testCastQualifiedArgument() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/casts/castQualifiedArgument.kt"); + doTest(fileName); + } + @TestMetadata("castToFunctionType.kt") public void testCastToFunctionType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/casts/castToFunctionType.kt");