mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
Add "Replace 'compute' with 'computeIfPresent'" fix
Helps for IDEA-194058 False-positive warning of producing NullPointerException for Map.compute
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.codeInsight.intention.HighPriorityAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.siyeh.ig.callMatcher.CallMatcher;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
|
||||
public class ReplaceComputeWithComputeIfPresentFix implements LocalQuickFix, HighPriorityAction {
|
||||
private static final CallMatcher MAP_COMPUTE = CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_MAP, "compute").
|
||||
parameterTypes("K", CommonClassNames.JAVA_UTIL_FUNCTION_BI_FUNCTION);
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return InspectionsBundle.message("inspection.data.flow.use.computeifpresent.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiLambdaExpression lambda = PsiTreeUtil.getParentOfType(descriptor.getStartElement(), PsiLambdaExpression.class);
|
||||
if (lambda == null) return;
|
||||
PsiMethodCallExpression call = PsiTreeUtil.getParentOfType(lambda, PsiMethodCallExpression.class);
|
||||
if (call == null || !"compute".equals(call.getMethodExpression().getReferenceName())) return;
|
||||
ExpressionUtils.bindCallTo(call, "computeIfPresent");
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
public static ReplaceComputeWithComputeIfPresentFix makeFix(PsiElement reference) {
|
||||
if (!(reference instanceof PsiReferenceExpression)) return null;
|
||||
PsiParameter parameter = tryCast(((PsiReferenceExpression)reference).resolve(), PsiParameter.class);
|
||||
if (parameter == null) return null;
|
||||
PsiParameterList parameterList = tryCast(parameter.getParent(), PsiParameterList.class);
|
||||
if (parameterList == null || parameterList.getParametersCount() != 2 || parameterList.getParameterIndex(parameter) != 1) return null;
|
||||
PsiLambdaExpression lambda = tryCast(parameterList.getParent(), PsiLambdaExpression.class);
|
||||
if (lambda == null) return null;
|
||||
PsiExpressionList arguments = tryCast(lambda.getParent(), PsiExpressionList.class);
|
||||
if (arguments == null || arguments.getExpressionCount() != 2 || arguments.getExpressions()[1] != lambda) return null;
|
||||
PsiMethodCallExpression call = tryCast(arguments.getParent(), PsiMethodCallExpression.class);
|
||||
if (!MAP_COMPUTE.test(call)) return null;
|
||||
return new ReplaceComputeWithComputeIfPresentFix();
|
||||
}
|
||||
}
|
||||
@@ -119,6 +119,7 @@ public class DataFlowInspection extends DataFlowInspectionBase {
|
||||
|
||||
try {
|
||||
ContainerUtil.addIfNotNull(fixes, StreamFilterNotNullFix.makeFix(qualifier));
|
||||
ContainerUtil.addIfNotNull(fixes, ReplaceComputeWithComputeIfPresentFix.makeFix(qualifier));
|
||||
if (isVolatileFieldReference(qualifier)) {
|
||||
ContainerUtil.addIfNotNull(fixes, createIntroduceVariableFix(qualifier));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// "Replace 'compute' with 'computeIfPresent'" "true"
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
class Main {
|
||||
interface Item {
|
||||
Integer getInfo(int i);
|
||||
}
|
||||
|
||||
native List<String> getNamesList();
|
||||
|
||||
void test(List<Item> infoList) {
|
||||
Map<String, List<Integer>> data = new HashMap<>();
|
||||
List<String> names = getNamesList();
|
||||
for (String key : names) {
|
||||
data.put(key, new ArrayList<>());
|
||||
}
|
||||
for (Item info : infoList) {
|
||||
for (int i = 0; i < names.size(); i++) {
|
||||
final String k = names.get(i);
|
||||
final Integer newValue = info.getInfo(i);
|
||||
data.computeIfPresent(k, (key, array) -> {
|
||||
array.add(newValue);
|
||||
return array;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// "Replace 'compute' with 'computeIfPresent'" "true"
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
class Main {
|
||||
interface Item {
|
||||
Integer getInfo(int i);
|
||||
}
|
||||
|
||||
native List<String> getNamesList();
|
||||
|
||||
void test(List<Item> infoList) {
|
||||
Map<String, List<Integer>> data = new HashMap<>();
|
||||
List<String> names = getNamesList();
|
||||
for (String key : names) {
|
||||
data.put(key, new ArrayList<>());
|
||||
}
|
||||
for (Item info : infoList) {
|
||||
for (int i = 0; i < names.size(); i++) {
|
||||
final String k = names.get(i);
|
||||
final Integer newValue = info.getInfo(i);
|
||||
data.compute(k, (key, array) -> {
|
||||
array.a<caret>dd(newValue);
|
||||
return array;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
package com.intellij.java.codeInsight.daemon.quickFix;
|
||||
|
||||
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.dataFlow.DataFlowInspection;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ReplaceComputeWithComputeIfPresentFixTest extends LightQuickFixParameterizedTestCase {
|
||||
private static final LightProjectDescriptor DESCRIPTOR = new LightProjectDescriptor() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Sdk getSdk() {
|
||||
return PsiTestUtil.addJdkAnnotations(IdeaTestUtil.getMockJdk18());
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected LocalInspectionTool[] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new DataFlowInspection()};
|
||||
}
|
||||
|
||||
public void test() {
|
||||
doAllTests();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected LightProjectDescriptor getProjectDescriptor() {
|
||||
return DESCRIPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/replaceComputeWithComputeIfPresent";
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,7 @@ public class DataFlowInspectionTestSuite {
|
||||
suite.addTestSuite(UnwrapIfStatementFixTest.class);
|
||||
suite.addTestSuite(StreamFilterNotNullFixTest.class);
|
||||
suite.addTestSuite(RedundantInstanceofFixTest.class);
|
||||
suite.addTestSuite(ReplaceComputeWithComputeIfPresentFixTest.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ inspection.data.flow.redundant.instanceof.quickfix=Replace with a null check
|
||||
inspection.data.flow.simplify.boolean.expression.quickfix=Simplify boolean expression
|
||||
inspection.data.flow.simplify.to.assignment.quickfix.name=Simplify to normal assignment
|
||||
inspection.data.flow.filter.notnull.quickfix=Insert 'filter(Objects::nonNull)' step
|
||||
inspection.data.flow.use.computeifpresent.quickfix=Replace 'compute' with 'computeIfPresent'
|
||||
configure.annotations.option=Configure annotations
|
||||
|
||||
#messages from dataflow inspection
|
||||
|
||||
Reference in New Issue
Block a user