Better behaviour of "Change Type" quickfixes in case of function types

This commit is contained in:
Wojciech Lopata
2013-04-30 19:32:21 +02:00
parent 68d8716ba8
commit 35fa071e1b
16 changed files with 113 additions and 30 deletions
@@ -33,19 +33,22 @@ 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.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.renderer.DescriptorRenderer;
public class CastExpressionFix extends JetIntentionAction<JetExpression> {
private final JetType type;
private final String renderedType;
public CastExpressionFix(@NotNull JetExpression element, @NotNull JetType type) {
super(element);
this.type = type;
renderedType = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(type);
}
@NotNull
@Override
public String getText() {
return JetBundle.message("cast.expression.to.type", element.getText(), type.toString());
return JetBundle.message("cast.expression.to.type", element.getText(), renderedType);
}
@NotNull
@@ -64,9 +67,9 @@ public class CastExpressionFix extends JetIntentionAction<JetExpression> {
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
JetBinaryExpressionWithTypeRHS castedExpression =
(JetBinaryExpressionWithTypeRHS) JetPsiFactory.createExpression(project, "(" + element.getText() + ") as " + type.toString());
(JetBinaryExpressionWithTypeRHS) JetPsiFactory.createExpression(project, "(" + element.getText() + ") as " + renderedType);
if (JetPsiUtil.areParenthesesUseless((JetParenthesizedExpression) castedExpression.getLeft())) {
castedExpression = (JetBinaryExpressionWithTypeRHS) JetPsiFactory.createExpression(project, element.getText() + " as " + type.toString());
castedExpression = (JetBinaryExpressionWithTypeRHS) JetPsiFactory.createExpression(project, element.getText() + " as " + renderedType);
}
JetParenthesizedExpression castedExpressionInParentheses =
@@ -23,38 +23,38 @@ import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
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.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.renderer.DescriptorRenderer;
public class ChangeAccessorTypeFix extends JetIntentionAction<JetPropertyAccessor> {
private String renderedType;
public ChangeAccessorTypeFix(@NotNull JetPropertyAccessor element) {
super(element);
}
@Nullable
private JetType getPropertyType() {
JetProperty property = PsiTreeUtil.getParentOfType(element, JetProperty.class);
if (property == null) return null;
return QuickFixUtil.getDeclarationReturnType(property);
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
JetType type = getPropertyType();
return super.isAvailable(project, editor, file) && type != null && !ErrorUtils.isErrorType(type);
JetProperty property = PsiTreeUtil.getParentOfType(element, JetProperty.class);
if (property == null) return false;
JetType type = QuickFixUtil.getDeclarationReturnType(property);
if (super.isAvailable(project, editor, file) && type != null && !ErrorUtils.isErrorType(type)) {
renderedType = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(type);
return true;
}
return false;
}
@NotNull
@Override
public String getText() {
JetType type = getPropertyType();
return element.isGetter()
? JetBundle.message("change.getter.type", type)
: JetBundle.message("change.setter.type", type);
? JetBundle.message("change.getter.type", renderedType)
: JetBundle.message("change.setter.type", renderedType);
}
@NotNull
@@ -65,10 +65,8 @@ public class ChangeAccessorTypeFix extends JetIntentionAction<JetPropertyAccesso
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
JetType type = getPropertyType();
if (type == null) return;
JetPropertyAccessor newElement = (JetPropertyAccessor) element.copy();
JetTypeReference newTypeReference = JetPsiFactory.createType(project, type.toString());
JetTypeReference newTypeReference = JetPsiFactory.createType(project, renderedType);
if (element.isGetter()) {
JetTypeReference returnTypeReference = newElement.getReturnTypeReference();
@@ -43,13 +43,16 @@ import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheManagerUtil;
import org.jetbrains.jet.plugin.intentions.SpecifyTypeExplicitlyAction;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.renderer.DescriptorRenderer;
public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetNamedFunction> {
private final JetType type;
private final String renderedType;
public ChangeFunctionReturnTypeFix(@NotNull JetNamedFunction element, @NotNull JetType type) {
super(element);
this.type = type;
renderedType = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(type);
}
@NotNull
@@ -65,8 +68,8 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetNamedFunc
JetBundle.message("remove.function.return.type", functionName);
}
return functionName == null ?
JetBundle.message("change.no.name.function.return.type", type.toString()) :
JetBundle.message("change.function.return.type", functionName, type.toString());
JetBundle.message("change.no.name.function.return.type", renderedType) :
JetBundle.message("change.function.return.type", functionName, renderedType);
}
@NotNull
@@ -79,7 +82,7 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction<JetNamedFunc
public void invoke(@NotNull Project project, @Nullable Editor editor, @Nullable PsiFile file) throws IncorrectOperationException {
SpecifyTypeExplicitlyAction.removeTypeAnnotation(element);
if (!(KotlinBuiltIns.getInstance().isUnit(type) && element.hasBlockBody())) {
addReturnTypeAnnotation(project, element, type.toString());
addReturnTypeAnnotation(project, element, renderedType);
}
}
@@ -31,19 +31,20 @@ import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lang.psi.JetTypeReference;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.renderer.DescriptorRenderer;
public class ChangeTypeFix extends JetIntentionAction<JetTypeReference> {
private final JetType type;
private final String renderedType;
public ChangeTypeFix(@NotNull JetTypeReference element, JetType type) {
super(element);
this.type = type;
renderedType = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(type);
}
@NotNull
@Override
public String getText() {
return JetBundle.message("change.type", element.getText(), type);
return JetBundle.message("change.type", element.getText(), renderedType);
}
@NotNull
@@ -54,7 +55,7 @@ public class ChangeTypeFix extends JetIntentionAction<JetTypeReference> {
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
element.replace(JetPsiFactory.createType(project, type.toString()));
element.replace(JetPsiFactory.createType(project, renderedType));
}
@NotNull
@@ -36,19 +36,20 @@ import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheManagerUtil;
import org.jetbrains.jet.plugin.intentions.SpecifyTypeExplicitlyAction;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.renderer.DescriptorRenderer;
public class ChangeVariableTypeFix extends JetIntentionAction<JetVariableDeclaration> {
private final JetType type;
private final String renderedType;
public ChangeVariableTypeFix(@NotNull JetVariableDeclaration element, @NotNull JetType type) {
super(element);
this.type = type;
renderedType = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(type);
}
@NotNull
@Override
public String getText() {
return JetBundle.message("change.element.type", element.getName(), type);
return JetBundle.message("change.element.type", element.getName(), renderedType);
}
@NotNull
@@ -62,7 +63,7 @@ public class ChangeVariableTypeFix extends JetIntentionAction<JetVariableDeclara
SpecifyTypeExplicitlyAction.removeTypeAnnotation(element);
PsiElement nameIdentifier = element.getNameIdentifier();
assert nameIdentifier != null : "ChangeVariableTypeFix applied to variable without name";
Pair<PsiElement, PsiElement> typeWhiteSpaceAndColon = JetPsiFactory.createTypeWhiteSpaceAndColon(project, type.toString());
Pair<PsiElement, PsiElement> typeWhiteSpaceAndColon = JetPsiFactory.createTypeWhiteSpaceAndColon(project, renderedType);
element.addRangeAfter(typeWhiteSpaceAndColon.first, typeWhiteSpaceAndColon.second, nameIdentifier);
}
@@ -0,0 +1,7 @@
// "Change 'x' type to '(String) -> Int'" "true"
trait A {
var x: (String) -> Int
}
trait B : A {
override var x: (String) -> Int
}
@@ -0,0 +1,7 @@
// "Change 'x' type to '(String) -> Int'" "true"
trait A {
var x: (String) -> Int
}
trait B : A {
override var x: (Int) -> String<caret>
}
@@ -0,0 +1,5 @@
// "Change getter type to (String) -> Int" "true"
class A {
val x: (String) -> Int
get(): (String) -> Int<caret> = {42}
}
@@ -0,0 +1,5 @@
// "Change getter type to (String) -> Int" "true"
class A {
val x: (String) -> Int
get(): Int<caret> = {42}
}
@@ -0,0 +1,6 @@
// "Change type from 'String' to '(Int) -> String'" "true"
fun foo(f: ((Int) -> String) -> String) {
foo {
(f: (Int) -> String<caret>) -> f(42)
}
}
@@ -0,0 +1,4 @@
// "Change 'foo' function return type to '(Long) -> Int'" "true"
fun foo(x: Any): (Long) -> Int {
return {(x: Long) -> 42}<caret>
}
@@ -0,0 +1,6 @@
// "Change type from 'String' to '(Int) -> String'" "true"
fun foo(f: ((Int) -> String) -> String) {
foo {
(f: String<caret>) -> f(42)
}
}
@@ -0,0 +1,4 @@
// "Change 'foo' function return type to '(Long) -> Int'" "true"
fun foo(x: Any): Int {
return {(x: Long) -> 42}<caret>
}
@@ -0,0 +1,4 @@
// "Cast expression 'x' to '() -> Int'" "true"
fun foo(x: Any): () -> Int {
return x as () -> Int<caret>
}
@@ -0,0 +1,4 @@
// "Cast expression 'x' to '() -> Int'" "true"
fun foo(x: Any): () -> Int {
return x<caret>
}
@@ -1018,6 +1018,11 @@ 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);
}
@TestMetadata("beforeChangeOverridingPropertyTypeToFunctionType.kt")
public void testChangeOverridingPropertyTypeToFunctionType() throws Exception {
doTest("idea/testData/quickfix/override/typeMismatchOnOverride/beforeChangeOverridingPropertyTypeToFunctionType.kt");
}
@TestMetadata("beforePropertyReturnTypeMismatchOnOverride.kt")
public void testPropertyReturnTypeMismatchOnOverride() throws Exception {
doTest("idea/testData/quickfix/override/typeMismatchOnOverride/beforePropertyReturnTypeMismatchOnOverride.kt");
@@ -1149,6 +1154,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest("idea/testData/quickfix/typeAddition/beforeAmbiguousPropertyReturnType.kt");
}
@TestMetadata("beforeChangeAccessorTypeToFunctionType.kt")
public void testChangeAccessorTypeToFunctionType() throws Exception {
doTest("idea/testData/quickfix/typeAddition/beforeChangeAccessorTypeToFunctionType.kt");
}
@TestMetadata("beforeNoAddErrorType.kt")
public void testNoAddErrorType() throws Exception {
doTest("idea/testData/quickfix/typeAddition/beforeNoAddErrorType.kt");
@@ -1236,6 +1246,16 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/quickfix/typeMismatch"), Pattern.compile("^before(\\w+)\\.kt$"), true);
}
@TestMetadata("beforeChangeFunctionReturnTypeToFunctionType.kt")
public void testChangeFunctionReturnTypeToFunctionType() throws Exception {
doTest("idea/testData/quickfix/typeMismatch/beforeChangeFunctionReturnTypeToFunctionType.kt");
}
@TestMetadata("beforeChangeParameterTypeToFunctionType.kt")
public void testChangeParameterTypeToFunctionType() throws Exception {
doTest("idea/testData/quickfix/typeMismatch/beforeChangeParameterTypeToFunctionType.kt");
}
@TestMetadata("beforeChangeReturnTypeWhenFunctionNameIsMissing.kt")
public void testChangeReturnTypeWhenFunctionNameIsMissing() throws Exception {
doTest("idea/testData/quickfix/typeMismatch/beforeChangeReturnTypeWhenFunctionNameIsMissing.kt");
@@ -1332,6 +1352,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest("idea/testData/quickfix/typeMismatch/casts/beforeAutocastImpossible3.kt");
}
@TestMetadata("beforeCastToFunctionType.kt")
public void testCastToFunctionType() throws Exception {
doTest("idea/testData/quickfix/typeMismatch/casts/beforeCastToFunctionType.kt");
}
@TestMetadata("beforeTypeMismatch1.kt")
public void testTypeMismatch1() throws Exception {
doTest("idea/testData/quickfix/typeMismatch/casts/beforeTypeMismatch1.kt");