RedundantStringOperationInspection: String constructor can be simplified in case the passed array copied entirely

IDEA-226130

GitOrigin-RevId: d20197f50aeceaea2074e905b94ea7d838d53b4a
This commit is contained in:
Andrey Cherkasov
2022-12-15 12:36:23 +04:00
committed by intellij-monorepo-bot
parent f0efafd51c
commit 3ec4cf4a76
4 changed files with 89 additions and 2 deletions

View File

@@ -0,0 +1,17 @@
// "Fix all 'Redundant 'String' operation' problems in file" "true"
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
class Main {
void foo(char[] chars, byte[] bytes, int[] ints) {
String s1 = new String(bytes);
String s2 = new String(chars);
String s3 = new String(bytes, Charset.defaultCharset());
String s4 = new String(bytes, StandardCharsets.ISO_8859_1);
String s5 = new String(ints, 0, ints.length);
String s6 = new String(chars, 0, bytes.length);
String s7 = new String(bytes, 1, bytes.length, Charset.defaultCharset());
String s8 = new String(bytes, 0, bytes.length - 1, StandardCharsets.ISO_8859_1);
}
}

View File

@@ -0,0 +1,17 @@
// "Fix all 'Redundant 'String' operation' problems in file" "true"
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
class Main {
void foo(char[] chars, byte[] bytes, int[] ints) {
String s1 = new String(bytes, 0, bytes.length<caret>);
String s2 = new String(chars, 0, chars.length);
String s3 = new String(bytes, 0, bytes.length, Charset.defaultCharset());
String s4 = new String(bytes, 0, bytes.length, StandardCharsets.ISO_8859_1);
String s5 = new String(ints, 0, ints.length);
String s6 = new String(chars, 0, bytes.length);
String s7 = new String(bytes, 1, bytes.length, Charset.defaultCharset());
String s8 = new String(bytes, 0, bytes.length - 1, StandardCharsets.ISO_8859_1);
}
}

View File

@@ -2187,6 +2187,7 @@ inspection.redundant.empty.string.argument.message=Unnecessary empty string argu
inspection.redundant.string.length.argument.message=Unnecessary string length argument
inspection.redundant.zero.argument.message=Unnecessary zero argument
inspection.redundant.string.remove.argument.fix.name=Remove argument
inspection.redundant.arguments.message=Unnecessary arguments
inspection.redundant.string.intern.on.constant.message=Call to <code>#ref()</code> on compile-time constant is unnecessary #loc
inspection.redundant.string.constructor.message=<code>new #ref()</code> is redundant #loc
inspection.redundant.string.new.array.message=<code>#ref</code> is redundant #loc

View File

@@ -204,9 +204,39 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myIsOnTheFly, fixes);
}
}
else if (isNewStringCreatedFromEntireArray(params)) {
LocalQuickFix fix = new RemoveRedundantOffsetAndLengthArgumentsFix(params[1], params[2]);
return myManager.createProblemDescriptor(params[1], params[2],
InspectionGadgetsBundle.message("inspection.redundant.arguments.message"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myIsOnTheFly, fix);
}
return null;
}
/**
* Checks that a new string is created from an entire array
*
* @param args arguments passed to the string constructor
*
* @return {@code true} if a new string is created from an entire array and the constructor
* call can be simplified by removing redundant arguments, otherwise - {@code false}
*
* @see String#String(byte[], int, int)
* @see String#String(char[], int, int)
* @see String#String(byte[], int, int, java.nio.charset.Charset)
* @see String#String(byte[], int, int, String)
*/
private static boolean isNewStringCreatedFromEntireArray(PsiExpression[] args) {
if (args.length < 3 || !ExpressionUtils.isZero(args[1])) return false;
PsiExpression arrayExpression = ExpressionUtils.getArrayFromLengthExpression(args[2]);
EquivalenceChecker equivalence = EquivalenceChecker.getCanonicalPsiEquivalence();
if (!equivalence.expressionsAreEquivalent(args[0], arrayExpression)) return false;
return args.length == 3 && (TypeUtils.typeEquals("byte[]", args[0].getType()) || TypeUtils.typeEquals("char[]", args[0].getType())) ||
args.length == 4 &&
TypeUtils.typeEquals("byte[]", args[0].getType()) &&
(TypeUtils.isJavaLangString(args[3].getType()) || TypeUtils.typeEquals(JAVA_NIO_CHARSET_CHARSET, args[3].getType()));
}
private static boolean isNewStringFromByteArrayParams(PsiExpression[] params) {
if (params.length == 0 || !TypeUtils.typeEquals("byte[]", params[0].getType())) {
return false;
@@ -1082,8 +1112,8 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
@NotNull PsiExpression initializer;
private CharArrayCreationArgument(@NotNull PsiNewExpression newExpression,
@NotNull PsiArrayInitializerExpression arrayInitializer,
@NotNull PsiExpression initializer) {
@NotNull PsiArrayInitializerExpression arrayInitializer,
@NotNull PsiExpression initializer) {
this.newExpression = newExpression;
this.arrayInitializer = arrayInitializer;
this.initializer = initializer;
@@ -1105,4 +1135,26 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
return new CharArrayCreationArgument(newExpression, arrayInitializer, initializer);
}
}
private static final class RemoveRedundantOffsetAndLengthArgumentsFix extends LocalQuickFixOnPsiElement {
RemoveRedundantOffsetAndLengthArgumentsFix(PsiElement argument1, PsiElement argument2) {
super(argument1, argument2);
}
@Override
public @NotNull String getText() {
return getFamilyName();
}
@Override
public @NotNull String getFamilyName() {
return QuickFixBundle.message("remove.redundant.arguments.family");
}
@Override
public void invoke(@NotNull Project project, @NotNull PsiFile file, @NotNull PsiElement startElement, @NotNull PsiElement endElement) {
new CommentTracker().delete(startElement, endElement);
}
}
}