mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-dfa] Do not dereference method reference qualifier for static method references
Fixes IDEA-290952 Constant conditions & expression warns about NullPointerException for Objects.nonNull with checked "Treat non-annotated members and parameters as @Nullable" GitOrigin-RevId: 88b063f12031b85dfa9fb7a009f75ebf0673760a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9f2ea8fe74
commit
299d0bed02
+3
-1
@@ -441,7 +441,9 @@ public class MethodCallInstruction extends ExpressionPushingInstruction {
|
||||
DfaValue value = memState.pop();
|
||||
if (getContext() instanceof PsiMethodReferenceExpression) {
|
||||
PsiMethodReferenceExpression context = (PsiMethodReferenceExpression)getContext();
|
||||
value = CheckNotNullInstruction.dereference(interpreter, memState, value, NullabilityProblemKind.callMethodRefNPE.problem(context, null));
|
||||
if (MethodReferenceInstruction.isQualifierDereferenced(context)) {
|
||||
value = CheckNotNullInstruction.dereference(interpreter, memState, value, NullabilityProblemKind.callMethodRefNPE.problem(context, null));
|
||||
}
|
||||
}
|
||||
DfType dfType = memState.getDfType(value);
|
||||
if (getMutationSignature().mutatesThis() && !Mutability.fromDfType(dfType).canBeModified()) {
|
||||
|
||||
+14
-4
@@ -56,7 +56,10 @@ public class MethodReferenceInstruction extends ExpressionPushingInstruction {
|
||||
if (method == null) return;
|
||||
PsiSubstitutor substitutor = resolveResult.getSubstitutor();
|
||||
DfaCallArguments callArguments = getMethodReferenceCallArguments(state, methodRef, qualifier, interpreter, sam, method, substitutor);
|
||||
CheckNotNullInstruction.dereference(interpreter, state, callArguments.getQualifier(), NullabilityProblemKind.callMethodRefNPE.problem(methodRef, null));
|
||||
if (isQualifierDereferenced(methodRef)) {
|
||||
CheckNotNullInstruction.dereference(interpreter, state, callArguments.getQualifier(),
|
||||
NullabilityProblemKind.callMethodRefNPE.problem(methodRef, null));
|
||||
}
|
||||
List<? extends MethodContract> contracts = JavaMethodContractUtil.getMethodCallContracts(method, null);
|
||||
if (contracts.isEmpty() || !JavaMethodContractUtil.isPure(method)) return;
|
||||
PsiType returnType = substitutor.substitute(method.getReturnType());
|
||||
@@ -81,6 +84,15 @@ public class MethodReferenceInstruction extends ExpressionPushingInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isQualifierDereferenced(@NotNull PsiMethodReferenceExpression methodRef) {
|
||||
if (methodRef.isConstructor()) return false;
|
||||
PsiElement target = methodRef.resolve();
|
||||
if (!(target instanceof PsiMethod)) return false;
|
||||
if (((PsiMethod)target).hasModifierProperty(PsiModifier.STATIC)) return false;
|
||||
if (!PsiMethodReferenceUtil.isStaticallyReferenced(methodRef)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static @NotNull DfaCallArguments getMethodReferenceCallArguments(@NotNull DfaMemoryState state,
|
||||
@NotNull PsiMethodReferenceExpression methodRef,
|
||||
DfaValue qualifier,
|
||||
@@ -89,9 +101,7 @@ public class MethodReferenceInstruction extends ExpressionPushingInstruction {
|
||||
@NotNull PsiMethod method,
|
||||
@NotNull PsiSubstitutor substitutor) {
|
||||
PsiParameter[] samParameters = sam.getParameterList().getParameters();
|
||||
boolean isStatic = method.hasModifierProperty(PsiModifier.STATIC);
|
||||
boolean instanceBound = !isStatic && !method.isConstructor() && !PsiMethodReferenceUtil.isStaticallyReferenced(methodRef);
|
||||
boolean firstParameterIsQualifier = !isStatic && !instanceBound && !method.isConstructor();
|
||||
boolean firstParameterIsQualifier = isQualifierDereferenced(methodRef);
|
||||
PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
DfaValue[] arguments = new DfaValue[parameters.length];
|
||||
Arrays.fill(arguments, interpreter.getFactory().getUnknown());
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import java.util.*;
|
||||
import java.util.function.*;
|
||||
import typeUse.*;
|
||||
|
||||
public class ObjectsNonNullWithUnknownNullable {
|
||||
void foo(@NotNull List<@NotNull String> list) {
|
||||
Predicate<String> predicate = Objects::nonNull;
|
||||
list.stream()
|
||||
.map(s -> s.isEmpty() ? null : s)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(System.out::println);
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,10 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase {
|
||||
public void testUnboxingBoxingInLambdaReturn() { doTest(); }
|
||||
public void testUnboxingInMethodReferences() { doTest(); }
|
||||
public void testMethodReferenceOnNullable() { doTest(); }
|
||||
public void testObjectsNonNullWithUnknownNullable() {
|
||||
setupTypeUseAnnotations("typeUse", myFixture);
|
||||
doTestWith(insp -> insp.TREAT_UNKNOWN_MEMBERS_AS_NULLABLE = true);
|
||||
}
|
||||
public void testNullableVoidLambda() { doTest(); }
|
||||
public void testNullableForeachVariable() { doTestWithCustomAnnotations(); }
|
||||
public void testGenericParameterNullity() { doTestWithCustomAnnotations(); }
|
||||
|
||||
Reference in New Issue
Block a user