提交 2ac8e5b4 编写于 作者: M Mikhail Glukhikh

"Change return type fix" now handles data class properties correctly #KT-15028 Fixed

上级 0994d460
......@@ -48,7 +48,10 @@ import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.utils.addToStdlib.check
import java.util.*
abstract class ChangeFunctionReturnTypeFix(element: KtFunction, type: KotlinType) : KotlinQuickFixAction<KtFunction>(element) {
abstract class ChangeCallableReturnTypeFix(
element: KtCallableDeclaration,
type: KotlinType
) : KotlinQuickFixAction<KtCallableDeclaration>(element) {
private val changeFunctionLiteralReturnTypeFix: ChangeFunctionLiteralReturnTypeFix?
......@@ -73,32 +76,36 @@ abstract class ChangeFunctionReturnTypeFix(element: KtFunction, type: KotlinType
if (name != null) {
val container = element.resolveToDescriptor().containingDeclaration as? ClassDescriptor
val containerName = container?.name?.check { !it.isSpecial }?.asString()
return "function " + (if (containerName != null) "'$containerName.$name'" else "'$name'")
val fullName = if (containerName != null) "'$containerName.$name'" else "'$name'"
if (element is KtParameter) {
return "property $fullName"
}
return "function $fullName"
}
else {
return null
}
}
class OnType(element: KtFunction, type: KotlinType) : ChangeFunctionReturnTypeFix(element, type), HighPriorityAction {
class OnType(element: KtFunction, type: KotlinType) : ChangeCallableReturnTypeFix(element, type), HighPriorityAction {
override fun functionPresentation() = null
}
class ForEnclosing(element: KtFunction, type: KotlinType) : ChangeFunctionReturnTypeFix(element, type), HighPriorityAction {
class ForEnclosing(element: KtFunction, type: KotlinType) : ChangeCallableReturnTypeFix(element, type), HighPriorityAction {
override fun functionPresentation(): String? {
val presentation = super.functionPresentation() ?: return "enclosing function"
return "enclosing $presentation"
}
}
class ForCalled(element: KtFunction, type: KotlinType) : ChangeFunctionReturnTypeFix(element, type) {
class ForCalled(element: KtCallableDeclaration, type: KotlinType) : ChangeCallableReturnTypeFix(element, type) {
override fun functionPresentation(): String? {
val presentation = super.functionPresentation() ?: return "called function"
return "called $presentation"
return if (element is KtParameter) "accessed $presentation" else "called $presentation"
}
}
class ForOverridden(element: KtFunction, type: KotlinType) : ChangeFunctionReturnTypeFix(element, type) {
class ForOverridden(element: KtFunction, type: KotlinType) : ChangeCallableReturnTypeFix(element, type) {
override fun functionPresentation(): String? {
val presentation = super.functionPresentation() ?: return null
return "base $presentation"
......@@ -114,17 +121,19 @@ abstract class ChangeFunctionReturnTypeFix(element: KtFunction, type: KotlinType
val functionPresentation = functionPresentation()
if (isUnitType && element.hasBlockBody()) {
if (isUnitType && element is KtFunction && element.hasBlockBody()) {
return if (functionPresentation == null)
"Remove explicitly specified return type"
else
"Remove explicitly specified return type of $functionPresentation"
}
val typeName = if (element is KtFunction) "return type" else "type"
return if (functionPresentation == null)
"Change return type to '$typePresentation'"
"Change $typeName to '$typePresentation'"
else
"Change return type of $functionPresentation to '$typePresentation'"
"Change $typeName of $functionPresentation to '$typePresentation'"
}
override fun getFamilyName() = KotlinBundle.message("change.type.family")
......@@ -142,7 +151,7 @@ abstract class ChangeFunctionReturnTypeFix(element: KtFunction, type: KotlinType
changeFunctionLiteralReturnTypeFix.invoke(project, editor!!, file)
}
else {
if (!(isUnitType && element.hasBlockBody())) {
if (!(isUnitType && element is KtFunction && element.hasBlockBody())) {
var newTypeRef = KtPsiFactory(project).createType(typeSourceCode)
newTypeRef = element.setTypeReference(newTypeRef)!!
ShortenReferences.DEFAULT.process(newTypeRef)
......@@ -158,9 +167,11 @@ abstract class ChangeFunctionReturnTypeFix(element: KtFunction, type: KotlinType
val entry = getDestructuringDeclarationEntryThatTypeMismatchComponentFunction(diagnostic)
val context = entry.analyze(BodyResolveMode.PARTIAL)
val resolvedCall = context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry) ?: return null
val componentFunction = DescriptorToSourceUtils.descriptorToDeclaration(resolvedCall.candidateDescriptor) as KtFunction? ?: return null
val componentFunction =
DescriptorToSourceUtils.descriptorToDeclaration(resolvedCall.candidateDescriptor) as? KtCallableDeclaration
?: return null
val expectedType = context[BindingContext.TYPE, entry.typeReference!!] ?: return null
return ChangeFunctionReturnTypeFix.ForCalled(componentFunction, expectedType)
return ChangeCallableReturnTypeFix.ForCalled(componentFunction, expectedType)
}
}
......@@ -172,7 +183,7 @@ abstract class ChangeFunctionReturnTypeFix(element: KtFunction, type: KotlinType
val resolvedCall = context[BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, expression] ?: return null
val hasNextDescriptor = resolvedCall.candidateDescriptor
val hasNextFunction = DescriptorToSourceUtils.descriptorToDeclaration(hasNextDescriptor) as KtFunction? ?: return null
return ChangeFunctionReturnTypeFix.ForCalled(hasNextFunction, hasNextDescriptor.builtIns.booleanType)
return ChangeCallableReturnTypeFix.ForCalled(hasNextFunction, hasNextDescriptor.builtIns.booleanType)
}
}
......@@ -183,7 +194,7 @@ abstract class ChangeFunctionReturnTypeFix(element: KtFunction, type: KotlinType
val resolvedCall = expression.getResolvedCall(context) ?: return null
val compareToDescriptor = resolvedCall.candidateDescriptor
val compareTo = DescriptorToSourceUtils.descriptorToDeclaration(compareToDescriptor) as? KtFunction ?: return null
return ChangeFunctionReturnTypeFix.ForCalled(compareTo, compareToDescriptor.builtIns.intType)
return ChangeCallableReturnTypeFix.ForCalled(compareTo, compareToDescriptor.builtIns.intType)
}
}
......@@ -197,7 +208,7 @@ abstract class ChangeFunctionReturnTypeFix(element: KtFunction, type: KotlinType
val matchingReturnType = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(descriptor)
if (matchingReturnType != null) {
actions.add(ChangeFunctionReturnTypeFix.OnType(function, matchingReturnType))
actions.add(ChangeCallableReturnTypeFix.OnType(function, matchingReturnType))
}
val functionType = descriptor.returnType ?: return actions
......@@ -213,7 +224,7 @@ abstract class ChangeFunctionReturnTypeFix(element: KtFunction, type: KotlinType
if (overriddenMismatchingFunctions.size == 1) {
val overriddenFunction = DescriptorToSourceUtils.descriptorToDeclaration(overriddenMismatchingFunctions[0])
if (overriddenFunction is KtFunction) {
actions.add(ChangeFunctionReturnTypeFix.ForOverridden(overriddenFunction, functionType))
actions.add(ChangeCallableReturnTypeFix.ForOverridden(overriddenFunction, functionType))
}
}
......@@ -224,14 +235,14 @@ abstract class ChangeFunctionReturnTypeFix(element: KtFunction, type: KotlinType
object ChangingReturnTypeToUnitFactory : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val function = QuickFixUtil.getParentElementOfType(diagnostic, KtFunction::class.java) ?: return null
return ChangeFunctionReturnTypeFix.ForEnclosing(function, function.builtIns.unitType)
return ChangeCallableReturnTypeFix.ForEnclosing(function, function.builtIns.unitType)
}
}
object ChangingReturnTypeToNothingFactory : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val function = QuickFixUtil.getParentElementOfType(diagnostic, KtFunction::class.java) ?: return null
return ChangeFunctionReturnTypeFix.ForEnclosing(function, function.builtIns.nothingType)
return ChangeCallableReturnTypeFix.ForEnclosing(function, function.builtIns.nothingType)
}
}
......
......@@ -96,7 +96,7 @@ class ChangeFunctionLiteralReturnTypeFix(
val parentFunctionReturnTypeRef = parentFunction.typeReference
val parentFunctionReturnType = context.get(BindingContext.TYPE, parentFunctionReturnTypeRef)
return if (parentFunctionReturnType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(eventualFunctionLiteralType, parentFunctionReturnType))
ChangeFunctionReturnTypeFix.ForEnclosing(parentFunction, eventualFunctionLiteralType)
ChangeCallableReturnTypeFix.ForEnclosing(parentFunction, eventualFunctionLiteralType)
else
null
}
......
......@@ -113,7 +113,7 @@ open class ChangeVariableTypeFix(element: KtVariableDeclaration, type: KotlinTyp
object ComponentFunctionReturnTypeMismatchFactory : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val entry = ChangeFunctionReturnTypeFix.getDestructuringDeclarationEntryThatTypeMismatchComponentFunction(diagnostic)
val entry = ChangeCallableReturnTypeFix.getDestructuringDeclarationEntryThatTypeMismatchComponentFunction(diagnostic)
val context = entry.analyze()
val resolvedCall = context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry) ?: return null
if (DescriptorToSourceUtils.descriptorToDeclaration(resolvedCall.candidateDescriptor) == null) return null
......
......@@ -141,7 +141,7 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() {
if (function is KtFunction && QuickFixUtil.canFunctionOrGetterReturnExpression(function, diagnosticElement)) {
val scope = function.getResolutionScope(context, function.getResolutionFacade())
val typeToInsert = expressionType.approximateWithResolvableType(scope, false)
actions.add(ChangeFunctionReturnTypeFix.ForEnclosing(function, typeToInsert))
actions.add(ChangeCallableReturnTypeFix.ForEnclosing(function, typeToInsert))
}
// Fixing overloaded operators:
......@@ -150,7 +150,7 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() {
if (resolvedCall != null) {
val declaration = getFunctionDeclaration(resolvedCall)
if (declaration != null) {
actions.add(ChangeFunctionReturnTypeFix.ForCalled(declaration, expectedType))
actions.add(ChangeCallableReturnTypeFix.ForCalled(declaration, expectedType))
}
}
}
......@@ -161,7 +161,7 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() {
if (resolvedCall != null) {
val declaration = getFunctionDeclaration(resolvedCall)
if (declaration != null) {
actions.add(ChangeFunctionReturnTypeFix.ForCalled(declaration, expectedType))
actions.add(ChangeCallableReturnTypeFix.ForCalled(declaration, expectedType))
}
}
}
......
......@@ -264,14 +264,14 @@ class QuickFixRegistrar : QuickFixContributor {
VAR_TYPE_MISMATCH_ON_OVERRIDE.registerFactory(changeVariableTypeFix)
COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH.registerFactory(ChangeVariableTypeFix.ComponentFunctionReturnTypeMismatchFactory)
val changeFunctionReturnTypeFix = ChangeFunctionReturnTypeFix.ChangingReturnTypeToUnitFactory
val changeFunctionReturnTypeFix = ChangeCallableReturnTypeFix.ChangingReturnTypeToUnitFactory
RETURN_TYPE_MISMATCH.registerFactory(changeFunctionReturnTypeFix)
NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.registerFactory(changeFunctionReturnTypeFix)
RETURN_TYPE_MISMATCH_ON_OVERRIDE.registerFactory(ChangeFunctionReturnTypeFix.ReturnTypeMismatchOnOverrideFactory)
COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH.registerFactory(ChangeFunctionReturnTypeFix.ComponentFunctionReturnTypeMismatchFactory)
HAS_NEXT_FUNCTION_TYPE_MISMATCH.registerFactory(ChangeFunctionReturnTypeFix.HasNextFunctionTypeMismatchFactory)
COMPARE_TO_TYPE_MISMATCH.registerFactory(ChangeFunctionReturnTypeFix.CompareToTypeMismatchFactory)
IMPLICIT_NOTHING_RETURN_TYPE.registerFactory(ChangeFunctionReturnTypeFix.ChangingReturnTypeToNothingFactory)
RETURN_TYPE_MISMATCH_ON_OVERRIDE.registerFactory(ChangeCallableReturnTypeFix.ReturnTypeMismatchOnOverrideFactory)
COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH.registerFactory(ChangeCallableReturnTypeFix.ComponentFunctionReturnTypeMismatchFactory)
HAS_NEXT_FUNCTION_TYPE_MISMATCH.registerFactory(ChangeCallableReturnTypeFix.HasNextFunctionTypeMismatchFactory)
COMPARE_TO_TYPE_MISMATCH.registerFactory(ChangeCallableReturnTypeFix.CompareToTypeMismatchFactory)
IMPLICIT_NOTHING_RETURN_TYPE.registerFactory(ChangeCallableReturnTypeFix.ChangingReturnTypeToNothingFactory)
TOO_MANY_ARGUMENTS.registerFactory(ChangeFunctionSignatureFix)
NO_VALUE_FOR_PARAMETER.registerFactory(ChangeFunctionSignatureFix)
......
// "class org.jetbrains.kotlin.idea.quickfix.ChangeFunctionReturnTypeFix" "false"
// "class org.jetbrains.kotlin.idea.quickfix.ChangeCallableReturnTypeFix" "false"
// ERROR: Return type of 'foo' is not a subtype of the return type of the overridden member 'public abstract fun foo(): Int defined in A'
interface A {
fun foo(): Int
......
// "Change type of accessed property 'A.x' to 'String'" "true"
// See KT-15028 (CCE)
data class A(val x: Int, val y: String)
fun f1(a: A) {
val (x: String, y) = a<caret>
}
\ No newline at end of file
// "Change type of accessed property 'A.x' to 'String'" "true"
// See KT-15028 (CCE)
data class A(val x: String, val y: String)
fun f1(a: A) {
val (x: String, y) = a<caret>
}
\ No newline at end of file
// "class org.jetbrains.kotlin.idea.quickfix.ChangeFunctionReturnTypeFix" "false"
// "class org.jetbrains.kotlin.idea.quickfix.ChangeCallableReturnTypeFix" "false"
// ACTION: Change type of 'b' to 'A'
// ACTION: Convert property initializer to getter
// ACTION: Let 'A' implement interface 'B'
......
......@@ -9346,6 +9346,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/componentFunctionReturnTypeMismatch/componentFunctionReturnTypeMismatch5.kt");
doTest(fileName);
}
@TestMetadata("dataClass.kt")
public void testDataClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/componentFunctionReturnTypeMismatch/dataClass.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/quickfix/typeMismatch/fixOverloadedOperator")
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册