From 9aac402918b23d052d53d2f07b35c48549cb8bae Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 9 Dec 2016 11:47:05 +0100 Subject: [PATCH] enable suspicious collections method calls for method references (IDEA-165237) --- ...ciousCollectionsMethodCallsInspection.java | 27 +++++++++++----- .../SuspiciousMethodCallUtil.java | 31 ++++++++++++------- .../MethodReferenceWithCollectionCalls.java | 18 +++++++++++ .../SuspiciousCollectionMethodCallsTest.java | 4 +++ 4 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 java/java-tests/testData/inspection/suspiciousCalls/MethodReferenceWithCollectionCalls.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousCollectionsMethodCallsInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousCollectionsMethodCallsInspection.java index 77b988aae62e..020a710a00a8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousCollectionsMethodCallsInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousCollectionsMethodCallsInspection.java @@ -22,6 +22,9 @@ import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.psi.*; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.IntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -54,17 +57,25 @@ public class SuspiciousCollectionsMethodCallsInspection extends BaseJavaBatchLoc final IntArrayList indices = new IntArrayList(); return new JavaElementVisitor() { @Override - public void visitReferenceExpression(final PsiReferenceExpression expression) { - visitExpression(expression); + public void visitMethodCallExpression(PsiMethodCallExpression methodCall) { + final String message = getSuspiciousMethodCallMessage(methodCall, REPORT_CONVERTIBLE_METHOD_CALLS, patternMethods, indices); + if (message != null) { + holder.registerProblem(methodCall.getArgumentList().getExpressions()[0], message); + } } @Override - public void visitMethodCallExpression(PsiMethodCallExpression methodCall) { - super.visitMethodCallExpression(methodCall); - final String message = getSuspiciousMethodCallMessage(methodCall, REPORT_CONVERTIBLE_METHOD_CALLS, patternMethods, indices - ); - if (message != null) { - holder.registerProblem(methodCall.getArgumentList().getExpressions()[0], message); + public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { + final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType(); + final PsiClassType.ClassResolveResult functionalInterfaceResolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType); + if (interfaceMethod != null && interfaceMethod.getParameterList().getParametersCount() == 1) { + final PsiSubstitutor psiSubstitutor = LambdaUtil.getSubstitutor(interfaceMethod, functionalInterfaceResolveResult); + final MethodSignature signature = interfaceMethod.getSignature(psiSubstitutor); + String message = SuspiciousMethodCallUtil.getSuspiciousMethodCallMessage(expression, signature.getParameterTypes()[0], REPORT_CONVERTIBLE_METHOD_CALLS, patternMethods, indices); + if (message != null) { + holder.registerProblem(ObjectUtils.notNull(expression.getReferenceNameElement(), expression), message); + } } } }; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java index 18eb9eaf3e44..4d08af344a49 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java @@ -111,29 +111,38 @@ public class SuspiciousMethodCallUtil { @NotNull List patternMethods, @NotNull IntArrayList indices) { final PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); - final PsiExpression qualifier = methodExpression.getQualifierExpression(); - if (qualifier == null || qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression) return null; - if (argType instanceof PsiPrimitiveType) { - argType = ((PsiPrimitiveType)argType).getBoxedType(methodCall); - } - - if (argType == null) return null; if (arg instanceof PsiConditionalExpression && PsiPolyExpressionUtil.isPolyExpression(arg) && argType.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) { return null; } + return getSuspiciousMethodCallMessage(methodExpression, argType, reportConvertibleMethodCalls, patternMethods, indices); + } + + @Nullable + public static String getSuspiciousMethodCallMessage(PsiReferenceExpression methodExpression, + PsiType argType, + boolean reportConvertibleMethodCalls, + @NotNull List patternMethods, + @NotNull IntArrayList indices) { + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null || qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression) return null; + if (argType instanceof PsiPrimitiveType) { + argType = ((PsiPrimitiveType)argType).getBoxedType(methodExpression); + } + + if (argType == null) return null; final JavaResolveResult resolveResult = methodExpression.advancedResolve(false); PsiMethod calleeMethod = (PsiMethod)resolveResult.getElement(); if (calleeMethod == null) return null; - PsiMethod contextMethod = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class); + PsiMethod contextMethod = PsiTreeUtil.getParentOfType(methodExpression, PsiMethod.class); //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (patternMethods) { if (patternMethods.isEmpty()) { - setupPatternMethods(methodCall.getManager(), methodCall.getResolveScope(), patternMethods, indices); + setupPatternMethods(methodExpression.getManager(), methodExpression.getResolveScope(), patternMethods, indices); } } @@ -171,8 +180,8 @@ public class SuspiciousMethodCallUtil { final PsiType qualifierItemType = JavaGenericsUtil.getCollectionItemType(qualifierType, calleeMethod.getResolveScope()); if (qualifierItemType != null && itemType != null && !qualifierItemType.isAssignableFrom(itemType)) { return InspectionsBundle.message("inspection.suspicious.collections.method.calls.problem.descriptor", - PsiFormatUtil.formatType(qualifierType, 0, PsiSubstitutor.EMPTY), - PsiFormatUtil.formatType(itemType, 0, PsiSubstitutor.EMPTY)); + PsiFormatUtil.formatType(qualifierType, 0, PsiSubstitutor.EMPTY), + PsiFormatUtil.formatType(itemType, 0, PsiSubstitutor.EMPTY)); } } return null; diff --git a/java/java-tests/testData/inspection/suspiciousCalls/MethodReferenceWithCollectionCalls.java b/java/java-tests/testData/inspection/suspiciousCalls/MethodReferenceWithCollectionCalls.java new file mode 100644 index 000000000000..1745475883ad --- /dev/null +++ b/java/java-tests/testData/inspection/suspiciousCalls/MethodReferenceWithCollectionCalls.java @@ -0,0 +1,18 @@ + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +class JavaClass { + { + Map key2name = new HashMap<>(); + List codes = Arrays.asList(BigDecimal.ONE, BigDecimal.TEN); + List codes1 = Arrays.asList("a", "b", "c"); + + final List list = codes.stream().filter(key2name::containsKey).collect(Collectors.toList()); + final List list1 = codes1.stream().filter(key2name::containsKey).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/SuspiciousCollectionMethodCallsTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/SuspiciousCollectionMethodCallsTest.java index 12f726f0afc8..7918de01ef1a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/SuspiciousCollectionMethodCallsTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/SuspiciousCollectionMethodCallsTest.java @@ -46,6 +46,10 @@ public class SuspiciousCollectionMethodCallsTest extends LightCodeInsightFixture doTest(); } + public void testMethodReferenceWithCollectionCalls() throws Exception { + doTest(); + } + public void testNonClassArgTypes() throws Exception { doTest(); }