IDEA-332957 GuavaInspection false positive review refactor

GitOrigin-RevId: 32b819439b341b8b3170ae304304c339cfc9e753
This commit is contained in:
Georgii Ustinov
2023-10-12 09:43:18 +03:00
committed by intellij-monorepo-bot
parent b20135887b
commit cbdda56f99
10 changed files with 130 additions and 41 deletions

View File

@@ -114,12 +114,8 @@ public final class GuavaInspection extends AbstractBaseJavaLocalInspectionTool {
checkPredicatesUtilityMethod(expression);
}
private void checkPredicatesUtilityMethod(PsiMethodCallExpression expression) {
if (GuavaPredicateConversionRule.isPredicates(expression) && (
isReceiverOfEnclosingCallAFluentIterable(expression) ||
GuavaPredicateConversionRule.isEnclosingCallPredicate(expression) ||
GuavaPredicateConversionRule.isPredicateConvertibleInsideEnclosingMethod(expression)
)) {
private void checkPredicatesUtilityMethod(@NotNull PsiMethodCallExpression expression) {
if (GuavaPredicateConversionRule.isPredicates(expression) && isPossibleToConvertPredicate(expression)) {
final PsiClassType initialType = (PsiClassType)expression.getType();
if (initialType == null) return;
PsiClassType targetType = createTargetType(initialType);
@@ -132,6 +128,16 @@ public final class GuavaInspection extends AbstractBaseJavaLocalInspectionTool {
}
}
private static boolean isPossibleToConvertPredicate(@NotNull PsiMethodCallExpression expression) {
PsiMethodCallExpression enclosingMethodCallExpression =
PsiTreeUtil.getParentOfType(expression, PsiMethodCallExpression.class);
return enclosingMethodCallExpression == null ||
isReceiverOfEnclosingCallAFluentIterable(enclosingMethodCallExpression) ||
GuavaPredicateConversionRule.isEnclosingCallAPredicate(enclosingMethodCallExpression) ||
GuavaPredicateConversionRule.isPredicateConvertibleInsideEnclosingMethod(expression, enclosingMethodCallExpression);
}
private void checkFluentIterableGenerationMethod(PsiMethodCallExpression expression) {
if (!checkChains) return;
if (!isFluentIterableFromCall(expression)) return;
@@ -191,10 +197,7 @@ public final class GuavaInspection extends AbstractBaseJavaLocalInspectionTool {
return result;
}
public static boolean isReceiverOfEnclosingCallAFluentIterable(PsiMethodCallExpression expression) {
PsiMethodCallExpression enclosingMethodCallExpression =
PsiTreeUtil.getParentOfType(expression, PsiMethodCallExpression.class);
if (enclosingMethodCallExpression == null) return false;
public static boolean isReceiverOfEnclosingCallAFluentIterable(@NotNull PsiMethodCallExpression enclosingMethodCallExpression) {
PsiMethod method = enclosingMethodCallExpression.resolveMethod();
if (method == null) return false;
return isFluentIterable(method.getContainingClass());

View File

@@ -8,13 +8,11 @@ import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase;
import com.intellij.refactoring.typeMigration.TypeEvaluator;
import com.intellij.refactoring.typeMigration.TypeMigrationLabeler;
import com.siyeh.ig.psiutils.ExpressionUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
/**
@@ -73,26 +71,31 @@ public class GuavaPredicateConversionRule extends GuavaLambdaConversionRule {
return false;
}
public static boolean isEnclosingCallPredicate(PsiMethodCallExpression expression) {
PsiMethodCallExpression enclosingMethodCallExpression =
PsiTreeUtil.getParentOfType(expression, PsiMethodCallExpression.class);
if (enclosingMethodCallExpression == null) return false;
public static boolean isEnclosingCallAPredicate(@NotNull PsiMethodCallExpression enclosingMethodCallExpression) {
return isPredicates(enclosingMethodCallExpression);
}
private static int getExpressionPosition(@NotNull PsiExpressionList expressionList, @NotNull PsiExpression expression) {
var expressions = expressionList.getExpressions();
for (int i = 0; i < expressions.length; ++i) {
if (expressions[i].equals(expression)) {
return i;
}
}
return -1;
}
public static boolean isPredicateConvertibleInsideEnclosingMethod(PsiMethodCallExpression methodCallExpression) {
PsiExpressionList expressionList = PsiTreeUtil.getParentOfType(methodCallExpression, PsiExpressionList.class);
PsiMethodCallExpression enclosingMethodCallExpression =
PsiTreeUtil.getParentOfType(methodCallExpression, PsiMethodCallExpression.class);
if (expressionList == null || enclosingMethodCallExpression == null) return true;
public static boolean isPredicateConvertibleInsideEnclosingMethod(@NotNull PsiMethodCallExpression innerMethodCallExpression,
@NotNull PsiMethodCallExpression enclosingMethodCallExpression) {
PsiExpressionList expressionList = PsiTreeUtil.getParentOfType(innerMethodCallExpression, PsiExpressionList.class);
if (expressionList == null) return false;
PsiMethod enclosingMethod = enclosingMethodCallExpression.resolveMethod();
if (enclosingMethod == null) return true;
if (enclosingMethod == null) return false;
PsiClass aClass = enclosingMethod.getContainingClass();
if (aClass == null) return true;
int position = ExpressionUtils.getExpressionPosition(expressionList, methodCallExpression);
if (aClass == null) return false;
int position = getExpressionPosition(expressionList, innerMethodCallExpression);
return Arrays.stream(aClass.findMethodsByName(enclosingMethod.getName(), true))
.filter(method -> PsiUtil.isMemberAccessibleAt(method, methodCallExpression))
.filter(method -> PsiUtil.isMemberAccessibleAt(method, innerMethodCallExpression))
.anyMatch(method -> areExpressionsConvertibleToMethodParameters(expressionList.getExpressionTypes(),
method.getParameterList().getParameters(),
position));
@@ -101,20 +104,33 @@ public class GuavaPredicateConversionRule extends GuavaLambdaConversionRule {
private static boolean areExpressionsConvertibleToMethodParameters(PsiType[] expressionTypes,
PsiParameter[] parameters,
int predicateExpressionPosition) {
if (parameters.length != expressionTypes.length) {
if (parameters.length == 0 || (parameters.length > expressionTypes.length && !parameters[expressionTypes.length].isVarArgs())) {
return false;
}
boolean isJavaPredicatePresented = false;
for (int i = 0; i < parameters.length; ++i) {
PsiType parameterType = Objects.requireNonNull(parameters[i].getType());
if (!parameterType.isConvertibleFrom(expressionTypes[i])) return false;
int parametersLastIndex = parameters.length - 1;
for (int expressionTypeIndex = 0; expressionTypeIndex < expressionTypes.length; ++expressionTypeIndex) {
PsiType parameterType;
if (expressionTypeIndex < parameters.length) {
if (parameters[expressionTypeIndex].isVarArgs()) {
parameterType = ((PsiArrayType)parameters[expressionTypeIndex].getType()).getComponentType();
}
else {
parameterType = parameters[expressionTypeIndex].getType();
}
}
else {
if (!parameters[parametersLastIndex].isVarArgs()) return false;
parameterType = ((PsiArrayType)parameters[parametersLastIndex].getType()).getComponentType();
}
if (!parameterType.isConvertibleFrom(expressionTypes[expressionTypeIndex])) return false;
PsiClass parameterClass = PsiTypesUtil.getPsiClass(parameterType);
if (parameterClass == null) continue;
String qualifiedClassName = parameterClass.getQualifiedName();
if (qualifiedClassName == null) continue;
if (i == predicateExpressionPosition && qualifiedClassName.equals("java.util.function.Predicate")) {
if (expressionTypeIndex == predicateExpressionPosition && qualifiedClassName.equals(CommonClassNames.JAVA_UTIL_FUNCTION_PREDICATE)) {
isJavaPredicatePresented = true;
}
}

View File

@@ -263,6 +263,12 @@ public class GuavaInspectionTest extends JavaCodeInsightFixtureTestCase {
public void testPredicates6() { doTestAllFile(); }
public void testPredicatesVarArg1() { doTestAllFile(); }
public void testPredicatesVarArg2() { doTestAllFile(); }
public void testPredicatesVarArg3() { doTestAllFile(); }
public void testFluentIterableElementTypeChanged() {
doTest();
}

View File

@@ -0,0 +1,13 @@
package org.example;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
public class Main {
void foo(Predicate<String> p0, Predicate<Integer> p1) {
call(Predicates.not(p0), Predicates.not(p1));
}
public static <T> void call(java.util.function.Predicate<?>... pr) {
}
}

View File

@@ -0,0 +1,12 @@
package org.example;
import java.util.function.Predicate;
public class Main {
void foo(Predicate<String> p0, Predicate<Integer> p1) {
call(p0.negate(), p1.negate());
}
public static <T> void call(Predicate<?>... pr) {
}
}

View File

@@ -0,0 +1,13 @@
package org.example;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
public class Main {
void foo(Predicate<String> p0, Predicate<Integer> p1) {
call(10, Predicates.not(p0), Predicates.not(p1));
}
public static void call(int x, java.util.function.Predicate<String>, java.util.function.Predicate<?>... pr) {
}
}

View File

@@ -0,0 +1,12 @@
package org.example;
import java.util.function.Predicate;
public class Main {
void foo(Predicate<String> p0, Predicate<Integer> p1) {
call(10, p0.negate(), p1.negate());
}
public static void call(int x, Predicate<String>, Predicate<?>... pr) {
}
}

View File

@@ -0,0 +1,13 @@
package org.example;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
public class Main {
void foo(Predicate<String> p0, Predicate<Integer> p1) {
call(10, Predicates.not(p0), Predicates.not(p1));
}
public static void call(int x, java.util.function.Predicate<String>, java.util.function.Predicate<Integer>, java.util.function.Predicate<?>... pr) {
}
}

View File

@@ -0,0 +1,12 @@
package org.example;
import java.util.function.Predicate;
public class Main {
void foo(Predicate<String> p0, Predicate<Integer> p1) {
call(10, p0.negate(), p1.negate());
}
public static void call(int x, Predicate<String>, Predicate<Integer>, Predicate<?>... pr) {
}
}