Specify type explicitly: suggest also types from overridden
So #KT-22092 Fixed
This commit is contained in:
@@ -119,7 +119,11 @@ class SpecifyTypeExplicitlyIntention : SelfTargetingRangeIntention<KtCallableDec
|
||||
return type ?: ErrorUtils.createErrorType("null type")
|
||||
}
|
||||
|
||||
fun createTypeExpressionForTemplate(exprType: KotlinType, contextElement: KtElement): Expression? {
|
||||
fun createTypeExpressionForTemplate(
|
||||
exprType: KotlinType,
|
||||
contextElement: KtDeclaration,
|
||||
useTypesFromOverridden: Boolean = false
|
||||
): Expression? {
|
||||
val resolutionFacade = contextElement.getResolutionFacade()
|
||||
val bindingContext = resolutionFacade.analyze(contextElement, BodyResolveMode.PARTIAL)
|
||||
val scope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
|
||||
@@ -133,13 +137,24 @@ class SpecifyTypeExplicitlyIntention : SelfTargetingRangeIntention<KtCallableDec
|
||||
}
|
||||
}
|
||||
|
||||
val types = with(exprType.getResolvableApproximations(scope, checkTypeParameters).toList()) {
|
||||
when {
|
||||
exprType.isNullabilityFlexible() -> flatMap {
|
||||
listOf(TypeUtils.makeNotNullable(it), TypeUtils.makeNullable(it))
|
||||
fun KotlinType.toResolvableApproximations(): List<KotlinType> =
|
||||
with(getResolvableApproximations(scope, checkTypeParameters).toList()) {
|
||||
when {
|
||||
exprType.isNullabilityFlexible() -> flatMap {
|
||||
listOf(TypeUtils.makeNotNullable(it), TypeUtils.makeNullable(it))
|
||||
}
|
||||
else -> this
|
||||
}
|
||||
else -> this
|
||||
}
|
||||
|
||||
val overriddenTypes: List<KotlinType> = if (!useTypesFromOverridden) {
|
||||
null
|
||||
} else {
|
||||
val declarationDescriptor = contextElement.resolveToDescriptorIfAny() as? CallableDescriptor
|
||||
declarationDescriptor?.overriddenDescriptors?.mapNotNull { it.returnType }
|
||||
} ?: emptyList()
|
||||
val types = (listOf(exprType) + overriddenTypes).distinct().flatMap {
|
||||
it.toResolvableApproximations()
|
||||
}.ifEmpty { return null }
|
||||
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||
@@ -150,6 +165,14 @@ class SpecifyTypeExplicitlyIntention : SelfTargetingRangeIntention<KtCallableDec
|
||||
val targetType = types.firstOrNull { it.isMarkedNullable } ?: types.first()
|
||||
return TypeChooseValueExpression(listOf(targetType), targetType)
|
||||
}
|
||||
// This helps to be sure something except Nothing is suggested
|
||||
if (contextElement.containingKtFile.findDescendantOfType<PsiComment>()?.takeIf {
|
||||
it.text == "// DO_NOT_CHOOSE_NOTHING"
|
||||
} != null) {
|
||||
val targetType = types.firstOrNull { !KotlinBuiltIns.isNothingOrNullableNothing(it) } ?: types.first()
|
||||
return TypeChooseValueExpression(listOf(targetType), targetType)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return TypeChooseValueExpression(types, types.first())
|
||||
@@ -204,7 +227,7 @@ class SpecifyTypeExplicitlyIntention : SelfTargetingRangeIntention<KtCallableDec
|
||||
assert(!exprType.isError) { "Unexpected error type, should have been checked before: " + declaration.getElementTextWithContext() + ", type = " + exprType }
|
||||
|
||||
val project = declaration.project
|
||||
val expression = createTypeExpressionForTemplate(exprType, declaration) ?: return
|
||||
val expression = createTypeExpressionForTemplate(exprType, declaration, useTypesFromOverridden = true) ?: return
|
||||
|
||||
declaration.setType(KotlinBuiltIns.FQ_NAMES.any.asString())
|
||||
|
||||
|
||||
+1
-1
@@ -343,7 +343,7 @@ public class KotlinInplaceVariableIntroducer<D extends KtCallableDeclaration> ex
|
||||
|
||||
protected void addTypeReferenceVariable(TemplateBuilderImpl builder) {
|
||||
KtTypeReference typeReference = myDeclaration.getTypeReference();
|
||||
Expression expression = SpecifyTypeExplicitlyIntention.Companion.createTypeExpressionForTemplate(myExprType, myDeclaration);
|
||||
Expression expression = SpecifyTypeExplicitlyIntention.Companion.createTypeExpressionForTemplate(myExprType, myDeclaration, false);
|
||||
if (typeReference != null && expression != null) {
|
||||
builder.replaceElement(typeReference, TYPE_REFERENCE_VARIABLE_NAME, expression, false);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// DO_NOT_CHOOSE_NOTHING
|
||||
|
||||
interface I {
|
||||
fun foo(): String?
|
||||
}
|
||||
|
||||
class Test : I {
|
||||
override fun foo()<caret> = null
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// DO_NOT_CHOOSE_NOTHING
|
||||
|
||||
interface I {
|
||||
fun foo(): String?
|
||||
}
|
||||
|
||||
class Test : I {
|
||||
override fun foo(): String? = null
|
||||
}
|
||||
@@ -14574,6 +14574,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
runTest("idea/testData/intentions/specifyTypeExplicitly/loopParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("overriddenAsNull.kt")
|
||||
public void testOverriddenAsNull() throws Exception {
|
||||
runTest("idea/testData/intentions/specifyTypeExplicitly/overriddenAsNull.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("overrideNotNullFunction.kt")
|
||||
public void testOverrideNotNullFunction() throws Exception {
|
||||
runTest("idea/testData/intentions/specifyTypeExplicitly/overrideNotNullFunction.kt");
|
||||
|
||||
Reference in New Issue
Block a user