s.substring(s.length()-fooLen).equals(foo) -> s.endsWith(foo)

GitOrigin-RevId: 5dbd78e6359770f9680ef25dcf699297b5a28e46
This commit is contained in:
Tagir Valeev
2019-11-24 08:48:09 +07:00
committed by intellij-monorepo-bot
parent 4a2ea169ac
commit 25dc0f385c
4 changed files with 63 additions and 25 deletions

View File

@@ -9,5 +9,7 @@ class X {
if (s.startsWith("xyzt")) { }
if (s.startsWith("xyzt", 1)) { }
if (s.startsWith("xyzt", 1)) { }
if (s.endsWith("...")) {}
if (s.endsWith(s2)) {}
}
}

View File

@@ -9,5 +9,7 @@ class X {
if (s.substring(0, 4).equals("xyzt")) { }
if (s.substring(1, 5).equals("xyzt")) { }
if (s.substring(1, 1+"xyzt".length()).equals("xyzt")) { }
if (s.substring(s.length() - 3).equals("...")) {}
if (s.substring(s.length() - s2.length()).equals(s2)) {}
}
}

View File

@@ -4,7 +4,6 @@ package com.siyeh.ig.psiutils;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.CodeInsightUtilCore;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.PsiEquivalenceUtil;
import com.intellij.codeInspection.dataFlow.ContractReturnValue;
import com.intellij.codeInspection.dataFlow.JavaMethodContractUtil;
import com.intellij.openapi.project.Project;
@@ -1142,8 +1141,9 @@ public class ExpressionUtils {
public static boolean isDifference(@NotNull PsiExpression from, @NotNull PsiExpression to, @NotNull PsiExpression diff) {
diff = PsiUtil.skipParenthesizedExprDown(diff);
if (diff == null) return false;
if (isZero(from) && PsiEquivalenceUtil.areElementsEquivalent(to, diff)) return true;
EquivalenceChecker eq = EquivalenceChecker.getCanonicalPsiEquivalence();
if (isZero(from) && eq.expressionsAreEquivalent(to, diff)) return true;
if (isZero(diff) && eq.expressionsAreEquivalent(to, from)) return true;
if (diff instanceof PsiBinaryExpression && ((PsiBinaryExpression)diff).getOperationTokenType().equals(JavaTokenType.MINUS)) {
PsiExpression left = ((PsiBinaryExpression)diff).getLOperand();
PsiExpression right = ((PsiBinaryExpression)diff).getROperand();
@@ -1151,6 +1151,13 @@ public class ExpressionUtils {
return true;
}
}
if (from instanceof PsiBinaryExpression && ((PsiBinaryExpression)from).getOperationTokenType().equals(JavaTokenType.MINUS)) {
PsiExpression left = ((PsiBinaryExpression)from).getLOperand();
PsiExpression right = ((PsiBinaryExpression)from).getROperand();
if (right != null && eq.expressionsAreEquivalent(to, left) && eq.expressionsAreEquivalent(diff, right)) {
return true;
}
}
if (to instanceof PsiBinaryExpression && ((PsiBinaryExpression)to).getOperationTokenType().equals(JavaTokenType.PLUS)) {
PsiExpression left = ((PsiBinaryExpression)to).getLOperand();
PsiExpression right = ((PsiBinaryExpression)to).getROperand();

View File

@@ -148,7 +148,7 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
return myManager.createProblemDescriptor(anchor, (TextRange)null,
InspectionGadgetsBundle.message("inspection.redundant.string.call.message"),
ProblemHighlightType.LIKE_UNUSED_SYMBOL, myIsOnTheFly,
new RemoveRedundantSubstringFix());
new RemoveRedundantSubstringFix(null));
}
}
return null;
@@ -156,34 +156,56 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
private ProblemDescriptor getRedundantSubstringEqualsProblem(PsiMethodCallExpression call) {
PsiMethodCallExpression qualifierCall = MethodCallUtils.getQualifierMethodCall(call);
if (STRING_SUBSTRING_TWO_ARG.test(qualifierCall) && qualifierCall.getMethodExpression().getQualifierExpression() != null) {
if (qualifierCall == null) return null;
PsiExpression receiver = qualifierCall.getMethodExpression().getQualifierExpression();
if (receiver == null) return null;
if (STRING_SUBSTRING_TWO_ARG.test(qualifierCall)) {
PsiExpression equalTo = call.getArgumentList().getExpressions()[0];
PsiExpression[] args = qualifierCall.getArgumentList().getExpressions();
boolean lengthMatches = lengthMatches(equalTo, args);
boolean lengthMatches = lengthMatches(equalTo, args[0], args[1]);
if (lengthMatches) {
PsiElement anchor = qualifierCall.getMethodExpression().getReferenceNameElement();
if (anchor != null) {
return myManager.createProblemDescriptor(anchor, (TextRange)null,
InspectionGadgetsBundle.message("inspection.redundant.string.call.message"),
ProblemHighlightType.LIKE_UNUSED_SYMBOL, myIsOnTheFly,
new RemoveRedundantSubstringFix());
new RemoveRedundantSubstringFix("startsWith"));
}
}
}
if (STRING_SUBSTRING_ONE_ARG.test(qualifierCall)) {
PsiExpression equalTo = call.getArgumentList().getExpressions()[0];
PsiExpression from = qualifierCall.getArgumentList().getExpressions()[0];
PsiExpression to = getLengthExpression(receiver, JavaPsiFacade.getElementFactory(myHolder.getProject()));
boolean lengthMatches = lengthMatches(equalTo, from, to);
if (lengthMatches) {
PsiElement anchor = qualifierCall.getMethodExpression().getReferenceNameElement();
if (anchor != null) {
return myManager.createProblemDescriptor(anchor, (TextRange)null,
InspectionGadgetsBundle.message("inspection.redundant.string.call.message"),
ProblemHighlightType.LIKE_UNUSED_SYMBOL, myIsOnTheFly,
new RemoveRedundantSubstringFix("endsWith"));
}
}
}
return null;
}
private boolean lengthMatches(PsiExpression equalTo, PsiExpression[] args) {
private boolean lengthMatches(PsiExpression equalTo, PsiExpression from, PsiExpression to) {
String str = tryCast(ExpressionUtils.computeConstantExpression(equalTo), String.class);
PsiElementFactory factory = JavaPsiFacade.getElementFactory(myHolder.getProject());
if (str != null) {
PsiExpression lengthExpression =
factory.createExpressionFromText(String.valueOf(str.length()), equalTo);
if (ExpressionUtils.isDifference(args[0], args[1], lengthExpression)) return true;
if (ExpressionUtils.isDifference(from, to, lengthExpression)) return true;
}
PsiExpression lengthExpression = factory
.createExpressionFromText(ParenthesesUtils.getText(equalTo, ParenthesesUtils.METHOD_CALL_PRECEDENCE) + ".length()", equalTo);
return ExpressionUtils.isDifference(args[0], args[1], lengthExpression);
PsiExpression lengthExpression = getLengthExpression(equalTo, factory);
return ExpressionUtils.isDifference(from, to, lengthExpression);
}
private static PsiExpression getLengthExpression(PsiExpression string, PsiElementFactory factory) {
return factory
.createExpressionFromText(ParenthesesUtils.getText(string, ParenthesesUtils.METHOD_CALL_PRECEDENCE) + ".length()", string);
}
@Nullable
@@ -314,6 +336,20 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
}
private static class RemoveRedundantSubstringFix implements LocalQuickFix {
private final @Nullable String myBindCallName;
RemoveRedundantSubstringFix(@Nullable String bindCallName) {
myBindCallName = bindCallName;
}
@Nls(capitalization = Nls.Capitalization.Sentence)
@NotNull
@Override
public String getName() {
return myBindCallName == null ? getFamilyName() :
"Use '"+myBindCallName+"' and remove redundant 'substring()' call";
}
@Nls(capitalization = Nls.Capitalization.Sentence)
@NotNull
@Override
@@ -332,20 +368,11 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
PsiExpression[] args = substringCall.getArgumentList().getExpressions();
if (args.length == 0) return;
CommentTracker ct = new CommentTracker();
String nextCallName = nextCall.getMethodExpression().getReferenceName();
if (nextCallName == null) return;
switch (nextCallName) {
case "indexOf":
if (!ExpressionUtils.isZero(args[0])) {
nextCall.getArgumentList().add(ct.markUnchanged(args[0]));
}
break;
case "equals":
if (!ExpressionUtils.isZero(args[0])) {
nextCall.getArgumentList().add(ct.markUnchanged(args[0]));
}
ExpressionUtils.bindCallTo(nextCall, "startsWith");
break;
if (!"endsWith".equals(myBindCallName) && !ExpressionUtils.isZero(args[0])) {
nextCall.getArgumentList().add(ct.markUnchanged(args[0]));
}
if (myBindCallName != null) {
ExpressionUtils.bindCallTo(nextCall, myBindCallName);
}
ct.replaceAndRestoreComments(substringCall, stringExpr);
}