diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java index f1d0858eb5a5..5eca81ab6e23 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java @@ -25,6 +25,7 @@ import com.intellij.codeInsight.intention.impl.AddNotNullAnnotationFix; import com.intellij.codeInspection.*; import com.intellij.codeInspection.dataFlow.DfaPsiUtil; import com.intellij.codeInspection.dataFlow.Nullness; +import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.WriteExternalException; @@ -158,6 +159,51 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo } return false; } + + @Override + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + checkCollectionNullityOnAssignment(expression.getOperationSign(), expression.getLExpression().getType(), expression.getRExpression()); + } + + @Override + public void visitLocalVariable(PsiLocalVariable variable) { + PsiIdentifier identifier = variable.getNameIdentifier(); + if (identifier != null) { + checkCollectionNullityOnAssignment(identifier, variable.getType(), variable.getInitializer()); + } + } + + @Override + public void visitCallExpression(PsiCallExpression callExpression) { + PsiExpressionList argList = callExpression.getArgumentList(); + JavaResolveResult result = callExpression.resolveMethodGenerics(); + PsiMethod method = (PsiMethod)result.getElement(); + if (method == null || argList == null) return; + + PsiSubstitutor substitutor = result.getSubstitutor(); + PsiParameter[] parameters = method.getParameterList().getParameters(); + PsiExpression[] arguments = argList.getExpressions(); + for (int i = 0; i < arguments.length; i++) { + PsiExpression argument = arguments[i]; + if (i < parameters.length && + (i < parameters.length - 1 || !MethodCallInstruction.isVarArgCall(method, substitutor, arguments, parameters))) { + checkCollectionNullityOnAssignment(argument, substitutor.substitute(parameters[i].getType()), argument); + } + } + } + + private void checkCollectionNullityOnAssignment(@NotNull PsiElement errorElement, PsiType expectedType, PsiExpression assignedExpression) { + PsiType lItemType = JavaGenericsUtil.getCollectionItemType(expectedType, errorElement.getResolveScope()); + PsiType rItemType = assignedExpression == null ? null : JavaGenericsUtil.getCollectionItemType(assignedExpression); + + if (DfaPsiUtil.getTypeNullability(lItemType) == Nullness.NOT_NULL && + DfaPsiUtil.getTypeNullability(rItemType) == Nullness.NULLABLE) { + holder.registerProblem(errorElement, + "Assigning a collection of nullable elements into a collection of non-null elements", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING); + + } + } }; } diff --git a/java/java-tests/testData/inspection/nullableProblems/PassingNullableCollectionWhereNotNullIsExpected.java b/java/java-tests/testData/inspection/nullableProblems/PassingNullableCollectionWhereNotNullIsExpected.java new file mode 100644 index 000000000000..fecc38e39a94 --- /dev/null +++ b/java/java-tests/testData/inspection/nullableProblems/PassingNullableCollectionWhereNotNullIsExpected.java @@ -0,0 +1,21 @@ +import typeUse.*; +import java.util.*; + +class JC { + + public static void main(String[] args) { + List<@Nullable String> list = new ArrayList<>(); + print(list); + + List<@NotNull String> list2 = list; + + List<@NotNull String> list3; + list2 = list; + } + + private static void print(List<@NotNull String> list) { + for (String s : list) { + System.out.println(s.length()); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionTest.java index 4f95f5cd5494..7303709d892f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/NullableStuffInspectionTest.java @@ -207,4 +207,9 @@ public class NullableStuffInspectionTest extends LightCodeInsightFixtureTestCase doTest(); } + public void testPassingNullableCollectionWhereNotNullIsExpected() { + DataFlowInspection8Test.setupTypeUseAnnotations("typeUse", myFixture); + doTest(); + } + } \ No newline at end of file