Specify type: do not suggest nullable type if not null is overridden

So #KT-12814 Fixed
This commit is contained in:
Toshiaki Kameyama
2017-12-23 17:07:00 +03:00
committed by Mikhail Glukhikh
parent 50eaca1ac4
commit 817dadc120
10 changed files with 116 additions and 5 deletions
@@ -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<PsiComment>()?.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())
}
@@ -0,0 +1,9 @@
// CHOOSE_NULLABLE_TYPE_IF_EXISTS
// WITH_RUNTIME
interface Base {
fun notNullFun(): String
}
class Tesst : Base {
override fun notNullFun()<caret> = java.lang.String.valueOf("")
}
@@ -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("")
}
@@ -0,0 +1,9 @@
// CHOOSE_NULLABLE_TYPE_IF_EXISTS
// WITH_RUNTIME
interface Base {
val notNull: String
}
class Tesst : Base {
override val notNull<caret> = java.lang.String.valueOf("")
}
@@ -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("")
}
@@ -0,0 +1,9 @@
// CHOOSE_NULLABLE_TYPE_IF_EXISTS
// WITH_RUNTIME
interface Base {
fun nullableFun(): String?
}
class Tesst : Base {
override fun nullableFun()<caret> = java.lang.String.valueOf("")
}
@@ -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("")
}
@@ -0,0 +1,9 @@
// CHOOSE_NULLABLE_TYPE_IF_EXISTS
// WITH_RUNTIME
interface Base {
val nullable: String?
}
class Tesst : Base {
override val nullable<caret> = java.lang.String.valueOf("")
}
@@ -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("")
}
@@ -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");