From 33b6780ce2b2699e9b7146ff712857c06b8e4eb9 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 1 Jun 2016 17:28:17 +0300 Subject: [PATCH] Quick fix "add !!" for SMARTCAST_IMPOSSIBLE in certain situations --- .../kotlin/idea/quickfix/ExclExclCallFixes.kt | 21 +++++++++++++++++++ .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 1 + .../addExclExclWhenSmartCastImpossible.kt | 17 +++++++++++++++ ...ddExclExclWhenSmartCastImpossible.kt.after | 17 +++++++++++++++ .../idea/quickfix/QuickFixTestGenerated.java | 6 ++++++ 5 files changed, 62 insertions(+) create mode 100644 idea/testData/quickfix/typeMismatch/addExclExclWhenSmartCastImpossible.kt create mode 100644 idea/testData/quickfix/typeMismatch/addExclExclWhenSmartCastImpossible.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ExclExclCallFixes.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ExclExclCallFixes.kt index 8b614aff38d..eb4d7f3a6fc 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ExclExclCallFixes.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ExclExclCallFixes.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.incremental.components.NoLookupLocation @@ -34,6 +35,7 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.isValidOperator @@ -106,6 +108,25 @@ class AddExclExclCallFix(val psiElement: PsiElement) : ExclExclCallFix() { } } +object SmartCastImpossibleExclExclFixFactory: KotlinSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + if (diagnostic.factory !== Errors.SMARTCAST_IMPOSSIBLE) return null + val element = diagnostic.psiElement as? KtExpression ?: return null + + val analyze = element.analyze(BodyResolveMode.PARTIAL) + val type = analyze.getType(element) + if (type == null || !TypeUtils.isNullableType(type)) return null + + val diagnosticWithParameters = Errors.SMARTCAST_IMPOSSIBLE.cast(diagnostic) + val expectedType = diagnosticWithParameters.a + if (TypeUtils.isNullableType(expectedType)) return null + val nullableExpectedType = TypeUtils.makeNullable(expectedType) + if (!type.isSubtypeOf(nullableExpectedType)) return null + + return AddExclExclCallFix(element) + } +} + object MissingIteratorExclExclFixFactory : KotlinSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): IntentionAction? { val element = diagnostic.psiElement diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 1555fe76e45..7025ff153d1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -300,6 +300,7 @@ class QuickFixRegistrar : QuickFixContributor { NULL_FOR_NONNULL_TYPE.registerFactory(factoryForTypeMismatchError) CONSTANT_EXPECTED_TYPE_MISMATCH.registerFactory(factoryForTypeMismatchError) + SMARTCAST_IMPOSSIBLE.registerFactory(SmartCastImpossibleExclExclFixFactory) SMARTCAST_IMPOSSIBLE.registerFactory(CastExpressionFix.SmartCastImpossibleFactory) PLATFORM_CLASS_MAPPED_TO_KOTLIN.registerFactory(MapPlatformClassToKotlinFix) diff --git a/idea/testData/quickfix/typeMismatch/addExclExclWhenSmartCastImpossible.kt b/idea/testData/quickfix/typeMismatch/addExclExclWhenSmartCastImpossible.kt new file mode 100644 index 00000000000..4a10cbdae93 --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/addExclExclWhenSmartCastImpossible.kt @@ -0,0 +1,17 @@ +// "Add non-null asserted (!!) call" "true" +// ACTION: Cast expression 'a' to 'Foo' + +interface Foo { + fun bar() +} + +open class MyClass { + open val a: Foo? = null + + fun foo() { + if (a != null) { + a.bar() + } + } +} + diff --git a/idea/testData/quickfix/typeMismatch/addExclExclWhenSmartCastImpossible.kt.after b/idea/testData/quickfix/typeMismatch/addExclExclWhenSmartCastImpossible.kt.after new file mode 100644 index 00000000000..2e1a2252502 --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/addExclExclWhenSmartCastImpossible.kt.after @@ -0,0 +1,17 @@ +// "Add non-null asserted (!!) call" "true" +// ACTION: Cast expression 'a' to 'Foo' + +interface Foo { + fun bar() +} + +open class MyClass { + open val a: Foo? = null + + fun foo() { + if (a != null) { + a!!.bar() + } + } +} + diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 293be8e6524..cd56ff226c0 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -7662,6 +7662,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("addExclExclWhenSmartCastImpossible.kt") + public void testAddExclExclWhenSmartCastImpossible() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/addExclExclWhenSmartCastImpossible.kt"); + doTest(fileName); + } + @TestMetadata("addIntArrayOf.kt") public void testAddIntArrayOf() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/addIntArrayOf.kt");