[java-inspections] TrivialFunctionalExpressionUsageInspection: more accurate side-effect handling

IDEA-355026 "Trivial usage of functional expression" breaks semantics if one argument updates the variable used in another

GitOrigin-RevId: e3d9374ecc427d62cee0d821473e9119ae240fc5
This commit is contained in:
Tagir Valeev
2024-10-01 14:56:46 +02:00
committed by intellij-monorepo-bot
parent 041de56103
commit 5905b6f62a
5 changed files with 59 additions and 4 deletions

View File

@@ -70,7 +70,7 @@ public final class TrivialFunctionalExpressionUsageInspection extends AbstractBa
}
};
}
public static void simplifyAllLambdas(@NotNull PsiElement context) {
List<@NotNull Problem> problems = SyntaxTraverser.psiTraverser(context)
.filter(PsiLambdaExpression.class)
@@ -96,7 +96,7 @@ public final class TrivialFunctionalExpressionUsageInspection extends AbstractBa
if (callParent instanceof PsiReturnStatement) {
return true;
}
PsiStatement[] statements = ((PsiCodeBlock)body).getStatements();
if (statements.length == 1) {
return statements[0] instanceof PsiReturnStatement && expression.isValueCompatible();
@@ -145,6 +145,7 @@ public final class TrivialFunctionalExpressionUsageInspection extends AbstractBa
call.getArgumentList().getExpressionCount() == method.getParameterList().getParametersCount() &&
elementContainerPredicate.test(call);
if (!suitableMethod) return null;
//if (SideEffectChecker.definitelyChangesSemantics(call)) return null;
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(interfaceType);
if (method == interfaceMethod || interfaceMethod != null && MethodSignatureUtil.isSuperMethod(interfaceMethod, method)) {
return new Problem(referenceNameElement, fix);
@@ -192,12 +193,14 @@ public final class TrivialFunctionalExpressionUsageInspection extends AbstractBa
List<PsiStatement> statements = new ArrayList<>();
PsiElementFactory factory = JavaPsiFacade.getElementFactory(lambda.getProject());
List<List<PsiExpression>> allSideEffects = ContainerUtil.map(arguments, SideEffectChecker::extractSideEffectExpressions);
int lastSideEffectIndex = ContainerUtil.lastIndexOf(allSideEffects, se -> !se.isEmpty());
for (int i = 0; i < arguments.length; i++) {
PsiExpression argument = arguments[i];
PsiParameter parameter = parameters[i];
List<PsiExpression> sideEffects = SideEffectChecker.extractSideEffectExpressions(argument);
if (!sideEffects.isEmpty()) {
if (i <= lastSideEffectIndex) {
boolean used = VariableAccessUtils.variableIsUsed(parameter, lambda.getBody());
if (used) {
String name = parameter.getName();
@@ -262,7 +265,7 @@ public final class TrivialFunctionalExpressionUsageInspection extends AbstractBa
}
}
}
private static void solveNameConflicts(PsiStatement[] statements, @NotNull PsiElement anchor, @NotNull PsiLambdaExpression lambda) {
Predicate<PsiVariable> allowedVar = variable -> PsiTreeUtil.isAncestor(lambda, variable, true);
Project project = anchor.getProject();

View File

@@ -0,0 +1,14 @@
// "Replace method call on lambda with lambda body" "true-preview"
import java.util.function.BinaryOperator;
public class Main {
public static void main(String[] args) {
int l = 1;
int q = 2;
System.out.println(l + " " + q);
Integer i = q;
q = l;
l = i;
System.out.println(l + " " + q);
}
}

View File

@@ -0,0 +1,14 @@
// "Replace method call on lambda with lambda body" "true-preview"
import java.util.function.IntBinaryOperator;
public class Main {
public static void main(String[] args) {
int l = 1;
int q = 2;
System.out.println(l + " " + q);
int i = q;
q++;
l = i;
System.out.println(l + " " + q);
}
}

View File

@@ -0,0 +1,12 @@
// "Replace method call on lambda with lambda body" "true-preview"
import java.util.function.BinaryOperator;
public class Main {
public static void main(String[] args) {
int l = 1;
int q = 2;
System.out.println(l + " " + q);
l = ((BinaryOperator<Integer>) (i, _) -> i).<caret>apply(q, q = l);
System.out.println(l + " " + q);
}
}

View File

@@ -0,0 +1,12 @@
// "Replace method call on lambda with lambda body" "true-preview"
import java.util.function.IntBinaryOperator;
public class Main {
public static void main(String[] args) {
int l = 1;
int q = 2;
System.out.println(l + " " + q);
l = ((IntBinaryOperator) (i, _) -> i).<caret>applyAsInt(q, q++);
System.out.println(l + " " + q);
}
}