Cast to type quick-fix: handle case with qualified elements correctly
Same fix for 'add !!' fix So #KT-18368 Fixed
This commit is contained in:
@@ -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.approximateWithResolvableType
|
||||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunction
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunction
|
||||||
@@ -115,15 +116,24 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() {
|
|||||||
expressionTypeDeclaration?.let { actions.add(LetImplementInterfaceFix(it, expectedType, expressionType)) }
|
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:
|
// We don't want to cast a cast or type-asserted expression:
|
||||||
if (diagnosticElement !is KtBinaryExpressionWithTypeRHS && diagnosticElement.parent !is KtBinaryExpressionWithTypeRHS) {
|
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)) {
|
if (!expectedType.isMarkedNullable && org.jetbrains.kotlin.types.TypeUtils.isNullableType(expressionType)) {
|
||||||
val nullableExpected = expectedType.makeNullable()
|
val nullableExpected = expectedType.makeNullable()
|
||||||
if (expressionType.isSubtypeOf(nullableExpected)) {
|
if (expressionType.isSubtypeOf(nullableExpected)) {
|
||||||
actions.add(AddExclExclCallFix(diagnosticElement))
|
actions.add(AddExclExclCallFix(diagnosticElement.getTopMostQualifiedForSelectorIfAny()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// "Add non-null asserted (!!) call" "true"
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun foo(): List<Int?> = listOf()
|
||||||
|
|
||||||
|
fun bar(i : Int, s: String) = Unit
|
||||||
|
|
||||||
|
fun use() {
|
||||||
|
val a = A()
|
||||||
|
a.bar(a.foo().<caret>single(), "Asd")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// "Add non-null asserted (!!) call" "true"
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun foo(): List<Int?> = listOf()
|
||||||
|
|
||||||
|
fun bar(i : Int, s: String) = Unit
|
||||||
|
|
||||||
|
fun use() {
|
||||||
|
val a = A()
|
||||||
|
a.bar(a.foo().single()!!, "Asd")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// "Cast expression 'a.foo().single()' to 'Int'" "true"
|
||||||
|
// WITH_RUNTIME
|
||||||
|
class A {
|
||||||
|
fun foo(): List<Any> = listOf()
|
||||||
|
|
||||||
|
fun bar(i : Int, s: String) = Unit
|
||||||
|
|
||||||
|
fun use() {
|
||||||
|
val a = A()
|
||||||
|
a.bar(a.foo().single<caret>(), "Asd")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// "Cast expression 'a.foo().single()' to 'Int'" "true"
|
||||||
|
// WITH_RUNTIME
|
||||||
|
class A {
|
||||||
|
fun foo(): List<Any> = listOf()
|
||||||
|
|
||||||
|
fun bar(i : Int, s: String) = Unit
|
||||||
|
|
||||||
|
fun use() {
|
||||||
|
val a = A()
|
||||||
|
a.bar(a.foo().single() as Int, "Asd")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10375,6 +10375,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("addExclExclToRemoveNullability.kt")
|
||||||
public void testAddExclExclToRemoveNullability() throws Exception {
|
public void testAddExclExclToRemoveNullability() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/addExclExclToRemoveNullability.kt");
|
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);
|
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")
|
@TestMetadata("castToFunctionType.kt")
|
||||||
public void testCastToFunctionType() throws Exception {
|
public void testCastToFunctionType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/casts/castToFunctionType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/casts/castToFunctionType.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user