diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java index 76f3d1b92a61..bf0f3d10b17a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaPsiUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.*; +import com.intellij.util.ArrayUtil; import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; @@ -102,6 +103,10 @@ public class DfaPsiUtil { if (PsiJavaPatterns.psiParameter().withParents(PsiParameterList.class, PsiLambdaExpression.class).accepts(owner)) { PsiLambdaExpression lambda = (PsiLambdaExpression)owner.getParent().getParent(); int index = lambda.getParameterList().getParameterIndex((PsiParameter)owner); + Nullness nullness = inferLambdaParameterNullness(lambda, index); + if(nullness != Nullness.UNKNOWN) { + return nullness; + } PsiMethod sam = LambdaUtil.getFunctionalInterfaceMethod(lambda.getFunctionalInterfaceType()); if (sam != null && index < sam.getParameterList().getParametersCount()) { return getElementNullability(null, sam.getParameterList().getParameters()[index]); @@ -111,6 +116,43 @@ public class DfaPsiUtil { return Nullness.UNKNOWN; } + @NotNull + private static Nullness inferLambdaParameterNullness(PsiLambdaExpression lambda, int parameterIndex) { + PsiElement expression = lambda; + PsiElement expressionParent = lambda.getParent(); + while(expressionParent instanceof PsiConditionalExpression) { + expression = expressionParent; + expressionParent = expressionParent.getParent(); + } + if(expressionParent instanceof PsiExpressionList) { + PsiExpressionList list = (PsiExpressionList)expressionParent; + PsiElement listParent = list.getParent(); + if(listParent instanceof PsiMethodCallExpression) { + PsiMethod method = ((PsiMethodCallExpression)listParent).resolveMethod(); + if(method != null) { + int expressionIndex = ArrayUtil.find(list.getExpressions(), expression); + return getLambdaParameterNullness(method, expressionIndex, parameterIndex); + } + } + } + return Nullness.UNKNOWN; + } + + @NotNull + private static Nullness getLambdaParameterNullness(@NotNull PsiMethod method, int parameterIndex, int lambdaParameterIndex) { + PsiClass type = method.getContainingClass(); + if(type != null) { + if(CommonClassNames.JAVA_UTIL_OPTIONAL.equals(type.getQualifiedName())) { + String methodName = method.getName(); + if((methodName.equals("map") || methodName.equals("filter") || methodName.equals("ifPresent") || methodName.equals("flatMap")) + && parameterIndex == 0 && lambdaParameterIndex == 0) { + return Nullness.NOT_NULL; + } + } + } + return Nullness.UNKNOWN; + } + private static boolean isNotNullLocally(@NotNull PsiModifierListOwner owner) { NullableNotNullManager nnnm = NullableNotNullManager.getInstance(owner.getProject()); PsiAnnotation notNullAnno = nnnm.getNotNullAnnotation(owner, true); diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/NotNullOptionalLambdaParameter.java b/java/java-tests/testData/inspection/dataFlow/fixture/NotNullOptionalLambdaParameter.java new file mode 100644 index 000000000000..508861cfb9c3 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/NotNullOptionalLambdaParameter.java @@ -0,0 +1,10 @@ +import java.util.stream.Stream; + +class Example { + public static void main(String[] args) { + Stream.of(args).filter(arg -> arg.startsWith("a")) + .findFirst().ifPresent(args.length == 1 ? value -> {} : value -> { + System.out.println(value == null ? "none" : value); + }); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspection8Test.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspection8Test.java index 0e766d54f1bd..1554016ddf7b 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspection8Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspection8Test.java @@ -49,6 +49,7 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase { public void testOptionalOfNullable() { doTest(); } public void testPrimitiveInVoidLambda() { doTest(); } public void testNotNullLambdaParameter() { doTest(); } + public void testNotNullOptionalLambdaParameter() { doTest(); } public void testNullArgumentIsFailingMethodCall() { doTest();