java: report string.toCharArray().length -> string.length() (IDEA-351174)

for "Redundant 'String' operation" inspection

GitOrigin-RevId: 96c3b5d310b9639c74241f48348257bbb83dbe93
This commit is contained in:
Bas Leijdekkers
2024-04-10 18:02:39 +02:00
committed by intellij-monorepo-bot
parent b686093c55
commit 0b1872f794
5 changed files with 61 additions and 2 deletions

View File

@@ -2185,6 +2185,7 @@ inspection.redundant.string.replace.with.empty.fix.name=Replace with empty strin
inspection.redundant.string.option.do.not.report.string.constructors=Do not report String constructor calls
inspection.redundant.string.option.do.not.report.single.argument.substring=Do not report redundant single argument substring() calls
inspection.x.call.can.be.replaced.with.y=<code>#ref()</code> call can be replaced with ''{0}()''
remove.unnecessary.0.call.quickfix=Remove unnecessary ''{0}()'' call
inspection.type.may.be.weakened.display.name=Type may be weakened
inspection.type.may.be.weakened.problem.descriptor=Type of variable <code>#ref</code> may be weakened to {0} #loc

View File

@@ -81,8 +81,9 @@ public final class RedundantStringOperationInspection extends AbstractBaseJavaLo
private static final CallMatcher CHANGE_CASE = anyOf(exactInstanceCall(JAVA_LANG_STRING, "toLowerCase").parameterCount(0),
exactInstanceCall(JAVA_LANG_STRING, "toUpperCase").parameterCount(0));
private static final CallMatcher STRING_VALUE_OF = staticCall(JAVA_LANG_STRING, "valueOf").parameterTypes("char[]");
private static final CallMatcher STRIP =
private static final CallMatcher STRING_STRIP =
exactInstanceCall(JAVA_LANG_STRING, "strip", "stripLeading", "stripTrailing").parameterCount(0);
private static final CallMatcher STRING_TO_CHAR_ARRAY = exactInstanceCall(JAVA_LANG_STRING, "toCharArray").parameterCount(0);
public boolean ignoreStringConstructor = false;
public boolean ignoreSingleArgSubstring = true;
@@ -160,6 +161,19 @@ public final class RedundantStringOperationInspection extends AbstractBaseJavaLo
}
}
@Override
public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) {
PsiExpression qualifier = PsiUtil.skipParenthesizedExprDown(expression.getQualifierExpression());
if (!(qualifier instanceof PsiMethodCallExpression call) ||
!"length".equals(expression.getReferenceName()) ||
!STRING_TO_CHAR_ARRAY.test(call)) {
return;
}
myHolder.registerProblem(Objects.requireNonNull(call.getMethodExpression().getReferenceNameElement()),
InspectionGadgetsBundle.message("unnecessary.tostring.call.problem.descriptor"),
new RemoveToCharArrayCallFix());
}
@Override
public void visitTemplateExpression(@NotNull PsiTemplateExpression element) {
if (!PsiUtil.isAvailable(JavaFeature.STRING_TEMPLATES, element) || element.getLiteralExpression() == null) {
@@ -472,7 +486,7 @@ public final class RedundantStringOperationInspection extends AbstractBaseJavaLo
@Nullable
private ProblemDescriptor getStripIsEmptyProblem(PsiMethodCallExpression call) {
PsiMethodCallExpression qualifierCall = MethodCallUtils.getQualifierMethodCall(call);
if (!STRIP.test(qualifierCall)) return null;
if (!STRING_STRIP.test(qualifierCall)) return null;
PsiElement anchor = qualifierCall.getMethodExpression().getReferenceNameElement();
if (anchor == null) return null;
String message = InspectionGadgetsBundle.message("inspection.x.call.can.be.replaced.with.y", "isBlank");
@@ -1234,4 +1248,32 @@ public final class RedundantStringOperationInspection extends AbstractBaseJavaLo
}
}
}
private static class RemoveToCharArrayCallFix extends PsiUpdateModCommandQuickFix {
@Override
public @NotNull String getFamilyName() {
return InspectionGadgetsBundle.message("remove.unnecessary.0.call.quickfix", "toCharArray");
}
@Override
protected void applyFix(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) {
PsiElement parent = element.getParent();
if (!(parent instanceof PsiReferenceExpression ref)) {
return;
}
PsiElement grandParent = parent.getParent();
if (!(grandParent instanceof PsiMethodCallExpression)) {
return;
}
PsiElement greatGrandParent = grandParent.getParent();
if (!(greatGrandParent instanceof PsiReferenceExpression)) {
return;
}
PsiExpression qualifier = ref.getQualifierExpression();
if (qualifier == null) {
return;
}
new CommentTracker().replaceAndRestoreComments(greatGrandParent, qualifier.getText() + ".length()");
}
}
}

View File

@@ -0,0 +1,6 @@
// "Remove unnecessary 'toCharArray()' call" "true-preview"
class Foo {
public void x(String s) {
return s.length();
}
}

View File

@@ -0,0 +1,6 @@
// "Remove unnecessary 'toCharArray()' call" "true-preview"
class Foo {
public void x(String s) {
return s.<caret>toCharArray().length;
}
}

View File

@@ -26,4 +26,8 @@ class Substring {
void m(StringBuilder sb, StringBuilder chars) {
sb.append(chars.<warning descr="Call to 'substring()' is redundant">substring</warning>(1, 3));
}
int z(String s) {
return s.<warning descr="Unnecessary 'toCharArray()' call">toCharArray</warning>().length;
}
}