Fixes after review: IDEA-249165

GitOrigin-RevId: 5f90b50bd298dbc73283a6b2e78267483211c111
This commit is contained in:
Andrey.Cherkasov
2020-09-15 21:23:00 +00:00
committed by intellij-monorepo-bot
parent ccd13a4b2d
commit d6ecf8f1f0
7 changed files with 179 additions and 58 deletions
@@ -0,0 +1,30 @@
// "Fix all 'Redundant String operation' problems in file" "true"
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
class Main {
private static ByteArrayOutputStream foo() {
return new ByteArrayOutputStream();
}
public static void main(String[] args) {
Charset charset = Charset.defaultCharset();
ByteArrayOutputStream out1 = new ByteArrayOutputStream();
String s1 = out1.toString(charset);
ByteArrayOutputStream out2 = new ByteArrayOutputStream();
String s2 = out2.toString((charset));
ByteArrayOutputStream out3 = new ByteArrayOutputStream();
String s3 = out3.toString(charset);
ByteArrayOutputStream out4 = new ByteArrayOutputStream();
String s4 = out4.toString((charset));
String s5 = foo().toString(charset);
String s6 = foo().toString((charset));
}
}
@@ -0,0 +1,29 @@
// "Fix all 'Redundant String operation' problems in file" "true"
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
class Main {
private static ByteArrayOutputStream foo() {
return new ByteArrayOutputStream();
}
public static void main(String[] args) throws UnsupportedEncodingException {
String csn = "ISO-8859-1";
ByteArrayOutputStream out1 = new ByteArrayOutputStream();
String s1 = out1.toString(csn);
ByteArrayOutputStream out2 = new ByteArrayOutputStream();
String s2 = out2.toString((csn));
ByteArrayOutputStream out3 = new ByteArrayOutputStream();
String s3 = out3.toString(csn);
ByteArrayOutputStream out4 = new ByteArrayOutputStream();
String s4 = out4.toString((csn));
String s5 = foo().toString(csn);
String s6 = foo().toString((csn));
}
}
@@ -0,0 +1,32 @@
// "Fix all 'Redundant String operation' problems in file" "true"
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
class Main {
private static ByteArrayOutputStream foo() {
return new ByteArrayOutputStream();
}
public static void main(String[] args) {
Charset charset = Charset.defaultCharset();
ByteArrayOutputStream out1 = new ByteArrayOutputStream();
byte[] result1 = out1.toByteArray();
String s1 = new String(result1, charset);
ByteArrayOutputStream out2 = new ByteArrayOutputStream();
byte[] result2 = out2.toByteArray();
String s2 = new String((result2), (charset));
ByteArrayOutputStream out3 = new ByteArrayOutputStream();
String s3 = new String(out3.toByteArray(), charset);
ByteArrayOutputStream out4 = new ByteArrayOutputStream();
String s4 = new String((out4.toByteArray()), (charset));
String s5 = new String(foo().toByteArray(), charset);
String s6 = new String((foo().toByteArray()), (charset<caret>));
}
}
@@ -0,0 +1,31 @@
// "Fix all 'Redundant String operation' problems in file" "true"
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
class Main {
private static ByteArrayOutputStream foo() {
return new ByteArrayOutputStream();
}
public static void main(String[] args) throws UnsupportedEncodingException {
String csn = "ISO-8859-1";
ByteArrayOutputStream out1 = new ByteArrayOutputStream();
byte[] result1 = out1.toByteArray();
String s1 = new String(result1, csn);
ByteArrayOutputStream out2 = new ByteArrayOutputStream();
byte[] result2 = out2.toByteArray();
String s2 = new String((result2), (csn));
ByteArrayOutputStream out3 = new ByteArrayOutputStream();
String s3 = new String(out3.toByteArray(), csn);
ByteArrayOutputStream out4 = new ByteArrayOutputStream();
String s4 = new String((out4.toByteArray()), (csn));
String s5 = new String(foo().toByteArray(), csn);
String s6 = new String((foo().toByteArray()), (csn<caret>));
}
}
@@ -107,6 +107,8 @@ public interface CommonClassNames {
String JAVA_LANG_NULL_POINTER_EXCEPTION = "java.lang.NullPointerException";
String JAVA_NIO_CHARSET_CHARSET = "java.nio.charset.Charset";
String JAVA_UTIL_CONCURRENT_FUTURE = "java.util.concurrent.Future";
String JAVA_UTIL_CONCURRENT_CALLABLE = "java.util.concurrent.Callable";
String JAVA_UTIL_CONCURRENT_COMPLETABLE_FUTURE = "java.util.concurrent.CompletableFuture";
@@ -2442,5 +2442,4 @@ convert.junit3.test.fix.conflict.semantics=Method call {0} may change semantics
convert.junit3.test.fix.conflict.compile=Method call {0} will not compile when {1} is converted to JUnit 4
convert.junit3.test.fix.conflict.compile.2=Reference {0} will not compile when {1} is converted to JUnit 4
junit5.convert.fix.conflict.inheritor=Class {0} can''t be converted to JUnit 5, cause there are incompatible inheritor(s): {1}
inspection.byte.array.output.stream.to.string.message=Inefficient conversion from ByteArrayOutputStream
inspection.byte.array.output.stream.to.string.fix.name=Replace with ByteArrayOutputStream.toString()
inspection.byte.array.output.stream.to.string.message=Inefficient conversion from ByteArrayOutputStream
@@ -12,7 +12,6 @@ import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiLiteralUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
@@ -25,6 +24,7 @@ import com.siyeh.ig.psiutils.*;
import org.jetbrains.annotations.*;
import javax.swing.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -42,7 +42,7 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
REPLACE_WITH_ARGUMENTS
}
private static final CallMatcher BYTE_ARRAY_OUTPUT_STREAM_INTO_STRING =
private static final CallMatcher BYTE_ARRAY_OUTPUT_STREAM_INTO_BYTE_ARRAY =
exactInstanceCall(JAVA_IO_BYTE_ARRAY_OUTPUT_STREAM, "toByteArray").parameterCount(0);
private static final CallMatcher STRING_TO_STRING = exactInstanceCall(JAVA_LANG_STRING, "toString").parameterCount(0);
private static final CallMatcher STRING_INTERN = exactInstanceCall(JAVA_LANG_STRING, "intern").parameterCount(0);
@@ -148,6 +148,26 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
InspectionGadgetsBundle.message("inspection.redundant.string.constructor.message"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myIsOnTheFly, fixes);
}
final PsiExpression[] params = args.getExpressions();
if (isNewStringFromByteArrayParams(params)) {
PsiMethodCallExpression methodCall = tryCast(ExpressionUtils.resolveExpression(params[0]), PsiMethodCallExpression.class);
if (methodCall == null) return null;
if (BYTE_ARRAY_OUTPUT_STREAM_INTO_BYTE_ARRAY.test(methodCall)) {
final TextRange range = new TextRange(0, expression.getTextLength());
final PsiElement qualifier = methodCall.getMethodExpression().getQualifier();
if (qualifier == null) return null;
String newExpressionText = qualifier.getText() + ".toString(" + (params.length == 2 ? params[1].getText() : "") + ")";
final LocalQuickFix fix = new ByteArrayOutputStreamToStringFix(newExpressionText);
return myManager.createProblemDescriptor(expression, range,
InspectionGadgetsBundle.message("inspection.byte.array.output.stream.to.string.message"),
ProblemHighlightType.WARNING, myIsOnTheFly, fix);
}
}
if (args.getExpressionCount() == 1) {
PsiExpression arg = args.getExpressions()[0];
if (TypeUtils.isJavaLangString(arg.getType()) &&
@@ -161,47 +181,22 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
return myManager.createProblemDescriptor(expression, range,
InspectionGadgetsBundle.message("inspection.redundant.string.constructor.message"),
ProblemHighlightType.LIKE_UNUSED_SYMBOL, myIsOnTheFly, fixes);
} else if (TypeUtils.typeEquals("byte[]", arg.getType())) {
arg = PsiUtil.skipParenthesizedExprDown(arg);
final ProblemDescriptor descriptor = getByteArrayOutputStreamToStringProblem(expression, arg, null);
if (descriptor != null) return descriptor;
if (!(arg instanceof PsiReferenceExpression)) return null;
final PsiElement intermediateArrayCandidate = ((PsiReferenceExpression)arg).resolve();
if (intermediateArrayCandidate == null) return null;
if (ReferencesSearch.search(intermediateArrayCandidate).findAll().size() != 1) return null;
if (intermediateArrayCandidate instanceof PsiLocalVariable) {
final PsiExpression initializer = ((PsiLocalVariable) intermediateArrayCandidate).getInitializer();
return getByteArrayOutputStreamToStringProblem(expression, initializer, intermediateArrayCandidate);
}
}
}
return null;
}
private ProblemDescriptor getByteArrayOutputStreamToStringProblem(
PsiNewExpression expression,
PsiExpression methodCallCandidate,
PsiElement intermediateArray
) {
if (methodCallCandidate instanceof PsiMethodCallExpression &&
BYTE_ARRAY_OUTPUT_STREAM_INTO_STRING.test((PsiMethodCallExpression)methodCallCandidate)) {
final TextRange range = new TextRange(0, expression.getTextLength());
final PsiElement qualifier = ((PsiMethodCallExpression) methodCallCandidate).getMethodExpression().getQualifier();
if (qualifier == null) return null;
final LocalQuickFix fix = new ByteArrayOutputStreamToStringFix(qualifier.getText(), intermediateArray);
return myManager.createProblemDescriptor(expression, range,
InspectionGadgetsBundle.message("inspection.byte.array.output.stream.to.string.message"),
ProblemHighlightType.WARNING, myIsOnTheFly, fix);
private static boolean isNewStringFromByteArrayParams(PsiExpression[] params) {
final List<String> targetTypes = Arrays.asList(JAVA_LANG_STRING, JAVA_NIO_CHARSET_CHARSET);
if (params.length == 0 || !TypeUtils.typeEquals("byte[]", params[0].getType())) {
return false;
}
return null;
if (params.length == 1) return true;
if (params.length == 2) {
PsiType type = params[1].getType();
return type != null && targetTypes.contains(type.getCanonicalText());
}
return false;
}
private ProblemDescriptor getRedundantCaseEqualsProblem(PsiMethodCallExpression call) {
@@ -890,7 +885,8 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
@Override
public void doFix(Project project, ProblemDescriptor descriptor) {
final PsiNewExpression expression = (PsiNewExpression)descriptor.getPsiElement();
final PsiNewExpression expression = tryCast(descriptor.getPsiElement(), PsiNewExpression.class);
if (expression == null) return;
final PsiExpressionList argList = expression.getArgumentList();
if (argList == null) return;
final PsiExpression[] args = argList.getExpressions();
@@ -902,23 +898,16 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
}
private static final class ByteArrayOutputStreamToStringFix extends InspectionGadgetsFix {
private final String elementToString;
private final SmartPsiElementPointer<PsiElement> intermediateArrayPointer;
private final String myText;
private ByteArrayOutputStreamToStringFix(String s, PsiElement intermediateArray) {
this.elementToString = s;
if (intermediateArray == null) {
intermediateArrayPointer = null;
} else {
final SmartPointerManager pointerManager = SmartPointerManager.getInstance(intermediateArray.getProject());
intermediateArrayPointer = pointerManager.createSmartPsiElementPointer(intermediateArray);
}
private ByteArrayOutputStreamToStringFix(String text) {
this.myText = text;
}
@Override
@NotNull
public String getName() {
return InspectionGadgetsBundle.message("inspection.byte.array.output.stream.to.string.fix.name");
return CommonQuickFixBundle.message("fix.replace.with.x", myText);
}
@NotNull
@@ -929,13 +918,22 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
@Override
public void doFix(Project project, ProblemDescriptor descriptor) {
if (elementToString == null) return;
final PsiNewExpression expression = (PsiNewExpression)descriptor.getPsiElement();
PsiReplacementUtil.replaceExpression(expression, elementToString + ".toString()", new CommentTracker());
if (intermediateArrayPointer == null) return;
final PsiElement intermediateArray = intermediateArrayPointer.getElement();
if (intermediateArray == null) return;
deleteElement(intermediateArray);
final PsiNewExpression expression = tryCast(descriptor.getPsiElement(), PsiNewExpression.class);
if (expression == null) return;
final PsiExpressionList args = expression.getArgumentList();
if (args == null) return;
final PsiExpression[] params = args.getExpressions();
if (!(params.length == 1 || params.length == 2)) return;
PsiMethodCallExpression resolvedExpression = tryCast(ExpressionUtils.resolveExpression(params[0]), PsiMethodCallExpression.class);
if (resolvedExpression == null) return;
PsiElement parent = tryCast(resolvedExpression.getParent(), PsiLocalVariable.class);
if (parent != null) deleteElement(parent);
PsiReplacementUtil.replaceExpression(expression, myText, new CommentTracker());
}
}
}