From 817dadc120df487a95b5a68c46d05d866c61783e Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Sat, 23 Dec 2017 17:07:00 +0300 Subject: [PATCH] Specify type: do not suggest nullable type if not null is overridden So #KT-12814 Fixed --- .../SpecifyTypeExplicitlyIntention.kt | 25 +++++++++++++++---- .../overrideNotNullFunction.kt | 9 +++++++ .../overrideNotNullFunction.kt.after | 9 +++++++ .../overrideNotNullProperty.kt | 9 +++++++ .../overrideNotNullProperty.kt.after | 9 +++++++ .../overrideNullableFunction.kt | 9 +++++++ .../overrideNullableFunction.kt.after | 9 +++++++ .../overrideNullableProperty.kt | 9 +++++++ .../overrideNullableProperty.kt.after | 9 +++++++ .../intentions/IntentionTestGenerated.java | 24 ++++++++++++++++++ 10 files changed, 116 insertions(+), 5 deletions(-) create mode 100644 idea/testData/intentions/specifyTypeExplicitly/overrideNotNullFunction.kt create mode 100644 idea/testData/intentions/specifyTypeExplicitly/overrideNotNullFunction.kt.after create mode 100644 idea/testData/intentions/specifyTypeExplicitly/overrideNotNullProperty.kt create mode 100644 idea/testData/intentions/specifyTypeExplicitly/overrideNotNullProperty.kt.after create mode 100644 idea/testData/intentions/specifyTypeExplicitly/overrideNullableFunction.kt create mode 100644 idea/testData/intentions/specifyTypeExplicitly/overrideNullableFunction.kt.after create mode 100644 idea/testData/intentions/specifyTypeExplicitly/overrideNullableProperty.kt create mode 100644 idea/testData/intentions/specifyTypeExplicitly/overrideNullableProperty.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyTypeExplicitlyIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyTypeExplicitlyIntention.kt index 92b3f413a0f..ab3e1fda2f3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyTypeExplicitlyIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyTypeExplicitlyIntention.kt @@ -18,8 +18,10 @@ package org.jetbrains.kotlin.idea.intentions import com.intellij.codeInsight.intention.LowPriorityAction import com.intellij.codeInsight.template.* +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Editor import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiComment import com.intellij.psi.PsiDocumentManager import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.CallableDescriptor @@ -35,12 +37,10 @@ import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.idea.util.getResolvableApproximations import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject -import org.jetbrains.kotlin.psi.psiUtil.endOffset -import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext -import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.utils.ifEmpty class SpecifyTypeExplicitlyIntention : @@ -102,7 +102,12 @@ class SpecifyTypeExplicitlyIntention : fun getTypeForDeclaration(declaration: KtCallableDeclaration): KotlinType { val descriptor = declaration.resolveToDescriptorIfAny() - val type = (descriptor as? CallableDescriptor)?.returnType + val type = (descriptor as? CallableDescriptor)?.let { + if (it.overriddenDescriptors.firstOrNull()?.returnType?.isMarkedNullable == false) + it.returnType?.makeNotNullable() + else + it.returnType + } if (type != null && type.isError && descriptor is PropertyDescriptor) { return descriptor.setterType ?: ErrorUtils.createErrorType("null type") } @@ -132,6 +137,16 @@ class SpecifyTypeExplicitlyIntention : } }.ifEmpty { return null } + if (ApplicationManager.getApplication().isUnitTestMode) { + // This helps to be sure no nullable types are suggested + if (contextElement.containingKtFile.findDescendantOfType()?.takeIf { + it.text == "// CHOOSE_NULLABLE_TYPE_IF_EXISTS" + } != null) { + val targetType = types.firstOrNull { it.isMarkedNullable } ?: types.first() + return TypeChooseValueExpression(listOf(targetType), targetType) + } + } + return TypeChooseValueExpression(types, types.first()) } diff --git a/idea/testData/intentions/specifyTypeExplicitly/overrideNotNullFunction.kt b/idea/testData/intentions/specifyTypeExplicitly/overrideNotNullFunction.kt new file mode 100644 index 00000000000..aca4df68dd0 --- /dev/null +++ b/idea/testData/intentions/specifyTypeExplicitly/overrideNotNullFunction.kt @@ -0,0 +1,9 @@ +// CHOOSE_NULLABLE_TYPE_IF_EXISTS +// WITH_RUNTIME +interface Base { + fun notNullFun(): String +} + +class Tesst : Base { + override fun notNullFun() = java.lang.String.valueOf("") +} diff --git a/idea/testData/intentions/specifyTypeExplicitly/overrideNotNullFunction.kt.after b/idea/testData/intentions/specifyTypeExplicitly/overrideNotNullFunction.kt.after new file mode 100644 index 00000000000..0cafd272634 --- /dev/null +++ b/idea/testData/intentions/specifyTypeExplicitly/overrideNotNullFunction.kt.after @@ -0,0 +1,9 @@ +// CHOOSE_NULLABLE_TYPE_IF_EXISTS +// WITH_RUNTIME +interface Base { + fun notNullFun(): String +} + +class Tesst : Base { + override fun notNullFun(): String = java.lang.String.valueOf("") +} diff --git a/idea/testData/intentions/specifyTypeExplicitly/overrideNotNullProperty.kt b/idea/testData/intentions/specifyTypeExplicitly/overrideNotNullProperty.kt new file mode 100644 index 00000000000..1eeb24880ce --- /dev/null +++ b/idea/testData/intentions/specifyTypeExplicitly/overrideNotNullProperty.kt @@ -0,0 +1,9 @@ +// CHOOSE_NULLABLE_TYPE_IF_EXISTS +// WITH_RUNTIME +interface Base { + val notNull: String +} + +class Tesst : Base { + override val notNull = java.lang.String.valueOf("") +} diff --git a/idea/testData/intentions/specifyTypeExplicitly/overrideNotNullProperty.kt.after b/idea/testData/intentions/specifyTypeExplicitly/overrideNotNullProperty.kt.after new file mode 100644 index 00000000000..37db9e8a0e2 --- /dev/null +++ b/idea/testData/intentions/specifyTypeExplicitly/overrideNotNullProperty.kt.after @@ -0,0 +1,9 @@ +// CHOOSE_NULLABLE_TYPE_IF_EXISTS +// WITH_RUNTIME +interface Base { + val notNull: String +} + +class Tesst : Base { + override val notNull: String = java.lang.String.valueOf("") +} diff --git a/idea/testData/intentions/specifyTypeExplicitly/overrideNullableFunction.kt b/idea/testData/intentions/specifyTypeExplicitly/overrideNullableFunction.kt new file mode 100644 index 00000000000..c7521ce821b --- /dev/null +++ b/idea/testData/intentions/specifyTypeExplicitly/overrideNullableFunction.kt @@ -0,0 +1,9 @@ +// CHOOSE_NULLABLE_TYPE_IF_EXISTS +// WITH_RUNTIME +interface Base { + fun nullableFun(): String? +} + +class Tesst : Base { + override fun nullableFun() = java.lang.String.valueOf("") +} diff --git a/idea/testData/intentions/specifyTypeExplicitly/overrideNullableFunction.kt.after b/idea/testData/intentions/specifyTypeExplicitly/overrideNullableFunction.kt.after new file mode 100644 index 00000000000..a51feae77e7 --- /dev/null +++ b/idea/testData/intentions/specifyTypeExplicitly/overrideNullableFunction.kt.after @@ -0,0 +1,9 @@ +// CHOOSE_NULLABLE_TYPE_IF_EXISTS +// WITH_RUNTIME +interface Base { + fun nullableFun(): String? +} + +class Tesst : Base { + override fun nullableFun(): String? = java.lang.String.valueOf("") +} diff --git a/idea/testData/intentions/specifyTypeExplicitly/overrideNullableProperty.kt b/idea/testData/intentions/specifyTypeExplicitly/overrideNullableProperty.kt new file mode 100644 index 00000000000..fa3b9446e93 --- /dev/null +++ b/idea/testData/intentions/specifyTypeExplicitly/overrideNullableProperty.kt @@ -0,0 +1,9 @@ +// CHOOSE_NULLABLE_TYPE_IF_EXISTS +// WITH_RUNTIME +interface Base { + val nullable: String? +} + +class Tesst : Base { + override val nullable = java.lang.String.valueOf("") +} diff --git a/idea/testData/intentions/specifyTypeExplicitly/overrideNullableProperty.kt.after b/idea/testData/intentions/specifyTypeExplicitly/overrideNullableProperty.kt.after new file mode 100644 index 00000000000..f871cebc66a --- /dev/null +++ b/idea/testData/intentions/specifyTypeExplicitly/overrideNullableProperty.kt.after @@ -0,0 +1,9 @@ +// CHOOSE_NULLABLE_TYPE_IF_EXISTS +// WITH_RUNTIME +interface Base { + val nullable: String? +} + +class Tesst : Base { + override val nullable: String? = java.lang.String.valueOf("") +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 35225c6928c..c9b57820833 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -14663,6 +14663,30 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("overrideNotNullFunction.kt") + public void testOverrideNotNullFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyTypeExplicitly/overrideNotNullFunction.kt"); + doTest(fileName); + } + + @TestMetadata("overrideNotNullProperty.kt") + public void testOverrideNotNullProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyTypeExplicitly/overrideNotNullProperty.kt"); + doTest(fileName); + } + + @TestMetadata("overrideNullableFunction.kt") + public void testOverrideNullableFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyTypeExplicitly/overrideNullableFunction.kt"); + doTest(fileName); + } + + @TestMetadata("overrideNullableProperty.kt") + public void testOverrideNullableProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyTypeExplicitly/overrideNullableProperty.kt"); + doTest(fileName); + } + @TestMetadata("propertyTypeFromGetter.kt") public void testPropertyTypeFromGetter() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyTypeExplicitly/propertyTypeFromGetter.kt");