IDEA-187224 Add inspection for substring with String#length as second param

This commit is contained in:
Tagir Valeev
2018-02-27 13:05:45 +07:00
parent 5a8ad55613
commit 5feb5cb75a
2 changed files with 41 additions and 25 deletions
@@ -0,0 +1,7 @@
// "Fix all 'Redundant String operation' problems in file" "true"
class Foo {
void test(String s) {
String s1 = s.substring(1);
String s2 = s.substring(2, s1.length());
}
}
@@ -98,35 +98,44 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
private void processSubstring(PsiMethodCallExpression call) {
PsiExpression[] args = call.getArgumentList().getExpressions();
if (isRedundantSubstring(call, args)) {
registerProblem(call, "inspection.redundant.string.call.message");
}
else if (args.length == 2) {
PsiElement parent = PsiUtil.skipParenthesizedExprUp(call.getParent());
if (parent instanceof PsiExpressionList && ((PsiExpressionList)parent).getExpressionCount() == 1) {
PsiMethodCallExpression parentCall = tryCast(parent.getParent(), PsiMethodCallExpression.class);
if (STRING_BUILDER_APPEND.test(parentCall)) {
PsiElement nameElement = Objects.requireNonNull(call.getMethodExpression().getReferenceNameElement());
holder.registerProblem(nameElement, InspectionGadgetsBundle.message("inspection.redundant.string.call.message"),
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
new RemoveRedundantStringCallFix(nameElement.getText(), FixType.REPLACE_WITH_ARGUMENTS));
PsiExpression stringExpression = call.getMethodExpression().getQualifierExpression();
switch (args.length) {
case 1:
if(ExpressionUtils.isZero(args[0])) {
registerProblem(call, "inspection.redundant.string.call.message");
}
}
break;
case 2:
if (isLengthOf(args[1], stringExpression)) {
if (ExpressionUtils.isZero(args[0])) {
registerProblem(call, "inspection.redundant.string.call.message");
} else {
DeleteElementFix fix =
new DeleteElementFix(args[1], InspectionGadgetsBundle.message("inspection.redundant.string.remove.argument.fix.name"));
holder.registerProblem(args[1], InspectionGadgetsBundle.message("inspection.redundant.string.call.message"),
ProblemHighlightType.LIKE_UNUSED_SYMBOL, fix);
}
} else {
PsiElement parent = PsiUtil.skipParenthesizedExprUp(call.getParent());
if (parent instanceof PsiExpressionList && ((PsiExpressionList)parent).getExpressionCount() == 1) {
PsiMethodCallExpression parentCall = tryCast(parent.getParent(), PsiMethodCallExpression.class);
if (STRING_BUILDER_APPEND.test(parentCall)) {
PsiElement nameElement = Objects.requireNonNull(call.getMethodExpression().getReferenceNameElement());
holder.registerProblem(nameElement, InspectionGadgetsBundle.message("inspection.redundant.string.call.message"),
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
new RemoveRedundantStringCallFix(nameElement.getText(), FixType.REPLACE_WITH_ARGUMENTS));
}
}
}
break;
}
}
private boolean isRedundantSubstring(PsiMethodCallExpression call, PsiExpression[] args) {
if (!ExpressionUtils.isZero(args[0])) return false;
if (args.length == 2) {
PsiMethodCallExpression argCall = tryCast(PsiUtil.skipParenthesizedExprDown(args[1]), PsiMethodCallExpression.class);
if (!STRING_LENGTH.test(argCall) ||
!EquivalenceChecker.getCanonicalPsiEquivalence()
.expressionsAreEquivalent(call.getMethodExpression().getQualifierExpression(),
argCall.getMethodExpression().getQualifierExpression())) {
return false;
}
}
return true;
private boolean isLengthOf(PsiExpression stringLengthCandidate, PsiExpression stringExpression) {
PsiMethodCallExpression argCall = tryCast(PsiUtil.skipParenthesizedExprDown(stringLengthCandidate), PsiMethodCallExpression.class);
return STRING_LENGTH.test(argCall) &&
EquivalenceChecker.getCanonicalPsiEquivalence()
.expressionsAreEquivalent(stringExpression, argCall.getMethodExpression().getQualifierExpression());
}
private void registerProblem(PsiMethodCallExpression call, @NotNull @PropertyKey(resourceBundle = BUNDLE) String key) {