QuickFix: change type of overridden function to type of overridding function

This commit is contained in:
Wojciech Lopata
2013-05-15 23:02:36 +02:00
parent e08d9ee8da
commit 16d9abf546
5 changed files with 89 additions and 9 deletions
@@ -28,6 +28,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters3;
import org.jetbrains.jet.lang.psi.*;
@@ -38,6 +39,7 @@ import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheManagerUtil;
@@ -45,6 +47,9 @@ import org.jetbrains.jet.plugin.intentions.SpecifyTypeExplicitlyAction;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import java.util.LinkedList;
import java.util.List;
public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetFunction> {
private final JetType type;
private final String renderedType;
@@ -175,7 +180,8 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetFunction>
JetBinaryExpression expression = QuickFixUtil.getParentElementOfType(diagnostic, JetBinaryExpression.class);
assert expression != null : "COMPARE_TO_TYPE_MISMATCH reported on element that is not within any expression";
BindingContext context = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) expression.getContainingFile()).getBindingContext();
ResolvedCall<? extends CallableDescriptor> resolvedCall = context.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
ResolvedCall<? extends CallableDescriptor> resolvedCall = context.get(BindingContext.RESOLVED_CALL,
expression.getOperationReference());
if (resolvedCall == null) return null;
PsiElement compareTo = BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getCandidateDescriptor());
if (!(compareTo instanceof JetFunction)) return null;
@@ -185,16 +191,43 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetFunction>
}
@NotNull
public static JetSingleIntentionActionFactory createFactoryForReturnTypeMismatchOnOverride() {
return new JetSingleIntentionActionFactory() {
@Nullable
public static JetIntentionActionsFactory createFactoryForReturnTypeMismatchOnOverride() {
return new JetIntentionActionsFactory() {
@NotNull
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
public List<IntentionAction> createActions(Diagnostic diagnostic) {
List<IntentionAction> actions = new LinkedList<IntentionAction>();
JetFunction function = QuickFixUtil.getParentElementOfType(diagnostic, JetFunction.class);
if (function == null) return null;
BindingContext context = KotlinCacheManagerUtil.getDeclarationsBindingContext(function);
JetType matchingReturnType = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(context, function);
return matchingReturnType == null ? null : new ChangeFunctionReturnTypeFix(function, matchingReturnType);
if (function != null) {
BindingContext context = KotlinCacheManagerUtil.getDeclarationsBindingContext(function);
JetType matchingReturnType = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(context, function);
if (matchingReturnType != null) {
actions.add(new ChangeFunctionReturnTypeFix(function, matchingReturnType));
}
SimpleFunctionDescriptor descriptor = context.get(BindingContext.FUNCTION, function);
if (descriptor == null) return actions;
JetType functionType = descriptor.getReturnType();
if (functionType == null) return actions;
List<FunctionDescriptor> overriddenMismatchingFunctions = new LinkedList<FunctionDescriptor>();
for (FunctionDescriptor overriddenFunction: descriptor.getOverriddenDescriptors()) {
JetType overriddenFunctionType = overriddenFunction.getReturnType();
if (overriddenFunctionType == null) continue;
if (!JetTypeChecker.INSTANCE.isSubtypeOf(functionType, overriddenFunctionType)) {
overriddenMismatchingFunctions.add(overriddenFunction);
}
}
if (overriddenMismatchingFunctions.size() == 1) {
PsiElement overriddenFunction = BindingContextUtils.descriptorToDeclaration(context, overriddenMismatchingFunctions.get(0));
if (overriddenFunction instanceof JetFunction) {
actions.add(new ChangeFunctionReturnTypeFix((JetFunction) overriddenFunction, functionType));
}
}
}
return actions;
}
};
}
@@ -0,0 +1,12 @@
// "Change 'A.foo' function return type to 'Long'" "true"
trait A {
fun foo(): Long
}
trait B {
fun foo(): Number
}
trait C : A, B {
override fun foo(): Long<caret>
}
@@ -0,0 +1,13 @@
// "Change 'A.foo' function return type to 'Long'" "false"
// ERROR: <html>Return type is 'jet.Long', which is not a subtype of overridden<br/><b>internal</b> <b>abstract</b> <b>fun</b> foo(): jet.Int <i>defined in</i> A</html>
trait A {
fun foo(): Int
}
trait B {
fun foo(): String
}
trait C : A, B {
override fun foo(): Long
}
@@ -0,0 +1,12 @@
// "Change 'A.foo' function return type to 'Long'" "true"
trait A {
fun foo(): Int
}
trait B {
fun foo(): Number
}
trait C : A, B {
override fun foo(): Long<caret>
}
@@ -1033,6 +1033,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest("idea/testData/quickfix/override/typeMismatchOnOverride/beforeCantChangePropertyTypeToMatchOverridenProperties.kt");
}
@TestMetadata("beforeCantChangeReturnTypeOfOverriddenFunction.kt")
public void testCantChangeReturnTypeOfOverriddenFunction() throws Exception {
doTest("idea/testData/quickfix/override/typeMismatchOnOverride/beforeCantChangeReturnTypeOfOverriddenFunction.kt");
}
@TestMetadata("beforeChangeOverriddenPropertyType1.kt")
public void testChangeOverriddenPropertyType1() throws Exception {
doTest("idea/testData/quickfix/override/typeMismatchOnOverride/beforeChangeOverriddenPropertyType1.kt");
@@ -1048,6 +1053,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest("idea/testData/quickfix/override/typeMismatchOnOverride/beforeChangeOverridingPropertyTypeToFunctionType.kt");
}
@TestMetadata("beforeChangeReturnTypeOfOverriddenFunction.kt")
public void testChangeReturnTypeOfOverriddenFunction() throws Exception {
doTest("idea/testData/quickfix/override/typeMismatchOnOverride/beforeChangeReturnTypeOfOverriddenFunction.kt");
}
@TestMetadata("beforePropertyReturnTypeMismatchOnOverride.kt")
public void testPropertyReturnTypeMismatchOnOverride() throws Exception {
doTest("idea/testData/quickfix/override/typeMismatchOnOverride/beforePropertyReturnTypeMismatchOnOverride.kt");