diff --git a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties index 8c8e63f2664..b0a8ee79a46 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties +++ b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties @@ -143,6 +143,7 @@ options.jet.attribute.descriptor.label=Label change.to.function.invocation=Change to function invocation migrate.sure=Replace sure() calls by !! in project remove.val.var.from.parameter=Remove val/var from function, loop and catch parameters in project +add.override.to.equals.hashCode.toString=Add 'override' to equals, hashCode, toString in project add.when.else.branch.action.family.name=Add Else Branch add.when.else.branch.action=Add else branch move.when.else.branch.to.the.end.action=Move else branch to the end diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AddOverrideToEqualsHashCodeToStringFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AddOverrideToEqualsHashCodeToStringFix.java new file mode 100644 index 00000000000..91586ebb831 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AddOverrideToEqualsHashCodeToStringFix.java @@ -0,0 +1,112 @@ +/* + * Copyright 2010-2014 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.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.analyzer.AnalyzeExhaust; +import org.jetbrains.jet.lang.diagnostics.Diagnostic; +import org.jetbrains.jet.lang.diagnostics.Errors; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetNamedFunction; +import org.jetbrains.jet.lang.psi.JetParameter; +import org.jetbrains.jet.lang.psi.JetTypeReference; +import org.jetbrains.jet.lexer.JetToken; +import org.jetbrains.jet.plugin.JetBundle; +import org.jetbrains.jet.plugin.project.PluginJetFilesProvider; + +import java.util.Collection; +import java.util.List; + +import static org.jetbrains.jet.lexer.JetTokens.*; + +public class AddOverrideToEqualsHashCodeToStringFix extends JetIntentionAction { + private static final JetToken[] MODIFIERS_TO_REPLACE = {PUBLIC_KEYWORD, OPEN_KEYWORD}; + + public AddOverrideToEqualsHashCodeToStringFix(@NotNull PsiElement element) { + super(element); + } + + @NotNull + @Override + public String getText() { + return JetBundle.message("add.override.to.equals.hashCode.toString"); + } + + @NotNull + @Override + public String getFamilyName() { + return JetBundle.message("add.override.to.equals.hashCode.toString"); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return super.isAvailable(project, editor, file) && isEqualsHashCodeOrToString(element); + } + + private static boolean isEqualsHashCodeOrToString(@Nullable PsiElement element) { + if (!(element instanceof JetNamedFunction)) return false; + JetNamedFunction function = (JetNamedFunction) element; + String name = function.getName(); + + if ("equals".equals(name)) { + List parameters = function.getValueParameters(); + if (parameters.size() != 1) return false; + JetTypeReference parameterType = parameters.iterator().next().getTypeReference(); + return parameterType != null && ("Any?".equals(parameterType.getText()) || "jet.Any?".equals(parameterType.getText())); + } + + if ("hashCode".equals(name) || "toString".equals(name)) { + return function.getValueParameters().isEmpty(); + } + + return false; + } + + @Override + protected void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException { + Collection files = PluginJetFilesProvider.WHOLE_PROJECT_DECLARATION_PROVIDER.fun(file); + + AnalyzeExhaust analyzeExhaust = MigrateSureInProjectFix.analyzeFiles(file, files); + + for (Diagnostic diagnostic : analyzeExhaust.getBindingContext().getDiagnostics()) { + if (diagnostic.getFactory() != Errors.VIRTUAL_MEMBER_HIDDEN) continue; + + PsiElement element = diagnostic.getPsiElement(); + if (!isEqualsHashCodeOrToString(element)) continue; + + element.replace(AddModifierFix.addModifier(element, OVERRIDE_KEYWORD, MODIFIERS_TO_REPLACE, project, false)); + } + } + + @NotNull + public static JetSingleIntentionActionFactory createFactory() { + return new JetSingleIntentionActionFactory() { + @Nullable + @Override + public AddOverrideToEqualsHashCodeToStringFix createAction(Diagnostic diagnostic) { + return new AddOverrideToEqualsHashCodeToStringFix(diagnostic.getPsiElement()); + } + }; + } + +} diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/MigrateSureInProjectFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/MigrateSureInProjectFix.java index 2df69d0b26a..6a3cde31a44 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/MigrateSureInProjectFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/MigrateSureInProjectFix.java @@ -145,7 +145,7 @@ public class MigrateSureInProjectFix extends JetIntentionAction { }; } - private static AnalyzeExhaust analyzeFiles(JetFile initialFile, Collection files) { + /* package */ static AnalyzeExhaust analyzeFiles(JetFile initialFile, Collection files) { AnalyzeExhaust analyzeExhaustHeaders = AnalyzerFacadeProvider.getAnalyzerFacadeForFile(initialFile).analyzeFiles( initialFile.getProject(), files, diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java index 09b18bf0471..f8a48def99b 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java @@ -165,6 +165,8 @@ public class QuickFixes { actions.put(VAL_OR_VAR_ON_LOOP_PARAMETER, removeValVarFromParametersFix); actions.put(VAL_OR_VAR_ON_CATCH_PARAMETER, removeValVarFromParametersFix); + factories.put(VIRTUAL_MEMBER_HIDDEN, AddOverrideToEqualsHashCodeToStringFix.createFactory()); + factories.put(UNUSED_VARIABLE, RemovePsiElementSimpleFix.createRemoveVariableFactory()); actions.put(UNNECESSARY_SAFE_CALL, ReplaceCallFix.toDotCallFromSafeCall()); diff --git a/idea/testData/quickfix/migration/afterAddOverrideToEqualsHashCodeToString.kt b/idea/testData/quickfix/migration/afterAddOverrideToEqualsHashCodeToString.kt new file mode 100644 index 00000000000..485c6315b39 --- /dev/null +++ b/idea/testData/quickfix/migration/afterAddOverrideToEqualsHashCodeToString.kt @@ -0,0 +1,29 @@ +// "Add 'override' to equals, hashCode, toString in project" "true" + +class A { + override fun equals(other: Any?) = false + override fun hashCode() = 0 + override fun toString(): String { + return "A" + } +} + +class B { + override fun equals(other: Any?) = false + override fun hashCode(): Int { + return 42 + } + override fun toString() = "" +} + +class C { + override fun equals(other: Any?): Boolean = true + override fun hashCode() = 0 + override fun toString() = "" +} + +class D { + override fun equals(o: Any?) = false + override fun hashCode(): Int = 239 + override fun toString() = "" +} diff --git a/idea/testData/quickfix/migration/beforeAddOverrideToEqualsHashCodeToString.kt b/idea/testData/quickfix/migration/beforeAddOverrideToEqualsHashCodeToString.kt new file mode 100644 index 00000000000..7b77b1d50b2 --- /dev/null +++ b/idea/testData/quickfix/migration/beforeAddOverrideToEqualsHashCodeToString.kt @@ -0,0 +1,29 @@ +// "Add 'override' to equals, hashCode, toString in project" "true" + +class A { + fun equals(other: Any?) = false + fun hashCode() = 0 + fun toString(): String { + return "A" + } +} + +class B { + open fun equals(other: Any?) = false + open fun hashCode(): Int { + return 42 + } + open fun toString() = "" +} + +class C { + public fun equals(other: Any?): Boolean = true + public fun hashCode() = 0 + public fun toString() = "" +} + +class D { + public open fun equals(o: Any?) = false + public open fun hashCode(): Int = 239 + public open fun toString() = "" +} diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index 5422a422afb..60b2ca17c1b 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -767,6 +767,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { @TestMetadata("idea/testData/quickfix/migration") public static class Migration extends AbstractQuickFixTest { + @TestMetadata("beforeAddOverrideToEqualsHashCodeToString.kt") + public void testAddOverrideToEqualsHashCodeToString() throws Exception { + doTest("idea/testData/quickfix/migration/beforeAddOverrideToEqualsHashCodeToString.kt"); + } + public void testAllFilesPresentInMigration() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/quickfix/migration"), Pattern.compile("^before(\\w+)\\.kt$"), true); }