Fixes after code review: IDEA-249165

GitOrigin-RevId: db35ebb920618b5e2105715406c1e24eb50bb71a
This commit is contained in:
Andrey.Cherkasov
2020-09-08 07:31:16 +00:00
committed by intellij-monorepo-bot
parent e7d0dd4021
commit 080b533383
15 changed files with 276 additions and 78 deletions
+1 -1
View File
@@ -1375,7 +1375,7 @@
implementationClass="com.intellij.codeInspection.RedundantExplicitCloseInspection"/>
<localInspection groupPath="Java" language="JAVA" shortName="RedundantFileCreation"
groupBundle="messages.InspectionsBundle"
groupKey="group.names.declaration.redundancy" enabledByDefault="true" level="WARNING"
groupKey="group.names.verbose.or.redundant.code.constructs" enabledByDefault="true" level="WARNING"
bundle="messages.JavaBundle"
key="inspection.redundant.file.creation.display.name"
implementationClass="com.intellij.codeInspection.RedundantFileCreationInspection"/>
@@ -5,12 +5,17 @@ import com.intellij.java.JavaBundle;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.siyeh.ig.PsiReplacementUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.CommentTracker;
import com.siyeh.ig.psiutils.TypeUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.List;
public class RedundantFileCreationInspection extends AbstractBaseJavaLocalInspectionTool {
@NotNull
@@ -22,33 +27,33 @@ public class RedundantFileCreationInspection extends AbstractBaseJavaLocalInspec
public void visitNewExpression(PsiNewExpression newExpression) {
super.visitNewExpression(newExpression);
final String[] targetTypes = new String[] {
"java.io.FileInputStream", "java.io.FileOutputStream", "java.io.FileReader","java.io.FileWriter",
"java.io.PrintStream", "java.io.PrintWriter", "java.util.Formatter"
};
final List<String> targetTypes = Arrays.asList(
CommonClassNames.JAVA_IO_FILE_INPUT_STREAM, CommonClassNames.JAVA_IO_FILE_OUTPUT_STREAM,
CommonClassNames.JAVA_IO_FILE_READER, CommonClassNames.JAVA_IO_FILE_WRITER,
CommonClassNames.JAVA_IO_PRINT_STREAM, CommonClassNames.JAVA_IO_PRINT_WRITER,
CommonClassNames.JAVA_UTIL_FORMATTER
);
final PsiType type = newExpression.getType();
if (!TypeUtils.typeEquals(type, targetTypes)) {
if (type == null || !targetTypes.contains(type.getCanonicalText())) {
return;
}
final PsiMethod streamConstructor = newExpression.resolveConstructor();
if (streamConstructor == null) return;
final PsiParameter[] streamParams = streamConstructor.getParameterList().getParameters();
if (streamParams.length != 1) return;
final PsiMethod constructor = newExpression.resolveConstructor();
if (constructor == null || !canReplacedWithConstructorTakesFilename(constructor)) return;
final PsiParameter[] params = constructor.getParameterList().getParameters();
if (!TypeUtils.typeEquals("java.io.File", streamParams[0].getType())) return;
if (!TypeUtils.typeEquals(CommonClassNames.JAVA_IO_FILE, params[0].getType())) return;
final PsiExpressionList streamArgList = newExpression.getArgumentList();
if (streamArgList == null) return;
final PsiExpressionList argList = newExpression.getArgumentList();
if (argList == null) return;
final PsiExpression[] streamArgs = streamArgList.getExpressions();
if (streamArgs.length != 1) return;
final PsiExpression[] args = argList.getExpressions();
PsiExpression streamArg = streamArgs[0];
if (!(streamArg instanceof PsiNewExpression)) return;
PsiNewExpression arg = ObjectUtils.tryCast(PsiUtil.skipParenthesizedExprDown(args[0]), PsiNewExpression.class);
if (arg == null) return;
final PsiMethod fileConstructor = ((PsiNewExpression)streamArg).resolveConstructor();
final PsiMethod fileConstructor = arg.resolveConstructor();
if (fileConstructor == null) return;
final PsiParameter[] fileParams = fileConstructor.getParameterList().getParameters();
@@ -56,10 +61,10 @@ public class RedundantFileCreationInspection extends AbstractBaseJavaLocalInspec
if (!TypeUtils.isJavaLangString(fileParams[0].getType())) return;
PsiExpressionList fileArgList = ((PsiNewExpression)streamArg).getArgumentList();
PsiExpressionList fileArgList = arg.getArgumentList();
if (fileArgList == null) return;
holder.registerProblem(streamArg,
holder.registerProblem(arg,
JavaBundle.message("inspection.redundant.file.creation.description"),
ProblemHighlightType.LIKE_UNUSED_SYMBOL,
new TextRange(0, fileArgList.getStartOffsetInParent()),
@@ -69,6 +74,23 @@ public class RedundantFileCreationInspection extends AbstractBaseJavaLocalInspec
};
}
private static boolean canReplacedWithConstructorTakesFilename(PsiMethod method) {
PsiClass containingClass = method.getContainingClass();
if (containingClass == null) return false;
List<PsiType> methodParams = ContainerUtil.map(method.getParameterList().getParameters(), param -> param.getType());
for (final PsiMethod candidate : containingClass.getMethods()) {
if (!candidate.isConstructor()) continue;
List<PsiType> candidateParams = ContainerUtil.map(candidate.getParameterList().getParameters(), param -> param.getType());
if (candidateParams.size() != methodParams.size()) continue;
if (methodParams.subList(1, methodParams.size()).equals(candidateParams.subList(1, candidateParams.size()))) {
return true;
}
}
return false;
}
private static class DeleteRedundantFileCreationFix implements LocalQuickFix {
@Nls
@NotNull
@@ -80,19 +102,18 @@ public class RedundantFileCreationInspection extends AbstractBaseJavaLocalInspec
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
assert element instanceof PsiNewExpression;
if (!(element instanceof PsiNewExpression)) return;
final PsiNewExpression newExpression = (PsiNewExpression)descriptor.getPsiElement();
final PsiNewExpression newExpression = (PsiNewExpression)element;
final PsiExpressionList argList = newExpression.getArgumentList();
assert argList != null;
if (argList == null) return;
final PsiExpression[] args = argList.getExpressions();
assert args.length == 1;
if (args.length != 1) return;
CommentTracker commentTracker = new CommentTracker();
final String argText = commentTracker.text(args[0]);
PsiReplacementUtil.replaceExpression(newExpression, argText, commentTracker);
commentTracker.replace(newExpression, args[0]);
}
}
}
@@ -1,8 +1,13 @@
<html>
<body>
Redundant File creation in a stream constructor
Reports redundant file creation when the stream constructor that takes a path could be used.
<p>The quick-fix replaces the constructor call with a <code>String</code> literal that represents the path, for example:</p>
<pre>
<code>InputStream is = new FileInputStream(new File("in.txt")); // before
InputStream is = new FileInputStream("in.txt"); // after
</code>
</pre>
<!-- tooltip end -->
<p>
</body>
</html>
</html>
@@ -0,0 +1,40 @@
// "Fix all 'Redundant File object creation' problems in file" "true"
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Formatter;
import java.util.Locale;
class Main {
private static String getSomePathname() {
return "Some pathname";
}
public void main(String[] args) throws IOException {
new FileOutputStream("in.txt", false);
new FileReader("in.txt", Charset.defaultCharset());
new FileWriter("in.txt", true);
new FileWriter("in.txt", Charset.defaultCharset());
new FileWriter("in.txt", Charset.defaultCharset(), false);
new PrintStream("in.txt", StandardCharsets.UTF_16.displayName());
new PrintStream("in.txt", Charset.defaultCharset());
new PrintWriter("in.txt", StandardCharsets.UTF_16.displayName());
new PrintWriter("in.txt", StandardCharsets.UTF_16.displayName());
new Formatter("in.txt", StandardCharsets.UTF_16.displayName());
new Formatter("in.txt", StandardCharsets.UTF_16.displayName(), Locale.ENGLISH);
new Formatter("in.txt", Charset.defaultCharset(), Locale.GERMAN);
new FileOutputStream(getSomePathname(), false);
new FileReader(getSomePathname(), Charset.defaultCharset());
new FileWriter(getSomePathname(), true);
new FileWriter(getSomePathname(), Charset.defaultCharset());
new FileWriter(getSomePathname(), Charset.defaultCharset(), false);
new PrintStream(getSomePathname(), StandardCharsets.UTF_16.displayName());
new PrintStream(getSomePathname(), Charset.defaultCharset());
new PrintWriter(getSomePathname(), StandardCharsets.UTF_16.displayName());
new PrintWriter(getSomePathname(), StandardCharsets.UTF_16.displayName());
new Formatter(getSomePathname(), StandardCharsets.UTF_16.displayName());
new Formatter(getSomePathname(), StandardCharsets.UTF_16.displayName(), Locale.ENGLISH);
new Formatter(getSomePathname(), Charset.defaultCharset(), Locale.GERMAN);
}
}
@@ -1,15 +1,15 @@
// "Fix all 'Redundant file creation' problems in file" "true"
// "Fix all 'Redundant File object creation' problems in file" "true"
import java.io.*;
import java.util.Formatter;
class Main {
public main(String[] args) {
InputStream is = new FileInputStream("1.txt");
OutputStream os = new FileOutputStream("2.txt");
FileReader fr = new FileReader("3.txt");
FileWriter fw = new FileWriter("4.txt");
PrintStream ps = new PrintStream("5.txt");
PrintWriter pw = new PrintWriter("6.txt");
Formatter f = new Formatter("7.txt");
public void main(String[] args) throws IOException {
new FileInputStream("in.txt");
new FileOutputStream("in.txt");
new FileReader("in.txt");
new FileWriter("in.txt");
new PrintStream("in.txt");
new PrintWriter("in.txt");
new Formatter("in.txt");
}
}
@@ -1,4 +1,4 @@
// "Fix all 'Redundant file creation' problems in file" "true"
// "Fix all 'Redundant File object creation' problems in file" "true"
import java.io.*;
import java.util.Formatter;
@@ -7,13 +7,13 @@ class Main {
return "Some pathname";
}
public main(String[] args) {
InputStream is = new FileInputStream(getSomePathname());
OutputStream os = new FileOutputStream(getSomePathname());
FileReader fr = new FileReader(getSomePathname());
FileWriter fw = new FileWriter(getSomePathname());
PrintStream ps = new PrintStream(getSomePathname());
PrintWriter pw = new PrintWriter(getSomePathname());
Formatter f = new Formatter(getSomePathname());
public void main(String[] args) throws IOException {
new FileInputStream(getSomePathname());
new FileOutputStream(getSomePathname());
new FileReader(getSomePathname());
new FileWriter(getSomePathname());
new PrintStream(getSomePathname());
new PrintWriter(getSomePathname());
new Formatter(getSomePathname());
}
}
@@ -0,0 +1,43 @@
// "Fix all 'Redundant File object creation' problems in file" "true"
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Formatter;
import java.util.Locale;
class Main {
private static String getSomePathname() {
return "Some pathname";
}
public void main(String[] args) throws IOException {
new FileInputStream((("in.txt")));
new FileOutputStream((("in.txt")));
new FileReader((("in.txt")));
new FileWriter((("in.txt")));
new PrintStream((("in.txt")));
new PrintWriter((("in.txt")));
new Formatter((("in.txt")));
new FileInputStream(((getSomePathname())));
new FileOutputStream(((getSomePathname())));
new FileReader(((getSomePathname())));
new FileWriter(((getSomePathname())));
new PrintStream(((getSomePathname())));
new PrintWriter(((getSomePathname())));
new Formatter(((getSomePathname())));
new FileOutputStream((getSomePathname()), false);
new FileReader((getSomePathname()), Charset.defaultCharset());
new FileWriter((getSomePathname()), true);
new FileWriter((getSomePathname()), Charset.defaultCharset());
new FileWriter((getSomePathname()), Charset.defaultCharset(), false);
new PrintStream((getSomePathname()), StandardCharsets.UTF_16.displayName());
new PrintStream((getSomePathname()), Charset.defaultCharset());
new PrintWriter((getSomePathname()), StandardCharsets.UTF_16.displayName());
new PrintWriter((getSomePathname()), StandardCharsets.UTF_16.displayName());
new Formatter((getSomePathname()), StandardCharsets.UTF_16.displayName());
new Formatter((getSomePathname()), StandardCharsets.UTF_16.displayName(), Locale.ENGLISH);
new Formatter((getSomePathname()), Charset.defaultCharset(), Locale.GERMAN);
}
}
@@ -0,0 +1,40 @@
// "Fix all 'Redundant File object creation' problems in file" "true"
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Formatter;
import java.util.Locale;
class Main {
private static String getSomePathname() {
return "Some pathname";
}
public void main(String[] args) throws IOException {
new FileOutputStream(new Fi<caret>le("in.txt"), false);
new FileReader(new File("in.txt"), Charset.defaultCharset());
new FileWriter(new File("in.txt"), true);
new FileWriter(new File("in.txt"), Charset.defaultCharset());
new FileWriter(new File("in.txt"), Charset.defaultCharset(), false);
new PrintStream(new File("in.txt"), StandardCharsets.UTF_16.displayName());
new PrintStream(new File("in.txt"), Charset.defaultCharset());
new PrintWriter(new File("in.txt"), StandardCharsets.UTF_16.displayName());
new PrintWriter(new File("in.txt"), StandardCharsets.UTF_16.displayName());
new Formatter(new File("in.txt"), StandardCharsets.UTF_16.displayName());
new Formatter(new File("in.txt"), StandardCharsets.UTF_16.displayName(), Locale.ENGLISH);
new Formatter(new File("in.txt"), Charset.defaultCharset(), Locale.GERMAN);
new FileOutputStream(new File(getSomePathname()), false);
new FileReader(new File(getSomePathname()), Charset.defaultCharset());
new FileWriter(new File(getSomePathname()), true);
new FileWriter(new File(getSomePathname()), Charset.defaultCharset());
new FileWriter(new File(getSomePathname()), Charset.defaultCharset(), false);
new PrintStream(new File(getSomePathname()), StandardCharsets.UTF_16.displayName());
new PrintStream(new File(getSomePathname()), Charset.defaultCharset());
new PrintWriter(new File(getSomePathname()), StandardCharsets.UTF_16.displayName());
new PrintWriter(new File(getSomePathname()), StandardCharsets.UTF_16.displayName());
new Formatter(new File(getSomePathname()), StandardCharsets.UTF_16.displayName());
new Formatter(new File(getSomePathname()), StandardCharsets.UTF_16.displayName(), Locale.ENGLISH);
new Formatter(new File(getSomePathname()), Charset.defaultCharset(), Locale.GERMAN);
}
}
@@ -1,15 +1,15 @@
// "Fix all 'Redundant file creation' problems in file" "true"
// "Fix all 'Redundant File object creation' problems in file" "true"
import java.io.*;
import java.util.Formatter;
class Main {
public main(String[] args) {
InputStream is = new FileInputStream(new Fi<caret>le("1.txt"));
OutputStream os = new FileOutputStream(new File("2.txt"));
FileReader fr = new FileReader(new File("3.txt"));
FileWriter fw = new FileWriter(new File("4.txt"));
PrintStream ps = new PrintStream(new File("5.txt"));
PrintWriter pw = new PrintWriter(new File("6.txt"));
Formatter f = new Formatter(new File("7.txt"));
public void main(String[] args) throws IOException {
new FileInputStream(new Fi<caret>le("in.txt"));
new FileOutputStream(new File("in.txt"));
new FileReader(new File("in.txt"));
new FileWriter(new File("in.txt"));
new PrintStream(new File("in.txt"));
new PrintWriter(new File("in.txt"));
new Formatter(new File("in.txt"));
}
}
@@ -1,4 +1,4 @@
// "Fix all 'Redundant file creation' problems in file" "true"
// "Fix all 'Redundant File object creation' problems in file" "true"
import java.io.*;
import java.util.Formatter;
@@ -7,13 +7,13 @@ class Main {
return "Some pathname";
}
public main(String[] args) {
InputStream is = new FileInputStream(new Fi<caret>le(getSomePathname()));
OutputStream os = new FileOutputStream(new File(getSomePathname()));
FileReader fr = new FileReader(new File(getSomePathname()));
FileWriter fw = new FileWriter(new File(getSomePathname()));
PrintStream ps = new PrintStream(new File(getSomePathname()));
PrintWriter pw = new PrintWriter(new File(getSomePathname()));
Formatter f = new Formatter(new File(getSomePathname()));
public void main(String[] args) throws IOException {
new FileInputStream(new Fi<caret>le(getSomePathname()));
new FileOutputStream(new File(getSomePathname()));
new FileReader(new File(getSomePathname()));
new FileWriter(new File(getSomePathname()));
new PrintStream(new File(getSomePathname()));
new PrintWriter(new File(getSomePathname()));
new Formatter(new File(getSomePathname()));
}
}
@@ -0,0 +1,43 @@
// "Fix all 'Redundant File object creation' problems in file" "true"
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Formatter;
import java.util.Locale;
class Main {
private static String getSomePathname() {
return "Some pathname";
}
public void main(String[] args) throws IOException {
new FileInputStream((new Fi<caret>le(("in.txt"))));
new FileOutputStream((new File(("in.txt"))));
new FileReader((new File(("in.txt"))));
new FileWriter((new File(("in.txt"))));
new PrintStream((new File(("in.txt"))));
new PrintWriter((new File(("in.txt"))));
new Formatter((new File(("in.txt"))));
new FileInputStream((new File((getSomePathname()))));
new FileOutputStream((new File((getSomePathname()))));
new FileReader((new File((getSomePathname()))));
new FileWriter((new File((getSomePathname()))));
new PrintStream((new File((getSomePathname()))));
new PrintWriter((new File((getSomePathname()))));
new Formatter((new File((getSomePathname()))));
new FileOutputStream((new File(getSomePathname())), false);
new FileReader((new File(getSomePathname())), Charset.defaultCharset());
new FileWriter((new File(getSomePathname())), true);
new FileWriter((new File(getSomePathname())), Charset.defaultCharset());
new FileWriter((new File(getSomePathname())), Charset.defaultCharset(), false);
new PrintStream((new File(getSomePathname())), StandardCharsets.UTF_16.displayName());
new PrintStream((new File(getSomePathname())), Charset.defaultCharset());
new PrintWriter((new File(getSomePathname())), StandardCharsets.UTF_16.displayName());
new PrintWriter((new File(getSomePathname())), StandardCharsets.UTF_16.displayName());
new Formatter((new File(getSomePathname())), StandardCharsets.UTF_16.displayName());
new Formatter((new File(getSomePathname())), StandardCharsets.UTF_16.displayName(), Locale.ENGLISH);
new Formatter((new File(getSomePathname())), Charset.defaultCharset(), Locale.GERMAN);
}
}
@@ -4,6 +4,9 @@ package com.intellij.java.codeInsight.daemon.quickFix;
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.RedundantFileCreationInspection;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.util.lang.JavaVersion;
import org.jetbrains.annotations.NotNull;
@@ -19,4 +22,9 @@ public class RedundantFileCreationInspectionTest extends LightQuickFixParameteri
protected String getBasePath() {
return "/codeInsight/daemonCodeAnalyzer/quickFix/redundantFileCreation";
}
@Override
protected Sdk getProjectJDK() {
return IdeaTestUtil.getMockJdk(JavaVersion.compose(11));
}
}
@@ -567,9 +567,9 @@ inspection.redundant.array.creation.display.name=Redundant array creation
inspection.redundant.array.creation.for.varargs.call.descriptor=Redundant array creation for calling varargs method
inspection.redundant.array.creation.quickfix=Remove explicit array creation
inspection.redundant.explicit.close=Redundant 'close()'
inspection.redundant.file.creation.display.name=Redundant file creation
inspection.redundant.file.creation.display.name=Redundant File object creation
inspection.redundant.file.creation.description=<code>#ref</code> is redundant #loc
inspection.redundant.file.creation.quickfix=Replace with argument
inspection.redundant.file.creation.quickfix=Replace with file name
inspection.redundant.null.check.always.fail.message=Null-check will always fail: {0} is never null
inspection.redundant.null.check.fix.family.name=Remove redundant null-check
inspection.redundant.null.check.fix.notnull.family.name=Remove erroneous '!= null'
@@ -71,6 +71,12 @@ public interface CommonClassNames {
String JAVA_IO_EXTERNALIZABLE = "java.io.Externalizable";
String JAVA_IO_SERIAL = "java.io.Serial";
String JAVA_IO_FILE = "java.io.File";
String JAVA_IO_FILE_INPUT_STREAM = "java.io.FileInputStream";
String JAVA_IO_FILE_OUTPUT_STREAM = "java.io.FileOutputStream";
String JAVA_IO_FILE_READER = "java.io.FileReader";
String JAVA_IO_FILE_WRITER = "java.io.FileWriter";
String JAVA_IO_PRINT_STREAM = "java.io.PrintStream";
String JAVA_IO_PRINT_WRITER = "java.io.PrintWriter";
String JAVA_LANG_STRING = "java.lang.String";
@NonNls String JAVA_LANG_STRING_SHORT = "String";
@@ -105,6 +111,8 @@ public interface CommonClassNames {
String JAVA_UTIL_CONCURRENT_COMPLETABLE_FUTURE = "java.util.concurrent.CompletableFuture";
String JAVA_UTIL_CONCURRENT_COMPLETION_STAGE = "java.util.concurrent.CompletionStage";
String JAVA_UTIL_FORMATTER = "java.util.Formatter";
String JAVA_UTIL_STREAM_BASE_STREAM = "java.util.stream.BaseStream";
String JAVA_UTIL_STREAM_STREAM = "java.util.stream.Stream";
String JAVA_UTIL_STREAM_INT_STREAM = "java.util.stream.IntStream";
@@ -54,16 +54,6 @@ public final class TypeUtils {
return targetType != null && targetType.equalsToText(typeName);
}
@Contract("null, _ -> false")
public static boolean typeEquals(@Nullable PsiType targetType, @NonNls String @NotNull ... typeNames) {
for (String typeName : typeNames) {
if (typeEquals(typeName, targetType)) {
return true;
}
}
return false;
}
public static PsiClassType getType(@NotNull String fqName, @NotNull PsiElement context) {
final Project project = context.getProject();
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);