Quickfix to add 'override' to equals, hashCode, toString in project

To help users migrate to the newest Kotlin version in two clicks
This commit is contained in:
Alexander Udalov
2014-02-07 18:25:33 +04:00
parent 774e5f0535
commit b2d074c5cc
7 changed files with 179 additions and 1 deletions
@@ -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
@@ -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<PsiElement> {
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<JetParameter> 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<JetFile> 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());
}
};
}
}
@@ -145,7 +145,7 @@ public class MigrateSureInProjectFix extends JetIntentionAction<PsiElement> {
};
}
private static AnalyzeExhaust analyzeFiles(JetFile initialFile, Collection<JetFile> files) {
/* package */ static AnalyzeExhaust analyzeFiles(JetFile initialFile, Collection<JetFile> files) {
AnalyzeExhaust analyzeExhaustHeaders = AnalyzerFacadeProvider.getAnalyzerFacadeForFile(initialFile).analyzeFiles(
initialFile.getProject(),
files,
@@ -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());
@@ -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() = ""
}
@@ -0,0 +1,29 @@
// "Add 'override' to equals, hashCode, toString in project" "true"
class A {
fun <caret>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() = ""
}
@@ -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);
}