diff --git a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties index 5c533243888..c8f56cfb045 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties +++ b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties @@ -57,7 +57,7 @@ add.semicolon.after.invocation=Add semicolon after invocation of ''{0}'' add.semicolon.family=Add Semicolon change.function.return.type=Change ''{0}'' function return type to ''{1}'' remove.function.return.type=Remove explicitly specified return type in ''{0}'' function -change.property.type.to.match.overridden.property=Change property type to ''{0}'' +change.element.type=Change ''{0}'' type to ''{1}'' change.type.family=Change Type add.kotlin.signature.action.family.name=Specify Custom Kotlin Signature diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/SpecifyTypeExplicitlyAction.java b/idea/src/org/jetbrains/jet/plugin/intentions/SpecifyTypeExplicitlyAction.java index 4c61e058275..7f2241a92f4 100644 --- a/idea/src/org/jetbrains/jet/plugin/intentions/SpecifyTypeExplicitlyAction.java +++ b/idea/src/org/jetbrains/jet/plugin/intentions/SpecifyTypeExplicitlyAction.java @@ -274,7 +274,7 @@ public class SpecifyTypeExplicitlyAction extends PsiElementBaseIntentionAction { sibling.getParent().getNode().removeRange(sibling.getNode(), nextSibling == null ? null : nextSibling.getNode()); } - public static void removeTypeAnnotation(JetProperty property) { + public static void removeTypeAnnotation(JetVariableDeclaration property) { removeTypeAnnotation(property.getNameIdentifier(), property.getTypeRef()); } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionReturnTypeFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionReturnTypeFix.java index 13c25c2a86e..c3b51bc32a2 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionReturnTypeFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeFunctionReturnTypeFix.java @@ -90,18 +90,23 @@ public class ChangeFunctionReturnTypeFix extends JetIntentionAction } } + @NotNull + public static JetMultiDeclarationEntry getMultiDeclarationEntryThatTypeMismatchComponentFunction(Diagnostic diagnostic) { + String componentName = ((DiagnosticWithParameters3) diagnostic).getA().getName(); + int componentIndex = Integer.valueOf(componentName.substring(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX.length())); + JetMultiDeclaration multiDeclaration = QuickFixUtil.getParentElementOfType(diagnostic, JetMultiDeclaration.class); + assert multiDeclaration != null : "COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH reported on expression that is not within any multi declaration"; + return multiDeclaration.getEntries().get(componentIndex - 1); + } + @NotNull public static JetIntentionActionFactory createFactoryForComponentFunctionReturnTypeMismatch() { return new JetIntentionActionFactory() { @Nullable @Override public IntentionAction createAction(Diagnostic diagnostic) { - String componentName = ((DiagnosticWithParameters3) diagnostic).getA().getName(); - int componentIndex = Integer.valueOf(componentName.substring(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX.length())); - JetMultiDeclaration multiDeclaration = QuickFixUtil.getParentElementOfType(diagnostic, JetMultiDeclaration.class); - assert multiDeclaration != null : "COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH reported on expression that is not within any multi declaration"; - JetMultiDeclarationEntry entry = multiDeclaration.getEntries().get(componentIndex - 1); - BindingContext context = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) multiDeclaration.getContainingFile().getContainingFile()).getBindingContext(); + JetMultiDeclarationEntry entry = getMultiDeclarationEntryThatTypeMismatchComponentFunction(diagnostic); + BindingContext context = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) entry.getContainingFile().getContainingFile()).getBindingContext(); ResolvedCall resolvedCall = context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry); if (resolvedCall == null) return null; JetFunction componentFunction = (JetFunction) BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getCandidateDescriptor()); diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangePropertyTypeToMatchOverriddenPropertyFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangePropertyTypeToMatchOverriddenPropertyFix.java deleted file mode 100644 index bb4a031f09a..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangePropertyTypeToMatchOverriddenPropertyFix.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -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.JetFile; -import org.jetbrains.jet.lang.psi.JetProperty; -import org.jetbrains.jet.lang.psi.JetPsiFactory; -import org.jetbrains.jet.lang.psi.JetTypeReference; -import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.plugin.JetBundle; -import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheManagerUtil; -import org.jetbrains.jet.plugin.intentions.SpecifyTypeExplicitlyAction; - -public class ChangePropertyTypeToMatchOverriddenPropertyFix extends JetIntentionAction { - private JetType matchingType; - - public ChangePropertyTypeToMatchOverriddenPropertyFix(@NotNull JetProperty property) { - super(property); - } - - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - if (!super.isAvailable(project, editor, file)) { - return false; - } - - BindingContext context = KotlinCacheManagerUtil.getDeclarationsBindingContext((JetFile) file); - matchingType = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(context, element); - return matchingType != null; - } - - @NotNull - @Override - public String getText() { - return JetBundle.message("change.property.type.to.match.overridden.property", matchingType); - } - - @NotNull - @Override - public String getFamilyName() { - return JetBundle.message("change.type.family"); - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - JetTypeReference typeReference = element.getTypeRef(); - if (typeReference == null) { - SpecifyTypeExplicitlyAction.addTypeAnnotation(project, editor, element, matchingType); - } - else { - PsiElement newType = JetPsiFactory.createType(project, matchingType.toString()); - typeReference.replace(newType); - } - } - - @NotNull - public static JetIntentionActionFactory createFactory() { - return new JetIntentionActionFactory() { - @Nullable - @Override - public IntentionAction createAction(Diagnostic diagnostic) { - JetProperty property = QuickFixUtil.getParentElementOfType(diagnostic, JetProperty.class); - return property == null ? null : new ChangePropertyTypeToMatchOverriddenPropertyFix(property); - } - }; - } -} diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeVariableTypeFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeVariableTypeFix.java new file mode 100644 index 00000000000..42fce58f2d9 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeVariableTypeFix.java @@ -0,0 +1,101 @@ +/* + * 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.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +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.BindingContextUtils; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; +import org.jetbrains.jet.lang.types.JetType; +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; + +public class ChangeVariableTypeFix extends JetIntentionAction { + private final JetType type; + + public ChangeVariableTypeFix(@NotNull JetVariableDeclaration element, @NotNull JetType type) { + super(element); + this.type = type; + } + + @NotNull + @Override + public String getText() { + return JetBundle.message("change.element.type", element.getName(), type); + } + + @NotNull + @Override + public String getFamilyName() { + return JetBundle.message("change.type.family"); + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + SpecifyTypeExplicitlyAction.removeTypeAnnotation(element); + PsiElement nameIdentifier = element.getNameIdentifier(); + assert nameIdentifier != null : "ChangeVariableTypeFix applied to variable without name"; + Pair typeWhiteSpaceAndColon = JetPsiFactory.createTypeWhiteSpaceAndColon(project, type.toString()); + element.addRangeAfter(typeWhiteSpaceAndColon.first, typeWhiteSpaceAndColon.second, nameIdentifier); + } + + @NotNull + public static JetIntentionActionFactory createFactoryForComponentFunctionReturnTypeMismatch() { + return new JetIntentionActionFactory() { + @Nullable + @Override + public IntentionAction createAction(Diagnostic diagnostic) { + JetMultiDeclarationEntry entry = ChangeFunctionReturnTypeFix.getMultiDeclarationEntryThatTypeMismatchComponentFunction(diagnostic); + BindingContext context = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) entry.getContainingFile()).getBindingContext(); + ResolvedCall resolvedCall = context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry); + if (resolvedCall == null) return null; + JetFunction componentFunction = (JetFunction) BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getCandidateDescriptor()); + if (componentFunction == null) return null; + JetType expectedType = resolvedCall.getCandidateDescriptor().getReturnType(); + return expectedType == null ? null : new ChangeVariableTypeFix(entry, expectedType); + } + }; + } + + @NotNull + public static JetIntentionActionFactory createFactoryForPropertyTypeMismatchOnOverride() { + return new JetIntentionActionFactory() { + @Nullable + @Override + public IntentionAction createAction(Diagnostic diagnostic) { + JetProperty property = QuickFixUtil.getParentElementOfType(diagnostic, JetProperty.class); + assert property != null : "PROPERTY_TYPE_MISMATCH_ON_OVERRIDE reported on element that is not within any property"; + BindingContext context = KotlinCacheManagerUtil.getDeclarationsBindingContext(property); + JetType type = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(context, property); + return type == null ? null : new ChangeVariableTypeFix(property, type); + } + }; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java index 582fb53edf2..a64153c0775 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java @@ -210,7 +210,9 @@ public class QuickFixes { factories.put(DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED, AddSemicolonAfterFunctionCallFix.createFactory()); - factories.put(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE, ChangePropertyTypeToMatchOverriddenPropertyFix.createFactory()); + factories.put(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE, ChangeVariableTypeFix.createFactoryForPropertyTypeMismatchOnOverride()); + factories.put(COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH, ChangeVariableTypeFix.createFactoryForComponentFunctionReturnTypeMismatch()); + factories.put(RETURN_TYPE_MISMATCH_ON_OVERRIDE, ChangeFunctionReturnTypeFix.createFactoryForReturnTypeMismatchOnOverride()); factories.put(COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH, ChangeFunctionReturnTypeFix.createFactoryForComponentFunctionReturnTypeMismatch()); factories.put(HAS_NEXT_FUNCTION_TYPE_MISMATCH, ChangeFunctionReturnTypeFix.createFactoryForHasNextFunctionTypeMismatch()); diff --git a/idea/testData/quickfix/override/typeMismatchOnOverride/afterPropertyTypeMismatchOnOverrideIntLong.kt b/idea/testData/quickfix/override/typeMismatchOnOverride/afterPropertyTypeMismatchOnOverrideIntLong.kt index 2ea365e2cad..e810c22a1ee 100644 --- a/idea/testData/quickfix/override/typeMismatchOnOverride/afterPropertyTypeMismatchOnOverrideIntLong.kt +++ b/idea/testData/quickfix/override/typeMismatchOnOverride/afterPropertyTypeMismatchOnOverrideIntLong.kt @@ -1,8 +1,8 @@ -// "Change property type to 'Int'" "true" +// "Change 'x' type to 'Int'" "true" abstract class A { abstract var x : Int } abstract class B : A() { - override abstract var x : Int + override abstract var x: Int } diff --git a/idea/testData/quickfix/override/typeMismatchOnOverride/afterPropertyTypeMismatchOnOverrideIntUnit.kt b/idea/testData/quickfix/override/typeMismatchOnOverride/afterPropertyTypeMismatchOnOverrideIntUnit.kt index fb5aa1327f4..8296b837504 100644 --- a/idea/testData/quickfix/override/typeMismatchOnOverride/afterPropertyTypeMismatchOnOverrideIntUnit.kt +++ b/idea/testData/quickfix/override/typeMismatchOnOverride/afterPropertyTypeMismatchOnOverrideIntUnit.kt @@ -1,8 +1,8 @@ -// "Change property type to 'Int'" "true" +// "Change 'x' type to 'Int'" "true" abstract class A { abstract var x : Int } abstract class B : A() { - override abstract var x: Int + override abstract var x: Int } diff --git a/idea/testData/quickfix/override/typeMismatchOnOverride/beforePropertyTypeMismatchOnOverrideIntLong.kt b/idea/testData/quickfix/override/typeMismatchOnOverride/beforePropertyTypeMismatchOnOverrideIntLong.kt index 1cffc8dcfaa..db0eabb5856 100644 --- a/idea/testData/quickfix/override/typeMismatchOnOverride/beforePropertyTypeMismatchOnOverrideIntLong.kt +++ b/idea/testData/quickfix/override/typeMismatchOnOverride/beforePropertyTypeMismatchOnOverrideIntLong.kt @@ -1,8 +1,8 @@ -// "Change property type to 'Int'" "true" +// "Change 'x' type to 'Int'" "true" abstract class A { abstract var x : Int } abstract class B : A() { - override abstract var x : Long + override abstract var x: Long } diff --git a/idea/testData/quickfix/override/typeMismatchOnOverride/beforePropertyTypeMismatchOnOverrideIntUnit.kt b/idea/testData/quickfix/override/typeMismatchOnOverride/beforePropertyTypeMismatchOnOverrideIntUnit.kt index 542a4f203e4..39289180da2 100644 --- a/idea/testData/quickfix/override/typeMismatchOnOverride/beforePropertyTypeMismatchOnOverrideIntUnit.kt +++ b/idea/testData/quickfix/override/typeMismatchOnOverride/beforePropertyTypeMismatchOnOverrideIntUnit.kt @@ -1,4 +1,4 @@ -// "Change property type to 'Int'" "true" +// "Change 'x' type to 'Int'" "true" abstract class A { abstract var x : Int } diff --git a/idea/testData/quickfix/typeMismatch/afterComponentFunctionReturnTypeMismatch5.kt b/idea/testData/quickfix/typeMismatch/afterComponentFunctionReturnTypeMismatch5.kt new file mode 100644 index 00000000000..503d3e31f01 --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/afterComponentFunctionReturnTypeMismatch5.kt @@ -0,0 +1,10 @@ +// "Change 'y' type to 'Int'" "true" +class A { + fun component1() = 42 + fun component2() = 42 + fun component3() = 42 +} + +fun foo(a: A) { + val (x: Int, y: Int, z: Int) = a +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeMismatch/beforeComponentFunctionReturnTypeMismatch5.kt b/idea/testData/quickfix/typeMismatch/beforeComponentFunctionReturnTypeMismatch5.kt new file mode 100644 index 00000000000..822bc91c700 --- /dev/null +++ b/idea/testData/quickfix/typeMismatch/beforeComponentFunctionReturnTypeMismatch5.kt @@ -0,0 +1,10 @@ +// "Change 'y' type to 'Int'" "true" +class A { + fun component1() = 42 + fun component2() = 42 + fun component3() = 42 +} + +fun foo(a: A) { + val (x: Int, y: String, z: Int) = a +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index 28202b3490e..930ff054b97 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -1003,6 +1003,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest("idea/testData/quickfix/typeMismatch/beforeComponentFunctionReturnTypeMismatch4.kt"); } + @TestMetadata("beforeComponentFunctionReturnTypeMismatch5.kt") + public void testComponentFunctionReturnTypeMismatch5() throws Exception { + doTest("idea/testData/quickfix/typeMismatch/beforeComponentFunctionReturnTypeMismatch5.kt"); + } + @TestMetadata("beforeHasNextFunctionReturnTypeMismatch.kt") public void testHasNextFunctionReturnTypeMismatch() throws Exception { doTest("idea/testData/quickfix/typeMismatch/beforeHasNextFunctionReturnTypeMismatch.kt");