mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-21 22:11:40 +07:00
BulkFileAttributesReadInspection: added inspection
Inspection reports multiple java.io.File attribute calls in a row. Attribute calls: - lastModified - isFile - isDirectory - length It suggests replacing them with a single attributes extraction using java.nio.file.Files.readAttributes method GitOrigin-RevId: cd2f93645aab9a4cba2e1f87e05b431f0d21ee50
This commit is contained in:
committed by
intellij-monorepo-bot
parent
00abfbc508
commit
51b6c30a78
@@ -0,0 +1,292 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil;
|
||||
import com.intellij.codeInsight.generation.surroundWith.JavaWithTryCatchSurrounder;
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.SuggestedNameInfo;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.CommonJavaRefactoringUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.siyeh.ig.PsiReplacementUtil;
|
||||
import com.siyeh.ig.callMatcher.CallMatcher;
|
||||
import com.siyeh.ig.psiutils.*;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class BulkFileAttributesReadInspection extends AbstractBaseJavaLocalInspectionTool {
|
||||
private static final Map<String, String> ATTR_REPLACEMENTS = Map.of(
|
||||
"lastModified", "lastModifiedTime().toMillis",
|
||||
"isFile", "isRegularFile",
|
||||
"isDirectory", "isDirectory",
|
||||
"length", "size"
|
||||
);
|
||||
|
||||
private static final CallMatcher FILE_ATTR_CALL_MATCHER =
|
||||
CallMatcher.instanceCall(CommonClassNames.JAVA_IO_FILE, ArrayUtil.toStringArray(ATTR_REPLACEMENTS.keySet())).parameterCount(0);
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
|
||||
boolean isOnTheFly) {
|
||||
if (!PsiUtil.isLanguageLevel7OrHigher(holder.getFile())) return PsiElementVisitor.EMPTY_VISITOR;
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression call) {
|
||||
super.visitMethodCallExpression(call);
|
||||
if (!FILE_ATTR_CALL_MATCHER.test(call)) return;
|
||||
PsiVariable fileVariable = getFileVariable(call);
|
||||
if (fileVariable == null) return;
|
||||
PsiMethod containingMethod = PsiTreeUtil.getParentOfType(call, PsiMethod.class);
|
||||
if (containingMethod == null) return;
|
||||
if (!HighlightControlFlowUtil.isEffectivelyFinal(fileVariable, containingMethod, null)) return;
|
||||
List<PsiMethodCallExpression> attrCalls = findAttributeCalls(fileVariable, containingMethod);
|
||||
if (distinctCalls(attrCalls) < 2) return;
|
||||
if (!isOnTheFly) {
|
||||
PsiExpression[] occurrences = attrCalls.toArray(PsiExpression.EMPTY_ARRAY);
|
||||
PsiElement anchor = CommonJavaRefactoringUtil.getAnchorElementForMultipleExpressions(occurrences, containingMethod);
|
||||
if (anchor == null || needsTryCatchBlock(anchor)) return;
|
||||
}
|
||||
holder.registerProblem(call, JavaBundle.message("inspection.bulk.file.attributes.read.message"),
|
||||
new ReplaceWithBulkCallFix(isOnTheFly));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiVariable getFileVariable(@NotNull PsiMethodCallExpression call) {
|
||||
PsiReferenceExpression qualifier = ObjectUtils.tryCast(call.getMethodExpression().getQualifier(), PsiReferenceExpression.class);
|
||||
if (qualifier == null) return null;
|
||||
return ObjectUtils.tryCast(qualifier.resolve(), PsiVariable.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<PsiMethodCallExpression> findAttributeCalls(@NotNull PsiVariable fileVar, @NotNull PsiMethod containingMethod) {
|
||||
Collection<PsiMethodCallExpression> calls = ReferencesSearch.search(fileVar, new LocalSearchScope(containingMethod))
|
||||
.mapping(ref -> ObjectUtils.tryCast(ref, PsiReferenceExpression.class))
|
||||
.mapping(ref -> ref == null ? null : ExpressionUtils.getCallForQualifier(ref))
|
||||
.filtering(FILE_ATTR_CALL_MATCHER)
|
||||
.findAll();
|
||||
return new ArrayList<>(calls);
|
||||
}
|
||||
|
||||
private static long distinctCalls(@NotNull List<PsiMethodCallExpression> calls) {
|
||||
return StreamEx.of(calls).distinct(call -> call.getMethodExpression().getReferenceName()).count();
|
||||
}
|
||||
|
||||
private static boolean needsTryCatchBlock(@NotNull PsiElement anchor) {
|
||||
PsiClassType ioExceptionType = TypeUtils.getType("java.io.IOException", anchor);
|
||||
return !ExceptionUtil.isHandled(ioExceptionType, anchor);
|
||||
}
|
||||
|
||||
private static class ReplaceWithBulkCallFix implements LocalQuickFix {
|
||||
|
||||
private final boolean myIsOnTheFly;
|
||||
|
||||
private ReplaceWithBulkCallFix(boolean isOnTheFly) {
|
||||
myIsOnTheFly = isOnTheFly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getFamilyName() {
|
||||
return JavaBundle.message("inspection.replace.with.bulk.file.attributes.read.fix.family.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiMethodCallExpression call = ObjectUtils.tryCast(descriptor.getPsiElement(), PsiMethodCallExpression.class);
|
||||
if (!FILE_ATTR_CALL_MATCHER.test(call)) return;
|
||||
FileVariableModel fileVariable = FileVariableModel.create(call);
|
||||
if (fileVariable == null) return;
|
||||
PsiElement anchor = fileVariable.findAnchor();
|
||||
if (anchor == null) return;
|
||||
PsiElement parent = anchor.getParent();
|
||||
if (parent == null) return;
|
||||
String fileVarName = fileVariable.getName();
|
||||
if (fileVarName == null) return;
|
||||
AttributesVariableModel attributesVariable = AttributesVariableModel.create(fileVarName, fileVariable.myContainingMethod, anchor);
|
||||
if (attributesVariable == null) return;
|
||||
|
||||
final PsiDeclarationStatement declaration;
|
||||
PsiReference[] usages = new PsiReference[fileVariable.myAttributeCalls.size() + (attributesVariable.myNeedsTryCatch ? 1 : 0)];
|
||||
if (!attributesVariable.myNeedsTryCatch) {
|
||||
declaration =
|
||||
addDeclaration(parent, anchor, attributesVariable.myName, attributesVariable.myType, attributesVariable.myInitializer);
|
||||
}
|
||||
else {
|
||||
declaration = addDeclaration(parent, anchor, attributesVariable.myName, attributesVariable.myType, null);
|
||||
PsiExpressionStatement assignment = addAssignment(parent, anchor, attributesVariable.myName, attributesVariable.myInitializer);
|
||||
assignment = surroundWithTryCatch(parent, declaration, assignment);
|
||||
if (assignment == null) return;
|
||||
PsiExpression lhs = getLhs(assignment);
|
||||
if (lhs == null) return;
|
||||
PsiReference lhsRef = lhs.getReference();
|
||||
if (lhsRef == null) return;
|
||||
usages[usages.length - 1] = lhsRef;
|
||||
}
|
||||
|
||||
List<PsiMethodCallExpression> attrCalls = fileVariable.myAttributeCalls;
|
||||
for (int i = 0; i < attrCalls.size(); i++) {
|
||||
PsiMethodCallExpression attrCall = attrCalls.get(i);
|
||||
String replacement = getBulkCallReplacement(attributesVariable.myName, attrCall);
|
||||
attrCall = (PsiMethodCallExpression)PsiReplacementUtil.replaceExpressionAndShorten(attrCall, replacement, new CommentTracker());
|
||||
usages[i] = getTopLevelQualifier(attrCall).getReference();
|
||||
}
|
||||
|
||||
if (!myIsOnTheFly) return;
|
||||
PsiVariable attrsVariable = (PsiVariable)declaration.getDeclaredElements()[0];
|
||||
HighlightUtils.showRenameTemplate(fileVariable.myContainingMethod, attrsVariable, usages);
|
||||
}
|
||||
|
||||
private static @NotNull PsiExpressionStatement addAssignment(@NotNull PsiElement parent,
|
||||
@NotNull PsiElement anchor,
|
||||
@NotNull String varName,
|
||||
@NotNull PsiExpression initializer) {
|
||||
PsiElementFactory elementFactory = PsiElementFactory.getInstance(parent.getProject());
|
||||
String assignmentText = varName + "=" + initializer.getText() + ";";
|
||||
PsiExpressionStatement assignment = (PsiExpressionStatement)elementFactory.createStatementFromText(assignmentText, parent);
|
||||
assignment = (PsiExpressionStatement)parent.addBefore(assignment, anchor);
|
||||
JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(parent.getProject());
|
||||
return (PsiExpressionStatement)codeStyleManager.shortenClassReferences(assignment);
|
||||
}
|
||||
|
||||
private static @Nullable PsiExpressionStatement surroundWithTryCatch(@NotNull PsiElement parent,
|
||||
@NotNull PsiStatement prevStatement,
|
||||
@NotNull PsiExpressionStatement assignment) {
|
||||
JavaWithTryCatchSurrounder tryCatchSurrounder = new JavaWithTryCatchSurrounder();
|
||||
Project project = assignment.getProject();
|
||||
Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
|
||||
if (editor == null) return null;
|
||||
tryCatchSurrounder.surroundStatements(project, editor, parent, new PsiExpressionStatement[]{assignment});
|
||||
PsiTryStatement tryStatement = ObjectUtils.tryCast(prevStatement.getNextSibling(), PsiTryStatement.class);
|
||||
if (tryStatement == null) return null;
|
||||
return ObjectUtils.tryCast(ControlFlowUtils.getOnlyStatementInBlock(tryStatement.getTryBlock()), PsiExpressionStatement.class);
|
||||
}
|
||||
|
||||
private static @Nullable PsiExpression getLhs(@NotNull PsiExpressionStatement statement) {
|
||||
PsiAssignmentExpression assignmentExpression = ObjectUtils.tryCast(statement.getExpression(), PsiAssignmentExpression.class);
|
||||
if (assignmentExpression == null) return null;
|
||||
return assignmentExpression.getLExpression();
|
||||
}
|
||||
|
||||
private static @NotNull PsiDeclarationStatement addDeclaration(@NotNull PsiElement parent,
|
||||
@NotNull PsiElement anchor,
|
||||
@NotNull String varName,
|
||||
@NotNull PsiType type,
|
||||
@Nullable PsiExpression initializer) {
|
||||
PsiElementFactory elementFactory = PsiElementFactory.getInstance(parent.getProject());
|
||||
PsiDeclarationStatement declaration = elementFactory.createVariableDeclarationStatement(varName, type, initializer);
|
||||
declaration = (PsiDeclarationStatement)parent.addBefore(declaration, anchor);
|
||||
JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(parent.getProject());
|
||||
return (PsiDeclarationStatement)codeStyleManager.shortenClassReferences(declaration);
|
||||
}
|
||||
|
||||
private static @NotNull String getBulkCallReplacement(@NotNull String attrsVarName, @NotNull PsiMethodCallExpression attrCall) {
|
||||
String attrMethodName = Objects.requireNonNull(attrCall.getMethodExpression().getReferenceName());
|
||||
return attrsVarName + "." + ATTR_REPLACEMENTS.get(attrMethodName) + "()";
|
||||
}
|
||||
|
||||
private static @NotNull PsiElement getTopLevelQualifier(@NotNull PsiMethodCallExpression methodCall) {
|
||||
PsiElement qualifier = PsiUtil.skipParenthesizedExprUp(methodCall.getMethodExpression().getQualifier());
|
||||
while (qualifier instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression call = (PsiMethodCallExpression)qualifier;
|
||||
qualifier = PsiUtil.skipParenthesizedExprUp(call.getMethodExpression().getQualifier());
|
||||
}
|
||||
return Objects.requireNonNull(qualifier);
|
||||
}
|
||||
|
||||
private static class FileVariableModel {
|
||||
private final PsiVariable myFileVariable;
|
||||
private final PsiMethod myContainingMethod;
|
||||
private List<PsiMethodCallExpression> myAttributeCalls;
|
||||
|
||||
private FileVariableModel(@NotNull List<PsiMethodCallExpression> attributeCalls,
|
||||
@NotNull PsiVariable fileVariable, @NotNull PsiMethod containingMethod) {
|
||||
myAttributeCalls = attributeCalls;
|
||||
myFileVariable = fileVariable;
|
||||
myContainingMethod = containingMethod;
|
||||
}
|
||||
|
||||
private @Nullable String getName() {
|
||||
return myFileVariable.getName();
|
||||
}
|
||||
|
||||
private @Nullable PsiElement findAnchor() {
|
||||
PsiExpression[] occurrences = myAttributeCalls.toArray(PsiExpression.EMPTY_ARRAY);
|
||||
PsiElement anchor = CommonJavaRefactoringUtil.getAnchorElementForMultipleExpressions(occurrences, myContainingMethod);
|
||||
if (anchor == null) return null;
|
||||
PsiLambdaExpression lambda = ObjectUtils.tryCast(PsiUtil.skipParenthesizedExprUp(anchor.getParent()), PsiLambdaExpression.class);
|
||||
if (lambda == null) return anchor;
|
||||
PsiCodeBlock codeBlock = RefactoringUtil.expandExpressionLambdaToCodeBlock(lambda);
|
||||
// attribute calls were inside lambda, need to recalculate them
|
||||
myAttributeCalls = findAttributeCalls(myFileVariable, myContainingMethod);
|
||||
return ControlFlowUtils.getOnlyStatementInBlock(codeBlock);
|
||||
}
|
||||
|
||||
private static FileVariableModel create(@NotNull PsiMethodCallExpression variableUsage) {
|
||||
PsiMethod containingMethod = PsiTreeUtil.getParentOfType(variableUsage, PsiMethod.class);
|
||||
if (containingMethod == null) return null;
|
||||
PsiVariable psiVariable = getFileVariable(variableUsage);
|
||||
if (psiVariable == null) return null;
|
||||
List<PsiMethodCallExpression> attributeCalls = findAttributeCalls(psiVariable, containingMethod);
|
||||
if (distinctCalls(attributeCalls) < 2) return null;
|
||||
return new FileVariableModel(attributeCalls, psiVariable, containingMethod);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AttributesVariableModel {
|
||||
private final PsiType myType;
|
||||
private final String myName;
|
||||
private final PsiExpression myInitializer;
|
||||
private final boolean myNeedsTryCatch;
|
||||
|
||||
private AttributesVariableModel(@NotNull PsiType type, @NotNull String name, @NotNull PsiExpression initializer,
|
||||
boolean needsTryCatch) {
|
||||
myType = type;
|
||||
myName = name;
|
||||
myInitializer = initializer;
|
||||
myNeedsTryCatch = needsTryCatch;
|
||||
}
|
||||
|
||||
private static @Nullable AttributesVariableModel create(@NotNull String fileVarName,
|
||||
@NotNull PsiElement context, @NotNull PsiElement anchor) {
|
||||
PsiClassType psiType = TypeUtils.getType("java.nio.file.attribute.BasicFileAttributes", context);
|
||||
PsiExpression initializer = createInitializer(context, psiType, fileVarName);
|
||||
String name = getSuggestedName(psiType, initializer, anchor);
|
||||
if (name == null) return null;
|
||||
boolean needsTryCatch = needsTryCatchBlock(anchor);
|
||||
return new AttributesVariableModel(psiType, name, initializer, needsTryCatch);
|
||||
}
|
||||
|
||||
private static @NotNull PsiExpression createInitializer(@NotNull PsiElement context,
|
||||
@NotNull PsiType psiType,
|
||||
@NotNull String fileVarName) {
|
||||
String initializerText = "java.nio.file.Files.readAttributes(" +
|
||||
fileVarName + ".toPath()" + "," +
|
||||
psiType.getCanonicalText() + ".class" + ")";
|
||||
return PsiElementFactory.getInstance(context.getProject()).createExpressionFromText(initializerText, context);
|
||||
}
|
||||
|
||||
private static @Nullable String getSuggestedName(@NotNull PsiType type,
|
||||
@NotNull PsiExpression initializer, @NotNull PsiElement anchor) {
|
||||
SuggestedNameInfo nameInfo = CommonJavaRefactoringUtil.getSuggestedName(type, initializer, anchor);
|
||||
String[] names = nameInfo.names;
|
||||
return names.length == 0 ? null : names[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1860,6 +1860,11 @@
|
||||
groupKey="group.names.performance.issues" groupBundle="messages.InspectionsBundle"
|
||||
enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.intellij.codeInspection.IOStreamConstructorInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="BulkFileAttributesRead"
|
||||
key="inspection.bulk.file.attributes.read.description" bundle="messages.JavaBundle"
|
||||
groupKey="group.names.performance.issues" groupBundle="messages.InspectionsBundle"
|
||||
enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.intellij.codeInspection.BulkFileAttributesReadInspection"/>
|
||||
<globalInspection groupPath="Java" language="JAVA" shortName="EmptyMethod" groupKey="group.names.declaration.redundancy" enabledByDefault="true" groupBundle="messages.InspectionsBundle"
|
||||
level="WARNING" implementationClass="com.intellij.codeInspection.emptyMethod.EmptyMethodInspection"
|
||||
key="inspection.empty.method.display.name" bundle="messages.JavaBundle"/>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports multiple 'java.io.File' attribute calls in a row, such as:
|
||||
<ul>
|
||||
<li>isDirectory</li>
|
||||
<li>isFile</li>
|
||||
<li>lastModified</li>
|
||||
<li>length</li>
|
||||
</ul>
|
||||
This calls can be replaced with a bulk 'Files.readAttributes' call.
|
||||
Usually bulk method is more performant then multiple attribute calls.
|
||||
<p>Example:</p>
|
||||
<pre><code>
|
||||
boolean isNewFile(File file, long lastModified) {
|
||||
return file.isFile() && file.lastModified() > lastModified;
|
||||
}
|
||||
</code></pre>
|
||||
<p>After quick-fix is applied:</p>
|
||||
<pre><code>
|
||||
boolean isNewFile(File file, long lastModified) {
|
||||
BasicFileAttributes basicFileAttributes;
|
||||
try {
|
||||
basicFileAttributes = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return basicFileAttributes.isRegularFile() && basicFileAttributes.lastModifiedTime().toMillis() > lastModified;
|
||||
}
|
||||
</code></pre>
|
||||
<!-- tooltip end -->
|
||||
<p>This inspection only reports if the language level of the project or module is 7 or higher.</p>
|
||||
<p><small>New in 2022.1</small></p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,18 @@
|
||||
// "Replace with bulk 'Files.readAttributes' call" "true"
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
class Foo {
|
||||
|
||||
private File file;
|
||||
|
||||
boolean printDirectory() {
|
||||
try {
|
||||
BasicFileAttributes basicFileAttributes = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
||||
return basicFileAttributes.isDirectory() && basicFileAttributes.isRegularFile();
|
||||
throw new IOException("");
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// "Replace with bulk 'Files.readAttributes' call" "true"
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
class Foo {
|
||||
boolean printDirectory(File file) {
|
||||
try {
|
||||
BasicFileAttributes basicFileAttributes = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
||||
return basicFileAttributes.isDirectory() && basicFileAttributes.isRegularFile();
|
||||
throw new IOException("");
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// "Replace with bulk 'Files.readAttributes' call" "true"
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
class Foo {
|
||||
void printDirectory(File file) {
|
||||
try {
|
||||
Callable<Boolean> r = () -> {
|
||||
BasicFileAttributes basicFileAttributes = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
||||
return basicFileAttributes.isDirectory() && basicFileAttributes.isRegularFile();
|
||||
};
|
||||
throw new IOException("");
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace with bulk 'Files.readAttributes' call" "true"
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
class Foo {
|
||||
long isNewFile(File file) throws IOException {
|
||||
BasicFileAttributes basicFileAttributes = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
||||
while (basicFileAttributes.isDirectory()) {
|
||||
System.out.println(basicFileAttributes.isRegularFile());
|
||||
}
|
||||
return basicFileAttributes.lastModifiedTime().toMillis();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// "Fix all 'Bulk 'Files.readAttributes' call can be used instead of multiple file attribute calls' problems in file" "true"
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
class Foo {
|
||||
void printDirectory(File file1, File file2) throws IOException {
|
||||
BasicFileAttributes readAttributes1 = Files.readAttributes(file1.toPath(), BasicFileAttributes.class);
|
||||
if (readAttributes1.isDirectory()) {
|
||||
System.out.println(readAttributes1.size());
|
||||
}
|
||||
BasicFileAttributes readAttributes = Files.readAttributes(file2.toPath(), BasicFileAttributes.class);
|
||||
if (readAttributes.isRegularFile()) {
|
||||
System.out.println(readAttributes.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// "Replace with bulk 'Files.readAttributes' call" "true"
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
class Foo {
|
||||
long isNewFile(File file, long lastModified) {
|
||||
BasicFileAttributes basicFileAttributes;
|
||||
try {
|
||||
basicFileAttributes = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
while (basicFileAttributes.isDirectory()) {
|
||||
System.out.println(basicFileAttributes.isRegularFile());
|
||||
}
|
||||
return basicFileAttributes.lastModifiedTime().toMillis();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// "Replace with bulk 'Files.readAttributes' call" "true"
|
||||
import java.io.*;
|
||||
|
||||
class Foo {
|
||||
|
||||
private File file;
|
||||
|
||||
boolean printDirectory() {
|
||||
try {
|
||||
return file.isDirec<caret>tory() && file.isFile();
|
||||
throw new IOException("");
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with bulk 'Files.readAttributes' call" "true"
|
||||
import java.io.*;
|
||||
|
||||
class Foo {
|
||||
boolean printDirectory(File file) {
|
||||
try {
|
||||
return file.isDirec<caret>tory() && file.isFile();
|
||||
throw new IOException("");
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with bulk 'Files.readAttributes' call" "true"
|
||||
import java.io.*;
|
||||
|
||||
class Foo {
|
||||
void printDirectory(File file) {
|
||||
try {
|
||||
Callable<Boolean> r = () -> file.isDirec<caret>tory() && file.isFile();
|
||||
throw new IOException("");
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace with bulk 'Files.readAttributes' call" "true"
|
||||
import java.io.*;
|
||||
|
||||
class Foo {
|
||||
long isNewFile(File file) throws IOException {
|
||||
while (file.isDire<caret>ctory()) {
|
||||
System.out.println(file.isFile());
|
||||
}
|
||||
return file.lastModified();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Fix all 'Bulk 'Files.readAttributes' call can be used instead of multiple file attribute calls' problems in file" "true"
|
||||
import java.io.*;
|
||||
|
||||
class Foo {
|
||||
void printDirectory(File file1, File file2) throws IOException {
|
||||
if (file1.isD<caret>irectory()) {
|
||||
System.out.println(file1.length());
|
||||
}
|
||||
if (file2.isFile()) {
|
||||
System.out.println(file2.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace with bulk 'Files.readAttributes' call" "false"
|
||||
import java.io.*;
|
||||
|
||||
class Foo {
|
||||
void printDirectory(File file, long lastModified) {
|
||||
while (file.isDire<caret>ctory()) {
|
||||
System.out.println(file.isDirectory());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with bulk 'Files.readAttributes' call" "false"
|
||||
import java.io.*;
|
||||
|
||||
class Foo {
|
||||
long isNewFile(File file, long lastModified) {
|
||||
while (file.isDir<caret>ectory()) {
|
||||
System.out.println(file.isFile());
|
||||
}
|
||||
file = new File("foo");
|
||||
return file.lastModified();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace with bulk 'Files.readAttributes' call" "true"
|
||||
import java.io.*;
|
||||
|
||||
class Foo {
|
||||
long isNewFile(File file, long lastModified) {
|
||||
while (file.isDire<caret>ctory()) {
|
||||
System.out.println(file.isFile());
|
||||
}
|
||||
return file.lastModified();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.java.codeInspection;
|
||||
|
||||
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
|
||||
import com.intellij.codeInspection.BulkFileAttributesReadInspection;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BulkFileAttributesReadTest extends LightQuickFixParameterizedTestCase {
|
||||
|
||||
@Override
|
||||
protected LocalInspectionTool @NotNull [] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new BulkFileAttributesReadInspection()};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sdk getProjectJDK() {
|
||||
return IdeaTestUtil.getMockJdk11();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/bulkFileAttributesRead";
|
||||
}
|
||||
}
|
||||
@@ -1720,6 +1720,9 @@ popup.title.effective.visibility=Effective Visibility
|
||||
inspection.io.stream.constructor.description=`InputStream' and 'OutputStream' can be constructed using 'Files' methods
|
||||
inspection.input.stream.constructor.message='InputStream' can be constructed using 'Files.newInputStream'
|
||||
inspection.output.stream.constructor.message='OutputStream' can be constructed using 'Files.newOutputStream'
|
||||
inspection.bulk.file.attributes.read.description=Bulk 'Files.readAttributes' call can be used instead of multiple file attribute calls
|
||||
inspection.replace.with.bulk.file.attributes.read.fix.family.name=Replace with bulk 'Files.readAttributes' call
|
||||
inspection.bulk.file.attributes.read.message=Multiple file attribute calls can be replaced with single 'Files.readAttributes' call
|
||||
external.annotations.problem.title=Unable to read external annotations
|
||||
external.annotations.problem.parse.error=File: {0}<br>Problem: {1}
|
||||
external.annotations.open.file=Open annotations file
|
||||
|
||||
Reference in New Issue
Block a user