mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-05 01:50:56 +07:00
[codeInsight] IDEA-240288 Inspection for StringBuilder.toString().substring()
This patch enhances RedundantStringOperationInspection with detecting either unnecessary naked calls StringBuilder.toString or redundant toString in StringBuilder.toString.substring. Signed-off-by: Nikita Eshkeev <nikita.eshkeev@jetbrains.com> GitOrigin-RevId: 3cd7e964c0acc73fb1ac38061ef31264035f82dc
This commit is contained in:
committed by
intellij-monorepo-bot
parent
43636d4a6e
commit
597a92c0b2
@@ -0,0 +1,86 @@
|
||||
// "Fix all 'Redundant String operation' problems in file" "true"
|
||||
|
||||
class StringBuilderToString {
|
||||
StringBuilderToString() {
|
||||
String s1 = new StringBuilder().toString();
|
||||
/* 1 */
|
||||
String s2 = new StringBuilder()/* 2 */.substring(1);
|
||||
/* 1 */
|
||||
String s3 = new StringBuilder()/* 2 */.substring(1, 4);
|
||||
/* 1 */
|
||||
String s4 = new StringBuilder()/* 2 */.substring(1, 4);
|
||||
/* 1 */
|
||||
int s5 = new StringBuilder()/* 2 */.substring(1, 4).length();
|
||||
|
||||
/* 1 */
|
||||
System.out.println(new StringBuilder()/* 2 */);
|
||||
/* 1 */
|
||||
System.out.println(new StringBuilder()/* 2 */.substring(1));
|
||||
/* 1 */
|
||||
System.out.println(new StringBuilder()/* 2 */.substring(1, 3));
|
||||
/* 1 */
|
||||
System.out.println(new StringBuilder()/* 2 */.substring(1, 3).length());
|
||||
System.out.println(new StringBuilder().substring(1, 3));
|
||||
System.out.println(new StringBuilder().substring(1, 3).length());
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
/* 1 */
|
||||
String s6 = sb/* 2 */ + sb. /* 3 */toString()/* 4 */;
|
||||
/* 1 */
|
||||
String s7 = sb/* 2 */ + sb./* 3 */toString()/* 4 */;
|
||||
String s8 = "Hello, World" + sb.toString();
|
||||
String s8 = ("Hello, " + "World") + sb.toString();
|
||||
String s9 = sb./* 1 */toString()/* 2 */ + 42;
|
||||
/* 1 */
|
||||
String s10 = sb/* 2 */ + "Hello, World";
|
||||
/* 3 */
|
||||
/* 1 */
|
||||
String s11 = sb/* 2 */ + sb/* 4 */ + sb./* 5 */toString()/* 6 */;
|
||||
|
||||
/* 1 */
|
||||
System.out.println(sb/* 2 */ + sb. /* 3 */toString()/* 4 */);
|
||||
/* 1 */
|
||||
System.out.println(sb/* 2 */ + sb./* 3 */toString()/* 4 */);
|
||||
/* 3 */
|
||||
/* 1 */
|
||||
System.out.println(sb/* 2 */ + sb/* 4 */ + sb./* 5 */toString()/* 6 */);
|
||||
System.out.println("Hello, World" + sb.toString());
|
||||
System.out.println(("Hello, " + "World") + sb.toString());
|
||||
System.out.println(sb./* 1 */toString()/* 2 */ + 42);
|
||||
/* 1 */
|
||||
System.out.println(sb/* 2 */ + "Hello, World");
|
||||
|
||||
}
|
||||
void builder(StringBuilder sb) {
|
||||
String s1 = sb.toString();
|
||||
/* 1 */
|
||||
String s2 = sb/* 2 */.substring(1);
|
||||
/* 1 */
|
||||
String s3 = sb/* 2 */.substring(1, 4);
|
||||
/* 1 */
|
||||
String s4 = sb/* 2 */.substring(1, 4);
|
||||
/* 1 */
|
||||
int s5 = sb/* 2 */.substring(1, 4).length();
|
||||
|
||||
/* 1 */
|
||||
String s6 = sb.append(sb)/* 2 */.substring(1);
|
||||
/* 1 */
|
||||
String s7 = (sb/* 2 */ + sb./* 3 */toString()/* 4 */).substring(1);
|
||||
|
||||
/* 1 */
|
||||
System.out.println(sb/* 2 */);
|
||||
/* 1 */
|
||||
System.out.println(sb/* 2 */.substring(1));
|
||||
/* 1 */
|
||||
System.out.println(sb/* 2 */.substring(1, 3));
|
||||
/* 1 */
|
||||
System.out.println(sb/* 2 */.substring(1, 3).length());
|
||||
System.out.println(sb.substring(1, 3));
|
||||
System.out.println(sb.substring(1, 3).length());
|
||||
|
||||
f(sb);
|
||||
f(sb.toString());
|
||||
}
|
||||
void f(StringBuilder s) {}
|
||||
void f(String s) {}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// "Fix all 'Redundant String operation' problems in file" "true"
|
||||
|
||||
class StringBuilderToString {
|
||||
StringBuilderToString() {
|
||||
String s1 = new StringBuilder().toString();
|
||||
String s2 = new StringBuilder()./* 1 */<caret>toString()/* 2 */.substring(1);
|
||||
String s3 = new StringBuilder()./* 1 */toString()/* 2 */.substring(1, 4);
|
||||
String s4 = new StringBuilder()./* 1 */toString()/* 2 */.substring(1, 4);
|
||||
int s5 = new StringBuilder()./* 1 */toString()/* 2 */.substring(1, 4).length();
|
||||
|
||||
System.out.println(new StringBuilder()./* 1 */toString()/* 2 */);
|
||||
System.out.println(new StringBuilder()./* 1 */toString()/* 2 */.substring(1));
|
||||
System.out.println(new StringBuilder()./* 1 */toString()/* 2 */.substring(1, 3));
|
||||
System.out.println(new StringBuilder()./* 1 */toString()/* 2 */.substring(1, 3).length());
|
||||
System.out.println(new StringBuilder().substring(1, 3));
|
||||
System.out.println(new StringBuilder().substring(1, 3).length());
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String s6 = sb./* 1 */toString()/* 2 */ + sb. /* 3 */toString()/* 4 */;
|
||||
String s7 = sb./* 1 */toString()/* 2 */ + sb./* 3 */toString()/* 4 */;
|
||||
String s8 = "Hello, World" + sb.toString();
|
||||
String s8 = ("Hello, " + "World") + sb.toString();
|
||||
String s9 = sb./* 1 */toString()/* 2 */ + 42;
|
||||
String s10 = sb./* 1 */toString()/* 2 */ + "Hello, World";
|
||||
String s11 = sb./* 1 */toString()/* 2 */ + sb./* 3 */toString()/* 4 */ + sb./* 5 */toString()/* 6 */;
|
||||
|
||||
System.out.println(sb./* 1 */toString()/* 2 */ + sb. /* 3 */toString()/* 4 */);
|
||||
System.out.println(sb./* 1 */toString()/* 2 */ + sb./* 3 */toString()/* 4 */);
|
||||
System.out.println(sb./* 1 */toString()/* 2 */ + sb./* 3 */toString()/* 4 */ + sb./* 5 */toString()/* 6 */);
|
||||
System.out.println("Hello, World" + sb.toString());
|
||||
System.out.println(("Hello, " + "World") + sb.toString());
|
||||
System.out.println(sb./* 1 */toString()/* 2 */ + 42);
|
||||
System.out.println(sb./* 1 */toString()/* 2 */ + "Hello, World");
|
||||
|
||||
}
|
||||
void builder(StringBuilder sb) {
|
||||
String s1 = sb.toString();
|
||||
String s2 = sb./* 1 */toString()/* 2 */.substring(1);
|
||||
String s3 = sb./* 1 */toString()/* 2 */.substring(1, 4);
|
||||
String s4 = sb./* 1 */toString()/* 2 */.substring(1, 4);
|
||||
int s5 = sb./* 1 */toString()/* 2 */.substring(1, 4).length();
|
||||
|
||||
String s6 = sb.append(sb)./* 1 */toString()/* 2 */.substring(1);
|
||||
String s7 = (sb./* 1 */toString()/* 2 */ + sb./* 3 */toString()/* 4 */).substring(1);
|
||||
|
||||
System.out.println(sb./* 1 */toString()/* 2 */);
|
||||
System.out.println(sb./* 1 */toString()/* 2 */.substring(1));
|
||||
System.out.println(sb./* 1 */toString()/* 2 */.substring(1, 3));
|
||||
System.out.println(sb./* 1 */toString()/* 2 */.substring(1, 3).length());
|
||||
System.out.println(sb.substring(1, 3));
|
||||
System.out.println(sb.substring(1, 3).length());
|
||||
|
||||
f(sb);
|
||||
f(sb.toString());
|
||||
}
|
||||
void f(StringBuilder s) {}
|
||||
void f(String s) {}
|
||||
}
|
||||
@@ -31,8 +31,7 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT;
|
||||
import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING;
|
||||
import static com.intellij.psi.CommonClassNames.*;
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
import static com.siyeh.InspectionGadgetsBundle.BUNDLE;
|
||||
import static com.siyeh.ig.callMatcher.CallMatcher.*;
|
||||
@@ -50,7 +49,8 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
|
||||
private static final CallMatcher STRING_SUBSTRING_TWO_ARG = exactInstanceCall(JAVA_LANG_STRING, "substring").parameterTypes("int", "int");
|
||||
private static final CallMatcher STRING_SUBSTRING = anyOf(STRING_SUBSTRING_ONE_ARG, STRING_SUBSTRING_TWO_ARG);
|
||||
private static final CallMatcher STRING_BUILDER_APPEND =
|
||||
instanceCall(CommonClassNames.JAVA_LANG_ABSTRACT_STRING_BUILDER, "append").parameterTypes(JAVA_LANG_STRING);
|
||||
instanceCall(JAVA_LANG_ABSTRACT_STRING_BUILDER, "append").parameterTypes(JAVA_LANG_STRING);
|
||||
private static final CallMatcher STRING_BUILDER_TO_STRING = instanceCall(JAVA_LANG_STRING_BUILDER, "toString").parameterCount(0);
|
||||
private static final CallMatcher PRINTSTREAM_PRINTLN = instanceCall("java.io.PrintStream", "println")
|
||||
.parameterTypes(JAVA_LANG_STRING);
|
||||
private static final CallMatcher METHOD_WITH_REDUNDANT_ZERO_AS_SECOND_PARAMETER =
|
||||
@@ -87,6 +87,7 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
|
||||
.register(STRING_TO_STRING, call -> getProblem(call, "inspection.redundant.string.call.message"))
|
||||
.register(STRING_SUBSTRING, this::getSubstringProblem)
|
||||
.register(STRING_BUILDER_APPEND, this::getAppendProblem)
|
||||
.register(STRING_BUILDER_TO_STRING, this::getRedundantStringBuilderToStringProblem)
|
||||
.register(STRING_INTERN, this::getInternProblem)
|
||||
.register(PRINTSTREAM_PRINTLN, call -> getRedundantArgumentProblem(getSingleEmptyStringArgument(call)))
|
||||
.register(METHOD_WITH_REDUNDANT_ZERO_AS_SECOND_PARAMETER, this::getRedundantZeroAsSecondParameterProblem)
|
||||
@@ -116,7 +117,7 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
|
||||
public void visitNewExpression(PsiNewExpression expression) {
|
||||
PsiJavaCodeReferenceElement classRef = expression.getClassReference();
|
||||
ProblemDescriptor descriptor = null;
|
||||
if (ConstructionUtils.isReferenceTo(classRef, CommonClassNames.JAVA_LANG_STRING_BUILDER, CommonClassNames.JAVA_LANG_STRING_BUFFER)) {
|
||||
if (ConstructionUtils.isReferenceTo(classRef, JAVA_LANG_STRING_BUILDER, JAVA_LANG_STRING_BUFFER)) {
|
||||
descriptor = getRedundantArgumentProblem(getSingleEmptyStringArgument(expression));
|
||||
}
|
||||
else if (ConstructionUtils.isReferenceTo(classRef, JAVA_LANG_STRING) && !myInspection.ignoreStringConstructor) {
|
||||
@@ -276,6 +277,30 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
|
||||
return getSingleEmptyStringArgument(call) != null ? getProblem(call, "inspection.redundant.string.call.message") : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ProblemDescriptor getRedundantStringBuilderToStringProblem(@NotNull final PsiMethodCallExpression call) {
|
||||
if (!ExpressionUtils.isConversionToStringNecessary(call, false)) {
|
||||
// report naked `new StringBuilder().toString()`
|
||||
final PsiElement parent = PsiUtil.skipParenthesizedExprUp(call.getParent());
|
||||
if (parent instanceof PsiPolyadicExpression && ((PsiPolyadicExpression)parent).getOperationTokenType() == JavaTokenType.PLUS) {
|
||||
// if there is a polyadic expression where all the operands are `new StringBuilder().toString()`
|
||||
// then it is wrong to report all the `toString` calls as redundant: at least one of them should call
|
||||
// `toString()`, let's choose the last one to remain with `toString()`
|
||||
final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)parent;
|
||||
final PsiExpression lastChild = PsiUtil.skipParenthesizedExprDown(polyadicExpression.getOperands()[polyadicExpression.getOperands().length - 1]);
|
||||
if (lastChild == call) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return getProblem(call, "inspection.redundant.string.call.message");
|
||||
}
|
||||
|
||||
final PsiMethodCallExpression substringCall = PsiTreeUtil.getParentOfType(call, PsiMethodCallExpression.class);
|
||||
if (!STRING_SUBSTRING.test(substringCall)) return null;
|
||||
|
||||
return getProblem(call, "inspection.redundant.string.call.message");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ProblemDescriptor getInternProblem(PsiMethodCallExpression call) {
|
||||
return PsiUtil.isConstantExpression(call.getMethodExpression().getQualifierExpression())
|
||||
|
||||
Reference in New Issue
Block a user