"Change return type for enclosing fix" now handles TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH correctly #KT-14063 Fixed
This commit is contained in:
@@ -121,13 +121,23 @@ public class QuickFixUtil {
|
|||||||
return null;
|
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) {
|
public static boolean canEvaluateTo(KtExpression parent, KtExpression child) {
|
||||||
if (parent == null || child == null) {
|
if (parent == null || child == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
while (parent != child) {
|
while (parent != child) {
|
||||||
if (child.getParent() instanceof KtParenthesizedExpression) {
|
PsiElement childParent = child.getParent();
|
||||||
child = (KtExpression) child.getParent();
|
if (childParent instanceof KtParenthesizedExpression) {
|
||||||
|
child = (KtExpression) childParent;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (childParent instanceof KtDotQualifiedExpression &&
|
||||||
|
(child instanceof KtCallExpression || child instanceof KtDotQualifiedExpression)) {
|
||||||
|
child = (KtExpression) childParent;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
child = getParentIfForBranch(child);
|
child = getParentIfForBranch(child);
|
||||||
|
|||||||
+27
-20
@@ -58,29 +58,36 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() {
|
|||||||
|
|
||||||
val expectedType: KotlinType
|
val expectedType: KotlinType
|
||||||
val expressionType: KotlinType?
|
val expressionType: KotlinType?
|
||||||
if (diagnostic.factory === Errors.TYPE_MISMATCH) {
|
when (diagnostic.factory) {
|
||||||
val diagnosticWithParameters = Errors.TYPE_MISMATCH.cast(diagnostic)
|
Errors.TYPE_MISMATCH -> {
|
||||||
expectedType = diagnosticWithParameters.a
|
val diagnosticWithParameters = Errors.TYPE_MISMATCH.cast(diagnostic)
|
||||||
expressionType = diagnosticWithParameters.b
|
expectedType = diagnosticWithParameters.a
|
||||||
}
|
expressionType = diagnosticWithParameters.b
|
||||||
else if (diagnostic.factory === Errors.NULL_FOR_NONNULL_TYPE) {
|
}
|
||||||
val diagnosticWithParameters = Errors.NULL_FOR_NONNULL_TYPE.cast(diagnostic)
|
Errors.NULL_FOR_NONNULL_TYPE -> {
|
||||||
expectedType = diagnosticWithParameters.a
|
val diagnosticWithParameters = Errors.NULL_FOR_NONNULL_TYPE.cast(diagnostic)
|
||||||
expressionType = expectedType.makeNullable()
|
expectedType = diagnosticWithParameters.a
|
||||||
}
|
expressionType = expectedType.makeNullable()
|
||||||
else if (diagnostic.factory === Errors.CONSTANT_EXPECTED_TYPE_MISMATCH) {
|
}
|
||||||
val diagnosticWithParameters = Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic)
|
Errors.TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH -> {
|
||||||
expectedType = diagnosticWithParameters.b
|
val diagnosticWithParameters = Errors.TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.cast(diagnostic)
|
||||||
expressionType = context.getType(diagnosticElement)
|
expectedType = diagnosticWithParameters.a
|
||||||
if (expressionType == null) {
|
expressionType = diagnosticWithParameters.b
|
||||||
LOG.error("No type inferred: " + diagnosticElement.text)
|
}
|
||||||
|
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()
|
return emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
LOG.error("Unexpected diagnostic: " + DefaultErrorMessages.render(diagnostic))
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expressionType.isPrimitiveNumberType() && expectedType.isPrimitiveNumberType()) {
|
if (expressionType.isPrimitiveNumberType() && expectedType.isPrimitiveNumberType()) {
|
||||||
var wrongPrimitiveLiteralFix: WrongPrimitiveLiteralFix? = null
|
var wrongPrimitiveLiteralFix: WrongPrimitiveLiteralFix? = null
|
||||||
|
|||||||
@@ -332,6 +332,7 @@ class QuickFixRegistrar : QuickFixContributor {
|
|||||||
TYPE_MISMATCH.registerFactory(factoryForTypeMismatchError)
|
TYPE_MISMATCH.registerFactory(factoryForTypeMismatchError)
|
||||||
NULL_FOR_NONNULL_TYPE.registerFactory(factoryForTypeMismatchError)
|
NULL_FOR_NONNULL_TYPE.registerFactory(factoryForTypeMismatchError)
|
||||||
CONSTANT_EXPECTED_TYPE_MISMATCH.registerFactory(factoryForTypeMismatchError)
|
CONSTANT_EXPECTED_TYPE_MISMATCH.registerFactory(factoryForTypeMismatchError)
|
||||||
|
TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.registerFactory(factoryForTypeMismatchError)
|
||||||
|
|
||||||
SMARTCAST_IMPOSSIBLE.registerFactory(SmartCastImpossibleExclExclFixFactory)
|
SMARTCAST_IMPOSSIBLE.registerFactory(SmartCastImpossibleExclExclFixFactory)
|
||||||
SMARTCAST_IMPOSSIBLE.registerFactory(CastExpressionFix.SmartCastImpossibleFactory)
|
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);
|
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")
|
@TestMetadata("changeReturnTypeNoFqNameForAnonymousObject.kt")
|
||||||
public void testChangeReturnTypeNoFqNameForAnonymousObject() throws Exception {
|
public void testChangeReturnTypeNoFqNameForAnonymousObject() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/changeReturnTypeNoFqNameForAnonymousObject.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/changeReturnTypeNoFqNameForAnonymousObject.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user