From 51d4d3135e1c5f2bb7c32a01de00acd38b8f776b Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Tue, 9 Dec 2014 14:24:47 +0300 Subject: [PATCH] Change return type quick-fix: Add support of constant expressions #KT-6260 Fixed #KT-6404 Fixed --- .../QuickFixFactoryForTypeMismatchError.java | 47 +++++++++++++++++-- .../plugin/quickfix/QuickFixRegistrar.java | 5 +- ...afterChangeReturnTypeToSpecificNullable.kt | 6 +++ .../typeMismatch/afterConstantTypeMismatch.kt | 5 ++ .../afterMakeReturnTypeNullable.kt | 5 ++ ...eforeChangeReturnTypeToSpecificNullable.kt | 6 +++ .../beforeConstantTypeMismatch.kt | 5 ++ .../beforeMakeReturnTypeNullable.kt | 5 ++ .../quickfix/QuickFixTestGenerated.java | 18 +++++++ 9 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 idea/testData/quickfix/typeMismatch/afterChangeReturnTypeToSpecificNullable.kt create mode 100644 idea/testData/quickfix/typeMismatch/afterConstantTypeMismatch.kt create mode 100644 idea/testData/quickfix/typeMismatch/afterMakeReturnTypeNullable.kt create mode 100644 idea/testData/quickfix/typeMismatch/beforeChangeReturnTypeToSpecificNullable.kt create mode 100644 idea/testData/quickfix/typeMismatch/beforeConstantTypeMismatch.kt create mode 100644 idea/testData/quickfix/typeMismatch/beforeMakeReturnTypeNullable.kt diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java index f57f3cf7cee..27d47e66f66 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixFactoryForTypeMismatchError.java @@ -17,37 +17,76 @@ package org.jetbrains.jet.plugin.quickfix; import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.diagnostics.Diagnostic; +import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters1; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters2; import org.jetbrains.jet.lang.diagnostics.Errors; +import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage; +import org.jetbrains.jet.plugin.util.UtilPackage; +import java.util.Collections; import java.util.LinkedList; import java.util.List; //TODO: should use change signature to deal with cases of multiple overridden descriptors public class QuickFixFactoryForTypeMismatchError extends JetIntentionActionsFactory { + private final static Logger LOG = Logger.getInstance(QuickFixFactoryForTypeMismatchError.class); + @NotNull @Override protected List doCreateActions(@NotNull Diagnostic diagnostic) { List actions = new LinkedList(); - DiagnosticWithParameters2 diagnosticWithParameters = Errors.TYPE_MISMATCH.cast(diagnostic); - JetExpression expression = diagnosticWithParameters.getPsiElement(); - JetType expectedType = diagnosticWithParameters.getA(); - JetType expressionType = diagnosticWithParameters.getB(); BindingContext context = ResolvePackage.analyzeFully((JetFile) diagnostic.getPsiFile()); + PsiElement diagnosticElement = diagnostic.getPsiElement(); + if (!(diagnosticElement instanceof JetExpression)) { + LOG.error("Unexpected element: " + diagnosticElement.getText()); + return Collections.emptyList(); + } + + JetExpression expression = (JetExpression) diagnosticElement; + + JetType expectedType; + JetType expressionType; + if (diagnostic.getFactory() == Errors.TYPE_MISMATCH) { + DiagnosticWithParameters2 diagnosticWithParameters = Errors.TYPE_MISMATCH.cast(diagnostic); + expectedType = diagnosticWithParameters.getA(); + expressionType = diagnosticWithParameters.getB(); + } + else if (diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE) { + DiagnosticWithParameters1 diagnosticWithParameters = + Errors.NULL_FOR_NONNULL_TYPE.cast(diagnostic); + expectedType = diagnosticWithParameters.getA(); + expressionType = UtilPackage.makeNullable(expectedType); + } + else if (diagnostic.getFactory() == Errors.CONSTANT_EXPECTED_TYPE_MISMATCH) { + DiagnosticWithParameters2 diagnosticWithParameters = + Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic); + expectedType = diagnosticWithParameters.getB(); + expressionType = context.get(BindingContext.EXPRESSION_TYPE, expression); + if (expressionType == null) { + LOG.error("No type inferred: " + expression.getText()); + return Collections.emptyList(); + } + } + else { + LOG.error("Unexpected diagnostic: " + DefaultErrorMessages.RENDERER.render(diagnostic)); + return Collections.emptyList(); + } + // We don't want to cast a cast or type-asserted expression: if (!(expression instanceof JetBinaryExpressionWithTypeRHS) && !(expression.getParent() instanceof JetBinaryExpressionWithTypeRHS)) { actions.add(new CastExpressionFix(expression, expectedType)); diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixRegistrar.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixRegistrar.java index 3d177d23331..5ba77442aa9 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixRegistrar.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixRegistrar.java @@ -254,7 +254,10 @@ public class QuickFixRegistrar { QuickFixes.factories.put(FUNCTION_EXPECTED, CreateInvokeFunctionActionFactory.INSTANCE$); - QuickFixes.factories.put(TYPE_MISMATCH, new QuickFixFactoryForTypeMismatchError()); + QuickFixFactoryForTypeMismatchError factoryForTypeMismatchError = new QuickFixFactoryForTypeMismatchError(); + QuickFixes.factories.put(TYPE_MISMATCH, factoryForTypeMismatchError); + QuickFixes.factories.put(NULL_FOR_NONNULL_TYPE, factoryForTypeMismatchError); + QuickFixes.factories.put(CONSTANT_EXPECTED_TYPE_MISMATCH, factoryForTypeMismatchError); QuickFixes.factories.put(SMARTCAST_IMPOSSIBLE, CastExpressionFix.createFactoryForSmartCastImpossible()); diff --git a/idea/testData/quickfix/typeMismatch/afterChangeReturnTypeToSpecificNullable.kt b/idea/testData/quickfix/typeMismatch/afterChangeReturnTypeToSpecificNullable.kt new file mode 100644 index 00000000000..ba5576c92c8 --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/afterChangeReturnTypeToSpecificNullable.kt @@ -0,0 +1,6 @@ +// "Change 'foo' function return type to 'Int?'" "true" + +fun foo(): Int? { + val n: Int? = 1 + return n +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeMismatch/afterConstantTypeMismatch.kt b/idea/testData/quickfix/typeMismatch/afterConstantTypeMismatch.kt new file mode 100644 index 00000000000..ab872a3848b --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/afterConstantTypeMismatch.kt @@ -0,0 +1,5 @@ +// "Change 'foo' function return type to 'Int'" "true" + +fun foo(): Int { + return 1 +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeMismatch/afterMakeReturnTypeNullable.kt b/idea/testData/quickfix/typeMismatch/afterMakeReturnTypeNullable.kt new file mode 100644 index 00000000000..4b4abaad2c8 --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/afterMakeReturnTypeNullable.kt @@ -0,0 +1,5 @@ +// "Change 'foo' function return type to 'String?'" "true" + +fun foo(): String? { + return null +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeMismatch/beforeChangeReturnTypeToSpecificNullable.kt b/idea/testData/quickfix/typeMismatch/beforeChangeReturnTypeToSpecificNullable.kt new file mode 100644 index 00000000000..43ed76c018b --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/beforeChangeReturnTypeToSpecificNullable.kt @@ -0,0 +1,6 @@ +// "Change 'foo' function return type to 'Int?'" "true" + +fun foo(): String { + val n: Int? = 1 + return n +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeMismatch/beforeConstantTypeMismatch.kt b/idea/testData/quickfix/typeMismatch/beforeConstantTypeMismatch.kt new file mode 100644 index 00000000000..34e7c7225bb --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/beforeConstantTypeMismatch.kt @@ -0,0 +1,5 @@ +// "Change 'foo' function return type to 'Int'" "true" + +fun foo(): String { + return 1 +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeMismatch/beforeMakeReturnTypeNullable.kt b/idea/testData/quickfix/typeMismatch/beforeMakeReturnTypeNullable.kt new file mode 100644 index 00000000000..5090cef639f --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/beforeMakeReturnTypeNullable.kt @@ -0,0 +1,5 @@ +// "Change 'foo' function return type to 'String?'" "true" + +fun foo(): String { + return null +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index 6a039ff2eb3..9161fc8127e 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -4166,6 +4166,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("beforeChangeReturnTypeToSpecificNullable.kt") + public void testChangeReturnTypeToSpecificNullable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeChangeReturnTypeToSpecificNullable.kt"); + doTest(fileName); + } + @TestMetadata("beforeChangeReturnTypeWhenFunctionNameIsMissing.kt") public void testChangeReturnTypeWhenFunctionNameIsMissing() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeChangeReturnTypeWhenFunctionNameIsMissing.kt"); @@ -4184,6 +4190,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("beforeConstantTypeMismatch.kt") + public void testConstantTypeMismatch() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeConstantTypeMismatch.kt"); + doTest(fileName); + } + @TestMetadata("beforeDontChangeOverriddenPropertyTypeToErrorType.kt") public void testDontChangeOverriddenPropertyTypeToErrorType() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeDontChangeOverriddenPropertyTypeToErrorType.kt"); @@ -4214,6 +4226,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("beforeMakeReturnTypeNullable.kt") + public void testMakeReturnTypeNullable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeMakeReturnTypeNullable.kt"); + doTest(fileName); + } + @TestMetadata("beforeNoReturnInFunctionWithBlockBody.kt") public void testNoReturnInFunctionWithBlockBody() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/beforeNoReturnInFunctionWithBlockBody.kt");