Single factory for TYPE_MISMATCH error
This commit is contained in:
@@ -20,7 +20,6 @@ import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -94,32 +93,4 @@ public class CastExpressionFix extends JetIntentionAction<JetExpression> {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetSingleIntentionActionFactory createFactoryForTypeMismatch() {
|
||||
return new JetSingleIntentionActionFactory() {
|
||||
@Nullable
|
||||
@Override
|
||||
public IntentionAction createAction(Diagnostic diagnostic) {
|
||||
assert diagnostic.getFactory() == Errors.TYPE_MISMATCH;
|
||||
@SuppressWarnings("unchecked")
|
||||
DiagnosticWithParameters2<JetExpression, JetType, JetType> diagnosticWithParameters =
|
||||
(DiagnosticWithParameters2<JetExpression, JetType, JetType>) diagnostic;
|
||||
JetExpression expression = diagnosticWithParameters.getPsiElement();
|
||||
|
||||
// we don't want to cast a cast:
|
||||
if (expression instanceof JetBinaryExpressionWithTypeRHS) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 'x: Int' - TYPE_MISMATCH might be reported on 'x', and we don't want this quickfix to be available:
|
||||
JetBinaryExpressionWithTypeRHS parentExpressionWithTypeRHS =
|
||||
PsiTreeUtil.getParentOfType(expression, JetBinaryExpressionWithTypeRHS.class, true);
|
||||
if (parentExpressionWithTypeRHS != null && parentExpressionWithTypeRHS.getLeft() == expression) {
|
||||
return null;
|
||||
}
|
||||
return new CastExpressionFix(expression, diagnosticWithParameters.getA());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,21 +16,16 @@
|
||||
|
||||
package org.jetbrains.jet.plugin.quickfix;
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.plugin.JetBundle;
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||
|
||||
public class ChangeFunctionParameterTypeFix extends JetIntentionAction<JetParameter> {
|
||||
@@ -68,38 +63,4 @@ public class ChangeFunctionParameterTypeFix extends JetIntentionAction<JetParame
|
||||
assert typeReference != null : "Parameter without type annotation cannot cause type mismatch";
|
||||
typeReference.replace(JetPsiFactory.createType(project, renderedType));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetSingleIntentionActionFactory createFactory() {
|
||||
return new JetSingleIntentionActionFactory() {
|
||||
@Nullable
|
||||
@Override
|
||||
public IntentionAction createAction(Diagnostic diagnostic) {
|
||||
// Change type of function parameter in case TYPE_MISMATCH is reported on expression passed as value argument of call
|
||||
JetParameter correspondingParameter = null;
|
||||
JetType type = null;
|
||||
|
||||
BindingContext context = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) diagnostic.getPsiFile()).getBindingContext();
|
||||
JetFunctionLiteralExpression functionLiteralExpression =
|
||||
QuickFixUtil.getParentElementOfType(diagnostic, JetFunctionLiteralExpression.class);
|
||||
|
||||
if (functionLiteralExpression != null && diagnostic.getPsiElement() == functionLiteralExpression.getBodyExpression()) {
|
||||
correspondingParameter =
|
||||
QuickFixUtil.getFunctionParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(functionLiteralExpression);
|
||||
type = context.get(BindingContext.EXPRESSION_TYPE, functionLiteralExpression);
|
||||
}
|
||||
else {
|
||||
JetValueArgument valueArgument = QuickFixUtil.getParentElementOfType(diagnostic, JetValueArgument.class);
|
||||
if (valueArgument != null && valueArgument.getArgumentExpression() == diagnostic.getPsiElement()) {
|
||||
correspondingParameter = QuickFixUtil.getFunctionParameterCorrespondingToValueArgumentPassedInCall(valueArgument);
|
||||
type = context.get(BindingContext.EXPRESSION_TYPE, valueArgument.getArgumentExpression());
|
||||
}
|
||||
}
|
||||
if (correspondingParameter != null && type != null) {
|
||||
return new ChangeFunctionParameterTypeFix(correspondingParameter, type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,24 +210,4 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetFunction>
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetSingleIntentionActionFactory createFactoryForTypeMismatch() {
|
||||
return new JetSingleIntentionActionFactory() {
|
||||
@Nullable
|
||||
@Override
|
||||
public IntentionAction createAction(Diagnostic diagnostic) {
|
||||
JetExpression expression = (JetExpression) diagnostic.getPsiElement();
|
||||
JetNamedFunction function = QuickFixUtil.getParentElementOfType(diagnostic, JetNamedFunction.class);
|
||||
|
||||
if (function != null && (function.getInitializer() == expression || expression.getParent() instanceof JetReturnExpression)) {
|
||||
BindingContext context = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) diagnostic.getPsiFile()).getBindingContext();
|
||||
JetType type = context.get(BindingContext.EXPRESSION_TYPE, expression);
|
||||
assert type != null : "Expression type mismatch, but expression has no type";
|
||||
return new ChangeFunctionReturnTypeFix(function, type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.plugin.quickfix;
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters2;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsFactory {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<IntentionAction> createActions(Diagnostic diagnostic) {
|
||||
List<IntentionAction> actions = new LinkedList<IntentionAction>();
|
||||
|
||||
assert diagnostic.getFactory() == Errors.TYPE_MISMATCH;
|
||||
@SuppressWarnings("unchecked")
|
||||
DiagnosticWithParameters2<JetExpression, JetType, JetType> diagnosticWithParameters =
|
||||
(DiagnosticWithParameters2<JetExpression, JetType, JetType>) diagnostic;
|
||||
JetExpression expression = diagnosticWithParameters.getPsiElement();
|
||||
JetType expectedType = diagnosticWithParameters.getA();
|
||||
JetType expressionType = diagnosticWithParameters.getB();
|
||||
BindingContext context = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) diagnostic.getPsiFile()).getBindingContext();
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
// Mismatch in returned expression:
|
||||
JetFunction function = PsiTreeUtil.getParentOfType(expression, JetFunction.class, true);
|
||||
if (function != null && QuickFixUtil.canFunctionReturnExpression(function, expression)) {
|
||||
actions.add(new ChangeFunctionReturnTypeFix(function, expressionType));
|
||||
}
|
||||
|
||||
// Change type of a function parameter in case TYPE_MISMATCH is reported on expression passed as value argument of call.
|
||||
// 1) When an argument is a dangling function literal:
|
||||
JetFunctionLiteralExpression functionLiteralExpression =
|
||||
QuickFixUtil.getParentElementOfType(diagnostic, JetFunctionLiteralExpression.class);
|
||||
if (functionLiteralExpression != null && functionLiteralExpression.getBodyExpression() == expression) {
|
||||
JetParameter correspondingParameter =
|
||||
QuickFixUtil.getFunctionParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(functionLiteralExpression);
|
||||
JetType functionLiteralExpressionType = context.get(BindingContext.EXPRESSION_TYPE, functionLiteralExpression);
|
||||
if (correspondingParameter != null && functionLiteralExpressionType != null) {
|
||||
actions.add(new ChangeFunctionParameterTypeFix(correspondingParameter, functionLiteralExpressionType));
|
||||
}
|
||||
}
|
||||
// 2) When an argument is passed inside value argument list:
|
||||
else {
|
||||
JetValueArgument valueArgument = QuickFixUtil.getParentElementOfType(diagnostic, JetValueArgument.class);
|
||||
if (valueArgument != null && valueArgument.getArgumentExpression() == expression) {
|
||||
JetParameter correspondingParameter = QuickFixUtil.getFunctionParameterCorrespondingToValueArgumentPassedInCall(valueArgument);
|
||||
JetType valueArgumentType = context.get(BindingContext.EXPRESSION_TYPE, valueArgument.getArgumentExpression());
|
||||
if (correspondingParameter != null && valueArgumentType != null) {
|
||||
actions.add(new ChangeFunctionParameterTypeFix(correspondingParameter, valueArgumentType));
|
||||
}
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
@@ -174,4 +174,19 @@ public class QuickFixUtil {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean canFunctionReturnExpression(@NotNull JetFunction function, @NotNull JetExpression expression) {
|
||||
if (function instanceof JetFunctionLiteral) {
|
||||
JetBlockExpression functionLiteralBody = ((JetFunctionLiteral) function).getBodyExpression();
|
||||
PsiElement returnedElement = functionLiteralBody == null ? null : functionLiteralBody.getLastChild();
|
||||
return returnedElement instanceof JetExpression && canEvaluateTo((JetExpression) returnedElement, expression);
|
||||
}
|
||||
else {
|
||||
if (function instanceof JetWithExpressionInitializer && canEvaluateTo(((JetWithExpressionInitializer) function).getInitializer(), expression)) {
|
||||
return true;
|
||||
}
|
||||
JetReturnExpression returnExpression = PsiTreeUtil.getParentOfType(expression, JetReturnExpression.class);
|
||||
return returnExpression != null && canEvaluateTo(returnExpression.getReturnedExpression(), expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +226,6 @@ public class QuickFixes {
|
||||
factories.put(COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH, ChangeFunctionReturnTypeFix.createFactoryForComponentFunctionReturnTypeMismatch());
|
||||
factories.put(HAS_NEXT_FUNCTION_TYPE_MISMATCH, ChangeFunctionReturnTypeFix.createFactoryForHasNextFunctionTypeMismatch());
|
||||
factories.put(COMPARE_TO_TYPE_MISMATCH, ChangeFunctionReturnTypeFix.createFactoryForCompareToTypeMismatch());
|
||||
factories.put(TYPE_MISMATCH, ChangeFunctionReturnTypeFix.createFactoryForTypeMismatch());
|
||||
|
||||
factories.put(TOO_MANY_ARGUMENTS, ChangeFunctionSignatureFix.createFactory());
|
||||
factories.put(NO_VALUE_FOR_PARAMETER, ChangeFunctionSignatureFix.createFactory());
|
||||
@@ -240,10 +239,9 @@ public class QuickFixes {
|
||||
factories.put(EXPECTED_TYPE_MISMATCH, changeFunctionLiteralReturnTypeFix);
|
||||
factories.put(ASSIGNMENT_TYPE_MISMATCH, changeFunctionLiteralReturnTypeFix);
|
||||
|
||||
factories.put(TYPE_MISMATCH, ChangeFunctionParameterTypeFix.createFactory());
|
||||
factories.put(TYPE_MISMATCH, new QuickFixFactoryForTypeMismatchError());
|
||||
|
||||
factories.put(AUTOCAST_IMPOSSIBLE, CastExpressionFix.createFactoryForAutoCastImpossible());
|
||||
factories.put(TYPE_MISMATCH, CastExpressionFix.createFactoryForTypeMismatch());
|
||||
|
||||
factories.put(PLATFORM_CLASS_MAPPED_TO_KOTLIN, MapPlatformClassToKotlinFix.createFactory());
|
||||
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Change function literal return type to 'String'" "true"
|
||||
fun foo(f: (String) -> Any) {
|
||||
foo {
|
||||
(s: String): String ->
|
||||
s<caret>
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Change function literal return type to 'String'" "true"
|
||||
fun foo() {
|
||||
val f: (String) -> String = {
|
||||
(s: Any): String ->
|
||||
""<caret>
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Change 'foo' function return type to '() -> Any'" "true"
|
||||
fun foo(x: Any): () -> Any {
|
||||
return {x<caret>}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Change parameter 'f' type of function 'foo' to '() -> String'" "true"
|
||||
fun foo(f: () -> String) {
|
||||
foo {
|
||||
""<caret>
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Change 'boo' function return type to 'String'" "true"
|
||||
fun boo(): String {
|
||||
return ((if (true) {
|
||||
val a = ""
|
||||
<caret>a
|
||||
} else ""))
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Change 'f' type to '(Int, Int) -> (String) -> Int'" "true"
|
||||
fun foo() {
|
||||
val f: (Int, Int) -> (String) -> Int = {
|
||||
(a: Int, b: Int): (String) -> Int ->
|
||||
val x = {(s: String) -> 42}
|
||||
if (true) x
|
||||
else if (true) x else {
|
||||
var y = 42
|
||||
if (true) x<caret> else x
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Change function literal return type to 'String'" "true"
|
||||
fun foo(f: (String) -> Any) {
|
||||
foo {
|
||||
(s: String): Int ->
|
||||
s<caret>
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Change function literal return type to 'String'" "true"
|
||||
fun foo() {
|
||||
val f: (String) -> String = {
|
||||
(s: Any): Int ->
|
||||
""<caret>
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Change 'foo' function return type to '() -> Any'" "true"
|
||||
fun foo(x: Any): () -> Int {
|
||||
return {x<caret>}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Change function 'foo' return type to 'String'" "false"
|
||||
// ERROR: <html>Type mismatch.<table><tr><td>Required:</td><td>jet.Int</td></tr><tr><td>Found:</td><td>jet.String</td></tr></table></html>
|
||||
// ACTION: Disable 'Replace 'if' with 'when''
|
||||
// ACTION: Edit intention settings
|
||||
// ACTION: Replace 'if' with 'when'
|
||||
fun foo(): Int = if (true) ""<caret>: Int else 4
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Change parameter 'f' type of function 'foo' to '() -> String'" "true"
|
||||
fun foo(f: () -> Int) {
|
||||
foo {
|
||||
""<caret>
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Change 'boo' function return type to 'String'" "true"
|
||||
fun boo(): Int {
|
||||
return ((if (true) {
|
||||
val a = ""
|
||||
<caret>a
|
||||
} else ""))
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Change 'f' type to '(Int, Int) -> (String) -> Int'" "true"
|
||||
fun foo() {
|
||||
val f: () -> Long = {
|
||||
(a: Int, b: Int): Long ->
|
||||
val x = {(s: String) -> 42}
|
||||
if (true) x
|
||||
else if (true) x else {
|
||||
var y = 42
|
||||
if (true) x<caret> else x
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1421,16 +1421,51 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeAssignmentTypeMismatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeFunctionLiteralTypeWithoutChangingFunctionParameterType.kt")
|
||||
public void testChangeFunctionLiteralTypeWithoutChangingFunctionParameterType() throws Exception {
|
||||
doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeChangeFunctionLiteralTypeWithoutChangingFunctionParameterType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeFunctionLiteralTypeWithoutChangingPropertyType.kt")
|
||||
public void testChangeFunctionLiteralTypeWithoutChangingPropertyType() throws Exception {
|
||||
doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeChangeFunctionLiteralTypeWithoutChangingPropertyType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeFunctionReturnTypeToFunctionType.kt")
|
||||
public void testChangeFunctionReturnTypeToFunctionType() throws Exception {
|
||||
doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeChangeFunctionReturnTypeToFunctionType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeChangeFunctionReturnTypeToMatchReturnTypeOfReturnedLiteral.kt")
|
||||
public void testChangeFunctionReturnTypeToMatchReturnTypeOfReturnedLiteral() throws Exception {
|
||||
doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeChangeFunctionReturnTypeToMatchReturnTypeOfReturnedLiteral.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeExpectedTypeMismatch.kt")
|
||||
public void testExpectedTypeMismatch() throws Exception {
|
||||
doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeExpectedTypeMismatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeReturnedExpresionCantEvaluateToExpresionThatTypeMismatch.kt")
|
||||
public void testReturnedExpresionCantEvaluateToExpresionThatTypeMismatch() throws Exception {
|
||||
doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeReturnedExpresionCantEvaluateToExpresionThatTypeMismatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeReturnedExpressionTypeMismatchFunctionParameterType.kt")
|
||||
public void testReturnedExpressionTypeMismatchFunctionParameterType() throws Exception {
|
||||
doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeReturnedExpressionTypeMismatchFunctionParameterType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeTypeMismatchInIfStatementReturnedByFunction.kt")
|
||||
public void testTypeMismatchInIfStatementReturnedByFunction() throws Exception {
|
||||
doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeTypeMismatchInIfStatementReturnedByFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeTypeMismatchInIfStatementReturnedByLiteral.kt")
|
||||
public void testTypeMismatchInIfStatementReturnedByLiteral() throws Exception {
|
||||
doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeTypeMismatchInIfStatementReturnedByLiteral.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeTypeMismatchInInitializer.kt")
|
||||
public void testTypeMismatchInInitializer() throws Exception {
|
||||
doTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/beforeTypeMismatchInInitializer.kt");
|
||||
|
||||
Reference in New Issue
Block a user