enable suspicious collections method calls for method references (IDEA-165237)

This commit is contained in:
Anna.Kozlova
2016-12-09 13:47:23 +01:00
parent e44fc30d10
commit 9aac402918
4 changed files with 61 additions and 19 deletions
@@ -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);
}
}
}
};
@@ -111,29 +111,38 @@ public class SuspiciousMethodCallUtil {
@NotNull List<PsiMethod> 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<PsiMethod> 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;
@@ -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<String, String> key2name = new HashMap<>();
List<BigDecimal> codes = Arrays.asList(BigDecimal.ONE, BigDecimal.TEN);
List<String> codes1 = Arrays.asList("a", "b", "c");
final List<BigDecimal> list = codes.stream().filter(key2name::<warning descr="'Map<String, String>' may not contain objects of type 'BigDecimal'">containsKey</warning>).collect(Collectors.toList());
final List<String> list1 = codes1.stream().filter(key2name::containsKey).collect(Collectors.toList());
}
}
@@ -46,6 +46,10 @@ public class SuspiciousCollectionMethodCallsTest extends LightCodeInsightFixture
doTest();
}
public void testMethodReferenceWithCollectionCalls() throws Exception {
doTest();
}
public void testNonClassArgTypes() throws Exception {
doTest();
}