QuickFix: change type of overridden property to type of overridding property
This commit is contained in:
@@ -25,6 +25,7 @@ import com.intellij.util.IncorrectOperationException;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
@@ -32,12 +33,16 @@ import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
|||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
import org.jetbrains.jet.plugin.JetBundle;
|
import org.jetbrains.jet.plugin.JetBundle;
|
||||||
import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheManagerUtil;
|
import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheManagerUtil;
|
||||||
import org.jetbrains.jet.plugin.intentions.SpecifyTypeExplicitlyAction;
|
import org.jetbrains.jet.plugin.intentions.SpecifyTypeExplicitlyAction;
|
||||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class ChangeVariableTypeFix extends JetIntentionAction<JetVariableDeclaration> {
|
public class ChangeVariableTypeFix extends JetIntentionAction<JetVariableDeclaration> {
|
||||||
private final String renderedType;
|
private final String renderedType;
|
||||||
|
|
||||||
@@ -90,16 +95,43 @@ public class ChangeVariableTypeFix extends JetIntentionAction<JetVariableDeclara
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JetSingleIntentionActionFactory createFactoryForPropertyOrReturnTypeMismatchOnOverride() {
|
public static JetIntentionActionsFactory createFactoryForPropertyOrReturnTypeMismatchOnOverride() {
|
||||||
return new JetSingleIntentionActionFactory() {
|
return new JetIntentionActionsFactory() {
|
||||||
@Nullable
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public IntentionAction createAction(Diagnostic diagnostic) {
|
public List<IntentionAction> createActions(Diagnostic diagnostic) {
|
||||||
|
List<IntentionAction> actions = new LinkedList<IntentionAction>();
|
||||||
|
|
||||||
JetProperty property = QuickFixUtil.getParentElementOfType(diagnostic, JetProperty.class);
|
JetProperty property = QuickFixUtil.getParentElementOfType(diagnostic, JetProperty.class);
|
||||||
if (property == null) return null;
|
if (property != null) {
|
||||||
BindingContext context = KotlinCacheManagerUtil.getDeclarationsBindingContext(property);
|
BindingContext context = KotlinCacheManagerUtil.getDeclarationsBindingContext(property);
|
||||||
JetType type = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(context, property);
|
JetType lowerBoundOfOverriddenPropertiesTypes = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(context, property);
|
||||||
return type == null ? null : new ChangeVariableTypeFix(property, type);
|
if (lowerBoundOfOverriddenPropertiesTypes != null) {
|
||||||
|
actions.add(new ChangeVariableTypeFix(property, lowerBoundOfOverriddenPropertiesTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyDescriptor descriptor = (PropertyDescriptor) context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
|
||||||
|
assert descriptor != null : "Descriptor of property not available in binding context";
|
||||||
|
JetType propertyType = descriptor.getReturnType();
|
||||||
|
assert propertyType != null : "Property type cannot be null if it mismatch something";
|
||||||
|
|
||||||
|
List<PropertyDescriptor> overriddenMismatchingProperties = new LinkedList<PropertyDescriptor>();
|
||||||
|
for (PropertyDescriptor overriddenProperty: descriptor.getOverriddenDescriptors()) {
|
||||||
|
JetType overriddenPropertyType = overriddenProperty.getReturnType();
|
||||||
|
if (overriddenPropertyType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(propertyType, overriddenPropertyType)) {
|
||||||
|
overriddenMismatchingProperties.add(overriddenProperty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overriddenMismatchingProperties.size() == 1) {
|
||||||
|
JetProperty overriddenProperty =
|
||||||
|
(JetProperty) BindingContextUtils.descriptorToDeclaration(context, overriddenMismatchingProperties.get(0));
|
||||||
|
if (overriddenProperty != null) {
|
||||||
|
actions.add(new ChangeVariableTypeFix(overriddenProperty, propertyType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return actions;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ public class QuickFixes {
|
|||||||
|
|
||||||
factories.put(DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED, AddSemicolonAfterFunctionCallFix.createFactory());
|
factories.put(DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED, AddSemicolonAfterFunctionCallFix.createFactory());
|
||||||
|
|
||||||
JetSingleIntentionActionFactory changeVariableTypeFix = ChangeVariableTypeFix.createFactoryForPropertyOrReturnTypeMismatchOnOverride();
|
JetIntentionActionsFactory changeVariableTypeFix = ChangeVariableTypeFix.createFactoryForPropertyOrReturnTypeMismatchOnOverride();
|
||||||
factories.put(RETURN_TYPE_MISMATCH_ON_OVERRIDE, changeVariableTypeFix);
|
factories.put(RETURN_TYPE_MISMATCH_ON_OVERRIDE, changeVariableTypeFix);
|
||||||
factories.put(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE, changeVariableTypeFix);
|
factories.put(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE, changeVariableTypeFix);
|
||||||
factories.put(COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH, ChangeVariableTypeFix.createFactoryForComponentFunctionReturnTypeMismatch());
|
factories.put(COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH, ChangeVariableTypeFix.createFactoryForComponentFunctionReturnTypeMismatch());
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// "Change 'B.x' type to '(Int) -> Int'" "true"
|
||||||
|
trait A {
|
||||||
|
val x: (Int) -> Int
|
||||||
|
}
|
||||||
|
|
||||||
|
trait B {
|
||||||
|
val x: (Int) -> Int
|
||||||
|
}
|
||||||
|
|
||||||
|
trait C : A, B {
|
||||||
|
override val x: (Int) -> Int<caret>
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// "Change 'A.x' type to '(Int) -> Int'" "false"
|
||||||
|
// ACTION: Change 'C.x' type to '(String) -> Int'
|
||||||
|
// ERROR: <html>Return type is '(jet.Int) → jet.Int', which is not a subtype of overridden<br/><b>internal</b> <b>abstract</b> <b>val</b> x: (jet.String) → jet.Int <i>defined in</i> A</html>
|
||||||
|
trait A {
|
||||||
|
val x: (String) -> Int
|
||||||
|
}
|
||||||
|
|
||||||
|
trait B {
|
||||||
|
val x: (String) -> Any
|
||||||
|
}
|
||||||
|
|
||||||
|
trait C : A, B {
|
||||||
|
override val x: (Int) -> Int<caret>
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// "Change 'B.x' type to '(Int) -> Int'" "true"
|
||||||
|
trait A {
|
||||||
|
val x: (Int) -> Int
|
||||||
|
}
|
||||||
|
|
||||||
|
trait B {
|
||||||
|
val x: (String) -> Any
|
||||||
|
}
|
||||||
|
|
||||||
|
trait C : A, B {
|
||||||
|
override val x: (Int) -> Int<caret>
|
||||||
|
}
|
||||||
@@ -1018,6 +1018,16 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/quickfix/override/typeMismatchOnOverride"), Pattern.compile("^before(\\w+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/quickfix/override/typeMismatchOnOverride"), Pattern.compile("^before(\\w+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beforeCantChangeMultipleOverriddenPropertiesTypes.kt")
|
||||||
|
public void testCantChangeMultipleOverriddenPropertiesTypes() throws Exception {
|
||||||
|
doTest("idea/testData/quickfix/override/typeMismatchOnOverride/beforeCantChangeMultipleOverriddenPropertiesTypes.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beforeChangeOverriddenPropertyType.kt")
|
||||||
|
public void testChangeOverriddenPropertyType() throws Exception {
|
||||||
|
doTest("idea/testData/quickfix/override/typeMismatchOnOverride/beforeChangeOverriddenPropertyType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("beforeChangeOverridingPropertyTypeToFunctionType.kt")
|
@TestMetadata("beforeChangeOverridingPropertyTypeToFunctionType.kt")
|
||||||
public void testChangeOverridingPropertyTypeToFunctionType() throws Exception {
|
public void testChangeOverridingPropertyTypeToFunctionType() throws Exception {
|
||||||
doTest("idea/testData/quickfix/override/typeMismatchOnOverride/beforeChangeOverridingPropertyTypeToFunctionType.kt");
|
doTest("idea/testData/quickfix/override/typeMismatchOnOverride/beforeChangeOverridingPropertyTypeToFunctionType.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user