"Change return type for enclosing fix" now handles TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH correctly #KT-14063 Fixed

This commit is contained in:
Mikhail Glukhikh
2016-12-05 12:22:27 +03:00
parent 2ac8e5b4a7
commit 268702e0cc
8 changed files with 76 additions and 22 deletions
@@ -121,13 +121,23 @@ public class QuickFixUtil {
return null;
}
// Returns true iff parent's value always or sometimes is evaluable to child's value, e.g.
// parent = (x), child = x;
// parent = if (...) x else y, child = x;
// parent = y.x, child = x
public static boolean canEvaluateTo(KtExpression parent, KtExpression child) {
if (parent == null || child == null) {
return false;
}
while (parent != child) {
if (child.getParent() instanceof KtParenthesizedExpression) {
child = (KtExpression) child.getParent();
PsiElement childParent = child.getParent();
if (childParent instanceof KtParenthesizedExpression) {
child = (KtExpression) childParent;
continue;
}
if (childParent instanceof KtDotQualifiedExpression &&
(child instanceof KtCallExpression || child instanceof KtDotQualifiedExpression)) {
child = (KtExpression) childParent;
continue;
}
child = getParentIfForBranch(child);
@@ -58,29 +58,36 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() {
val expectedType: KotlinType
val expressionType: KotlinType?
if (diagnostic.factory === Errors.TYPE_MISMATCH) {
val diagnosticWithParameters = Errors.TYPE_MISMATCH.cast(diagnostic)
expectedType = diagnosticWithParameters.a
expressionType = diagnosticWithParameters.b
}
else if (diagnostic.factory === Errors.NULL_FOR_NONNULL_TYPE) {
val diagnosticWithParameters = Errors.NULL_FOR_NONNULL_TYPE.cast(diagnostic)
expectedType = diagnosticWithParameters.a
expressionType = expectedType.makeNullable()
}
else if (diagnostic.factory === Errors.CONSTANT_EXPECTED_TYPE_MISMATCH) {
val diagnosticWithParameters = Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic)
expectedType = diagnosticWithParameters.b
expressionType = context.getType(diagnosticElement)
if (expressionType == null) {
LOG.error("No type inferred: " + diagnosticElement.text)
when (diagnostic.factory) {
Errors.TYPE_MISMATCH -> {
val diagnosticWithParameters = Errors.TYPE_MISMATCH.cast(diagnostic)
expectedType = diagnosticWithParameters.a
expressionType = diagnosticWithParameters.b
}
Errors.NULL_FOR_NONNULL_TYPE -> {
val diagnosticWithParameters = Errors.NULL_FOR_NONNULL_TYPE.cast(diagnostic)
expectedType = diagnosticWithParameters.a
expressionType = expectedType.makeNullable()
}
Errors.TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH -> {
val diagnosticWithParameters = Errors.TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.cast(diagnostic)
expectedType = diagnosticWithParameters.a
expressionType = diagnosticWithParameters.b
}
Errors.CONSTANT_EXPECTED_TYPE_MISMATCH -> {
val diagnosticWithParameters = Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic)
expectedType = diagnosticWithParameters.b
expressionType = context.getType(diagnosticElement)
if (expressionType == null) {
LOG.error("No type inferred: " + diagnosticElement.text)
return emptyList()
}
}
else -> {
LOG.error("Unexpected diagnostic: " + DefaultErrorMessages.render(diagnostic))
return emptyList()
}
}
else {
LOG.error("Unexpected diagnostic: " + DefaultErrorMessages.render(diagnostic))
return emptyList()
}
if (expressionType.isPrimitiveNumberType() && expectedType.isPrimitiveNumberType()) {
var wrongPrimitiveLiteralFix: WrongPrimitiveLiteralFix? = null
@@ -332,6 +332,7 @@ class QuickFixRegistrar : QuickFixContributor {
TYPE_MISMATCH.registerFactory(factoryForTypeMismatchError)
NULL_FOR_NONNULL_TYPE.registerFactory(factoryForTypeMismatchError)
CONSTANT_EXPECTED_TYPE_MISMATCH.registerFactory(factoryForTypeMismatchError)
TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.registerFactory(factoryForTypeMismatchError)
SMARTCAST_IMPOSSIBLE.registerFactory(SmartCastImpossibleExclExclFixFactory)
SMARTCAST_IMPOSSIBLE.registerFactory(CastExpressionFix.SmartCastImpossibleFactory)
@@ -0,0 +1,6 @@
// "Change return type of enclosing function 'test2' to 'List<Any>'" "true"
// WITH_RUNTIME
fun test2(ss: List<Any>) {
return ss.map { it }<caret>
}
@@ -0,0 +1,6 @@
// "Change return type of enclosing function 'test2' to 'List<Any>'" "true"
// WITH_RUNTIME
fun test2(ss: List<Any>): List<Any> {
return ss.map { it }<caret>
}
@@ -0,0 +1,6 @@
// "Change return type of enclosing function 'test1' to 'Int'" "true"
// WITH_RUNTIME
fun test1(ss: List<Any>) {
return ss.map { it }.size<caret>
}
@@ -0,0 +1,6 @@
// "Change return type of enclosing function 'test1' to 'Int'" "true"
// WITH_RUNTIME
fun test1(ss: List<Any>): Int {
return ss.map { it }.size<caret>
}
@@ -9006,6 +9006,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("changeReturnTypeForTypeInference.kt")
public void testChangeReturnTypeForTypeInference() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/changeReturnTypeForTypeInference.kt");
doTest(fileName);
}
@TestMetadata("changeReturnTypeForTypeMismatch.kt")
public void testChangeReturnTypeForTypeMismatch() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/changeReturnTypeForTypeMismatch.kt");
doTest(fileName);
}
@TestMetadata("changeReturnTypeNoFqNameForAnonymousObject.kt")
public void testChangeReturnTypeNoFqNameForAnonymousObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/changeReturnTypeNoFqNameForAnonymousObject.kt");