mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
ConvertEqualsMethodToStaticIntention merged with EqualsReplaceableByObjectsCallInspection to become a informational level inspection IDEA-157727
This commit is contained in:
-102
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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 com.intellij.codeInsight.intention.impl;
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInsight.intention.BaseElementAtCaretIntentionAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class ConvertEqualsMethodToStaticIntention extends BaseElementAtCaretIntentionAction {
|
||||
private static final Logger LOG = Logger.getInstance(ConvertEqualsMethodToStaticIntention.class);
|
||||
private static final String REPLACE_TEMPLATE = "java.util.Objects.equals(%s, %s)";
|
||||
public static final String TEXT = "Convert '.equals()' to 'java.util.Objects.equals()'";
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
|
||||
if (!(element instanceof PsiIdentifier)) {
|
||||
return false;
|
||||
}
|
||||
if (!PsiUtil.isLanguageLevel7OrHigher(element)) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement referenceExpression = element.getParent();
|
||||
if (!(referenceExpression instanceof PsiReferenceExpression)) {
|
||||
return false;
|
||||
}
|
||||
if (!"equals".equals(((PsiReferenceExpression)referenceExpression).getReferenceName())) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement methodCallExpression = referenceExpression.getParent();
|
||||
if (!(methodCallExpression instanceof PsiMethodCallExpression)) {
|
||||
return false;
|
||||
}
|
||||
final int argumentsCount = ((PsiMethodCallExpression)methodCallExpression).getArgumentList().getExpressions().length;
|
||||
if (argumentsCount != 1) {
|
||||
return false;
|
||||
}
|
||||
final PsiMethod method = ((PsiMethodCallExpression)methodCallExpression).resolveMethod();
|
||||
if (method == null) {
|
||||
return false;
|
||||
}
|
||||
PsiClass javaLangObject = JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_OBJECT, element.getResolveScope());
|
||||
if (javaLangObject == null) {
|
||||
return false;
|
||||
}
|
||||
if (javaLangObject.isEquivalentTo(method.getContainingClass())) {
|
||||
return true;
|
||||
}
|
||||
final PsiMethod[] superMethods = method.findSuperMethods(javaLangObject);
|
||||
return superMethods.length == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
|
||||
if (!FileModificationService.getInstance().preparePsiElementsForWrite(element)) {
|
||||
return;
|
||||
}
|
||||
final PsiElement parent = element.getParent().getParent();
|
||||
LOG.assertTrue(parent instanceof PsiMethodCallExpression);
|
||||
PsiMethodCallExpression methodCall = (PsiMethodCallExpression) parent;
|
||||
final PsiExpression qualifier = methodCall.getMethodExpression().getQualifierExpression();
|
||||
final String qualifierText = qualifier == null ? PsiKeyword.THIS : qualifier.getText();
|
||||
final PsiExpression parameter = methodCall.getArgumentList().getExpressions()[0];
|
||||
final String expressionText = String.format(REPLACE_TEMPLATE, qualifierText, parameter.getText());
|
||||
methodCall.replace(JavaPsiFacade.getElementFactory(project).createExpressionFromText(expressionText, null));
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return TEXT;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getText() {
|
||||
return getFamilyName();
|
||||
}
|
||||
}
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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 com.intellij.codeInsight.intention;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInsight.intention.impl.ConvertCompareToToEqualsIntention;
|
||||
import com.intellij.codeInsight.intention.impl.ConvertEqualsMethodToStaticIntention;
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestUtil;
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
|
||||
|
||||
/**
|
||||
* @author Dmitry Batkovich
|
||||
*/
|
||||
public class ConvertEqualsMethodToStaticTest extends JavaCodeInsightFixtureTestCase {
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return JavaTestUtil.getJavaTestDataPath() + "/codeInsight/convertEqualsMethodToStatic/";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7);
|
||||
}
|
||||
|
||||
public void testSimple() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testComplexQualifierAndArgument() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNotAvailable() {
|
||||
doTestNotAvailable();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
final String name = getTestName(true);
|
||||
CodeInsightTestUtil.doIntentionTest(myFixture, ConvertEqualsMethodToStaticIntention.TEXT, name + ".java", name + "_after.java");
|
||||
}
|
||||
|
||||
private void doTestNotAvailable() {
|
||||
myFixture.configureByFile(getTestName(true) + ".java");
|
||||
assertEmpty(myFixture.filterAvailableIntentions(ConvertEqualsMethodToStaticIntention.TEXT));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1312,7 +1312,7 @@
|
||||
implementationClass="com.siyeh.ig.migration.BigDecimalLegacyMethodInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="EqualsReplaceableByObjectsCall" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="equals.replaceable.by.objects.call.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.language.level.specific.issues.and.migration.aids" enabledByDefault="false" level="WARNING"
|
||||
groupKey="group.names.language.level.specific.issues.and.migration.aids" enabledByDefault="true" level="INFORMATION"
|
||||
implementationClass="com.siyeh.ig.migration.EqualsReplaceableByObjectsCallInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="EnumerationCanBeIteration" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="enumeration.can.be.iteration.display.name" groupBundle="messages.InspectionsBundle"
|
||||
|
||||
+1
@@ -2129,6 +2129,7 @@ dangling.javadoc.delete.quickfix=Remove dangling comment
|
||||
equals.replaceable.by.objects.call.display.name='equals()' expression replaceable by 'Objects.equals()' expression
|
||||
equals.replaceable.by.objects.call.problem.descriptor=<code>#ref</code> replaceable by 'Objects.equals()' expression #loc
|
||||
equals.replaceable.by.objects.call.quickfix=Replace with 'Objects.equals()' expression
|
||||
equals.replaceable.by.objects.check.not.null.option=Report only null safe 'equals' calls
|
||||
array.objects.equals.display.name='Objects.equals()' called on arrays
|
||||
array.objects.equals.problem.descriptor=<code>Objects.#ref()</code> on arrays should probably be 'Arrays.equals()' #loc
|
||||
array.objects.deep.equals.problem.descriptor=<code>Objects.#ref()</code> on arrays should probably be 'Arrays.deepEquals()' #loc
|
||||
|
||||
+43
-12
@@ -16,6 +16,7 @@
|
||||
package com.siyeh.ig.migration;
|
||||
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
@@ -34,10 +35,19 @@ import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public class EqualsReplaceableByObjectsCallInspection extends BaseInspection {
|
||||
public boolean checkNotNull;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message("equals.replaceable.by.objects.check.not.null.option"), this, "checkNotNull");
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@@ -86,10 +96,10 @@ public class EqualsReplaceableByObjectsCallInspection extends BaseInspection {
|
||||
@Override
|
||||
protected void doFix(Project project, ProblemDescriptor descriptor) {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
if (!(element instanceof PsiBinaryExpression)) {
|
||||
if (!(element instanceof PsiBinaryExpression || element instanceof PsiMethodCallExpression)) {
|
||||
return;
|
||||
}
|
||||
final PsiBinaryExpression expression = (PsiBinaryExpression)element;
|
||||
final PsiExpression expression = (PsiExpression)element;
|
||||
if (myEquals) {
|
||||
PsiReplacementUtil.replaceExpressionAndShorten(expression, "java.util.Objects.equals(" + myName1 + "," + myName2 + ")");
|
||||
}
|
||||
@@ -109,41 +119,62 @@ public class EqualsReplaceableByObjectsCallInspection extends BaseInspection {
|
||||
return new EqualsReplaceableByObjectsCallVisitor();
|
||||
}
|
||||
|
||||
private static class EqualsReplaceableByObjectsCallVisitor extends BaseInspectionVisitor {
|
||||
private class EqualsReplaceableByObjectsCallVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitBinaryExpression(PsiBinaryExpression expression) {
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
final PsiElement maybeBinary = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class, PsiPrefixExpression.class);
|
||||
if (maybeBinary instanceof PsiBinaryExpression) {
|
||||
if (processNotNullCheck((PsiBinaryExpression)maybeBinary)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!checkNotNull) {
|
||||
final PsiVariable variable = ExpressionUtils.getVariable(expression.getMethodExpression().getQualifierExpression());
|
||||
if (variable == null) {
|
||||
return;
|
||||
}
|
||||
final PsiVariable otherVariable = getArgumentFromEqualsCallOn(expression, variable);
|
||||
if (otherVariable == null) {
|
||||
return;
|
||||
}
|
||||
registerError(expression, variable.getName(), otherVariable.getName(), true);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processNotNullCheck(PsiBinaryExpression expression) {
|
||||
final IElementType tokenType = expression.getOperationTokenType();
|
||||
if (JavaTokenType.ANDAND.equals(tokenType)) {
|
||||
final PsiVariable variable = ExpressionUtils.getVariableFromNullComparison(expression.getLOperand(), false);
|
||||
if (variable == null) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
final PsiVariable otherVariable = getArgumentFromEqualsCallOn(expression.getROperand(), variable);
|
||||
if (otherVariable == null) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
checkEqualityBefore(expression, true, variable, otherVariable);
|
||||
}
|
||||
else if (JavaTokenType.OROR.equals(tokenType)) {
|
||||
final PsiVariable variable = ExpressionUtils.getVariableFromNullComparison(expression.getLOperand(), true);
|
||||
if (variable == null) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
final PsiExpression rhs = ParenthesesUtils.stripParentheses(expression.getROperand());
|
||||
if (!(rhs instanceof PsiPrefixExpression)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
final PsiPrefixExpression prefixExpression = (PsiPrefixExpression)rhs;
|
||||
if (!JavaTokenType.EXCL.equals(prefixExpression.getOperationTokenType())) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
final PsiVariable otherVariable = getArgumentFromEqualsCallOn(prefixExpression.getOperand(), variable);
|
||||
if (otherVariable == null) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
checkEqualityBefore(expression, false, variable, otherVariable);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void checkEqualityBefore(PsiExpression expression, boolean equals, PsiVariable variable1, PsiVariable variable2) {
|
||||
@@ -161,7 +192,7 @@ public class EqualsReplaceableByObjectsCallInspection extends BaseInspection {
|
||||
registerError(expression, variable1.getName(), variable2.getName(), Boolean.valueOf(equals));
|
||||
}
|
||||
|
||||
private static boolean isEquality(PsiExpression expression, boolean equals, PsiVariable variable1, PsiVariable variable2) {
|
||||
private boolean isEquality(PsiExpression expression, boolean equals, PsiVariable variable1, PsiVariable variable2) {
|
||||
expression = ParenthesesUtils.stripParentheses(expression);
|
||||
if (!(expression instanceof PsiBinaryExpression)) {
|
||||
return false;
|
||||
@@ -183,7 +214,7 @@ public class EqualsReplaceableByObjectsCallInspection extends BaseInspection {
|
||||
(VariableAccessUtils.evaluatesToVariable(lhs, variable2) && VariableAccessUtils.evaluatesToVariable(rhs, variable1));
|
||||
}
|
||||
|
||||
private static PsiVariable getArgumentFromEqualsCallOn(PsiExpression expression, @NotNull PsiVariable variable) {
|
||||
private PsiVariable getArgumentFromEqualsCallOn(PsiExpression expression, PsiVariable variable) {
|
||||
expression = ParenthesesUtils.stripParentheses(expression);
|
||||
if (!(expression instanceof PsiMethodCallExpression)) {
|
||||
return null;
|
||||
|
||||
+1
-1
@@ -635,7 +635,7 @@ public class ExpressionUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PsiVariable getVariable(PsiExpression expression) {
|
||||
public static PsiVariable getVariable(@Nullable PsiExpression expression) {
|
||||
expression = ParenthesesUtils.stripParentheses(expression);
|
||||
if (!(expression instanceof PsiReferenceExpression)) {
|
||||
return null;
|
||||
|
||||
+4
@@ -4,4 +4,8 @@ class EqualsReplaceableByObjectsCall {
|
||||
boolean d = <warning descr="'(a != b) && (a == null || !a.equals(b))' replaceable by 'Objects.equals()' expression">(a != b) && (a == null || !a.equals(b))</warning>;
|
||||
boolean e = <warning descr="'((a) == (b)) || ((a) != (null) && (a).equals((b)))' replaceable by 'Objects.equals()' expression">((a) == (b)) || ((a) != (null) && (a).equals((b)))</warning>;
|
||||
}
|
||||
|
||||
void ignoreNullityCheck(Object a, Object b) {
|
||||
boolean c = <warning descr="'a.equals(b)' replaceable by 'Objects.equals()' expression">a.equals(b)</warning>;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
class EqualsReplaceableByObjectsCall {
|
||||
void yyy(Object a, Object b) {
|
||||
boolean c = <warning descr="'(a != null) && a.equals(b)' replaceable by 'Objects.equals()' expression">(a != null) && a.equals(b)</warning>;
|
||||
boolean d = <warning descr="'(a != b) && (a == null || !a.equals(b))' replaceable by 'Objects.equals()' expression">(a != b) && (a == null || !a.equals(b))</warning>;
|
||||
boolean e = <warning descr="'((a) == (b)) || ((a) != (null) && (a).equals((b)))' replaceable by 'Objects.equals()' expression">((a) == (b)) || ((a) != (null) && (a).equals((b)))</warning>;
|
||||
}
|
||||
|
||||
void ignoreNullityCheck(Object a, Object b) {
|
||||
boolean c = a.equals(b);
|
||||
}
|
||||
}
|
||||
+24
-4
@@ -15,23 +15,43 @@
|
||||
*/
|
||||
package com.siyeh.ig.migration;
|
||||
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel;
|
||||
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl;
|
||||
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
|
||||
import com.siyeh.ig.LightInspectionTestCase;
|
||||
import junit.framework.TestCase;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public class EqualsReplaceableByObjectsCallInspectionTest extends LightInspectionTestCase {
|
||||
private EqualsReplaceableByObjectsCallInspection myInspection = new EqualsReplaceableByObjectsCallInspection();
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
final InspectionProfileImpl profile = (InspectionProfileImpl)InspectionProjectProfileManager.getInstance(getProject()).getInspectionProfile();
|
||||
profile.setErrorLevel(HighlightDisplayKey.find("EqualsReplaceableByObjectsCall"), HighlightDisplayLevel.WARNING, getProject());
|
||||
}
|
||||
|
||||
public void testEqualsReplaceableByObjectsCall() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testEqualsReplaceableByObjectsCallCheckNull() {
|
||||
try {
|
||||
myInspection.checkNotNull = true;
|
||||
doTest();
|
||||
} finally {
|
||||
myInspection.checkNotNull = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected InspectionProfileEntry getInspection() {
|
||||
return new EqualsReplaceableByObjectsCallInspection();
|
||||
protected LocalInspectionTool getInspection() {
|
||||
return myInspection;
|
||||
}
|
||||
}
|
||||
@@ -882,10 +882,6 @@
|
||||
<className>com.intellij.codeInsight.intention.impl.ConvertCompareToToEqualsIntention</className>
|
||||
<category>Java/Control Flow</category>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.intention.impl.ConvertEqualsMethodToStaticIntention</className>
|
||||
<category>Java/Control Flow</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.intention.impl.CreateFieldFromParameterAction</className>
|
||||
|
||||
Reference in New Issue
Block a user