diff options
Diffstat (limited to 'plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IndexOfReplaceableByContainsInspection.java')
-rw-r--r-- | plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IndexOfReplaceableByContainsInspection.java | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IndexOfReplaceableByContainsInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IndexOfReplaceableByContainsInspection.java new file mode 100644 index 000000000000..bd7acc861042 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IndexOfReplaceableByContainsInspection.java @@ -0,0 +1,272 @@ +/* + * Copyright 2005-2011 Bas Leijdekkers + * + * 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.siyeh.ig.migration; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.HardcodedMethodConstants; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.InspectionGadgetsFix; +import com.siyeh.ig.psiutils.ComparisonUtils; +import com.siyeh.ig.psiutils.ExpressionUtils; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class IndexOfReplaceableByContainsInspection + extends BaseInspection { + + @Override + public boolean isEnabledByDefault() { + return true; + } + + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "indexof.replaceable.by.contains.display.name"); + } + + @Override + @NotNull + public String buildErrorString(Object... infos) { + final PsiBinaryExpression expression = (PsiBinaryExpression)infos[0]; + final PsiExpression lhs = expression.getLOperand(); + final String text; + if (lhs instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression callExpression = + (PsiMethodCallExpression)lhs; + text = createContainsExpressionText(callExpression, false, + expression.getOperationTokenType()); + } + else { + final PsiMethodCallExpression callExpression = + (PsiMethodCallExpression)expression.getROperand(); + assert callExpression != null; + text = createContainsExpressionText(callExpression, true, + expression.getOperationTokenType()); + } + return InspectionGadgetsBundle.message( + "expression.can.be.replaced.problem.descriptor", text); + } + + @Override + @Nullable + protected InspectionGadgetsFix buildFix(Object... infos) { + return new IndexOfReplaceableByContainsFix(); + } + + private static class IndexOfReplaceableByContainsFix + extends InspectionGadgetsFix { + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) + throws IncorrectOperationException { + final PsiElement element = descriptor.getPsiElement(); + if (!(element instanceof PsiBinaryExpression)) { + return; + } + final PsiBinaryExpression expression = + (PsiBinaryExpression)element; + final PsiExpression lhs = expression.getLOperand(); + final PsiExpression rhs = expression.getROperand(); + final String newExpressionText; + if (lhs instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression callExpression = + (PsiMethodCallExpression)lhs; + newExpressionText = + createContainsExpressionText(callExpression, false, + expression.getOperationTokenType()); + } + else if (rhs instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression callExpression = + (PsiMethodCallExpression)rhs; + newExpressionText = + createContainsExpressionText(callExpression, true, + expression.getOperationTokenType()); + } + else { + return; + } + replaceExpression(expression, newExpressionText); + } + + @Override + @NotNull + public String getName() { + return InspectionGadgetsBundle.message( + "replace.indexof.with.contains.quickfix"); + } + + @Override + @NotNull + public String getFamilyName() { + return getName(); + } + + } + + static String createContainsExpressionText( + @NotNull PsiMethodCallExpression call, + boolean flipped, IElementType tokenType) { + final PsiReferenceExpression methodExpression = + call.getMethodExpression(); + final PsiExpression qualifierExpression = + methodExpression.getQualifierExpression(); + final String qualifierText; + if (qualifierExpression == null) { + qualifierText = ""; + } + else { + qualifierText = qualifierExpression.getText(); + } + final PsiExpressionList argumentList = call.getArgumentList(); + final PsiExpression expression = argumentList.getExpressions()[0]; + @NonNls final String newExpressionText = + qualifierText + ".contains(" + expression.getText() + ')'; + if (tokenType.equals(JavaTokenType.EQEQ)) { + return '!' + newExpressionText; + } + else if (!flipped && (tokenType.equals(JavaTokenType.LT) || + tokenType.equals(JavaTokenType.LE))) { + return '!' + newExpressionText; + } + else if (flipped && (tokenType.equals(JavaTokenType.GT) || + tokenType.equals(JavaTokenType.GE))) { + return '!' + newExpressionText; + } + return newExpressionText; + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new IndexOfReplaceableByContainsVisitor(); + } + + private static class IndexOfReplaceableByContainsVisitor + extends BaseInspectionVisitor { + + @Override + public void visitBinaryExpression( + PsiBinaryExpression expression) { + if (!PsiUtil.isLanguageLevel5OrHigher(expression)) { + return; + } + super.visitBinaryExpression(expression); + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return; + } + if (!ComparisonUtils.isComparison(expression)) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + if (lhs instanceof PsiMethodCallExpression) { + if (canBeReplacedByContains(lhs, rhs, false, + expression.getOperationTokenType())) { + registerError(expression, expression); + } + } + else if (rhs instanceof PsiMethodCallExpression) { + if (canBeReplacedByContains(rhs, lhs, true, + expression.getOperationTokenType())) { + registerError(expression, expression); + } + } + } + + private static boolean canBeReplacedByContains( + PsiExpression lhs, + PsiExpression rhs, boolean flipped, IElementType tokenType) { + final PsiMethodCallExpression callExpression = + (PsiMethodCallExpression)lhs; + if (!isIndexOfCall(callExpression)) { + return false; + } + final Object object = + ExpressionUtils.computeConstantExpression(rhs); + if (!(object instanceof Integer)) { + return false; + } + final Integer integer = (Integer)object; + final int constant = integer.intValue(); + if (flipped) { + if (constant == -1 && (JavaTokenType.NE.equals(tokenType) || + JavaTokenType.LT.equals(tokenType) || + JavaTokenType.EQEQ.equals(tokenType) || + JavaTokenType.GE.equals(tokenType))) { + return true; + } + else if (constant == 0 && + (JavaTokenType.LE.equals(tokenType) || + JavaTokenType.GT.equals(tokenType))) { + return true; + } + } + else { + if (constant == -1 && (JavaTokenType.NE.equals(tokenType) || + JavaTokenType.GT.equals(tokenType) || + JavaTokenType.EQEQ.equals(tokenType) || + JavaTokenType.LE.equals(tokenType))) { + return true; + } + else if (constant == 0 && + (JavaTokenType.GE.equals(tokenType) || + JavaTokenType.LT.equals(tokenType))) { + return true; + } + } + return false; + } + + private static boolean isIndexOfCall( + @NotNull PsiMethodCallExpression expression) { + final PsiReferenceExpression methodExpression = + expression.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if (!HardcodedMethodConstants.INDEX_OF.equals(methodName)) { + return false; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + final PsiExpression[] arguments = argumentList.getExpressions(); + if (arguments.length != 1) { + return false; + } + final PsiType argumentType = arguments[0].getType(); + if (argumentType == null || + !argumentType.equalsToText( + CommonClassNames.JAVA_LANG_STRING)) { + return false; + } + final PsiExpression qualifier = + methodExpression.getQualifierExpression(); + if (qualifier == null) { + return false; + } + final PsiType qualifierType = qualifier.getType(); + return qualifierType != null && + qualifierType.equalsToText(CommonClassNames.JAVA_LANG_STRING); + } + } +} |