mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-171248 Nullability: missing warning in for-each cycle
support for forEach lambda parameters
This commit is contained in:
@@ -17,12 +17,12 @@ package com.intellij.codeInspection.dataFlow;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.NullableNotNullManager;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.Instruction;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.ReturnInstruction;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.patterns.PsiJavaPatterns;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
@@ -93,15 +93,28 @@ public class DfaPsiUtil {
|
||||
Nullness fromType = getTypeNullability(resultType);
|
||||
if (fromType != Nullness.UNKNOWN) return fromType;
|
||||
|
||||
if (PsiJavaPatterns.psiParameter().withParents(PsiParameterList.class, PsiLambdaExpression.class).accepts(owner)) {
|
||||
PsiLambdaExpression lambda = (PsiLambdaExpression)owner.getParent().getParent();
|
||||
int index = lambda.getParameterList().getParameterIndex((PsiParameter)owner);
|
||||
return getFunctionalParameterNullability(lambda, index);
|
||||
if (owner instanceof PsiParameter) {
|
||||
return inferParameterNullability((PsiParameter)owner);
|
||||
}
|
||||
|
||||
return Nullness.UNKNOWN;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Nullness inferParameterNullability(@NotNull PsiParameter parameter) {
|
||||
PsiElement parent = parameter.getParent();
|
||||
if (parent instanceof PsiParameterList && parent.getParent() instanceof PsiLambdaExpression) {
|
||||
return getFunctionalParameterNullability((PsiLambdaExpression)parent.getParent(), ((PsiParameterList)parent).getParameterIndex(parameter));
|
||||
}
|
||||
if (parent instanceof PsiForeachStatement) {
|
||||
PsiExpression iteratedValue = ((PsiForeachStatement)parent).getIteratedValue();
|
||||
if (iteratedValue != null) {
|
||||
return getTypeNullability(JavaGenericsUtil.getCollectionItemType(iteratedValue));
|
||||
}
|
||||
}
|
||||
return Nullness.UNKNOWN;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Nullness getTypeNullability(@Nullable PsiType type) {
|
||||
if (type == null) return Nullness.UNKNOWN;
|
||||
@@ -142,7 +155,7 @@ public class DfaPsiUtil {
|
||||
if(nullness != Nullness.UNKNOWN) {
|
||||
return nullness;
|
||||
}
|
||||
PsiClassType type = ObjectUtils.tryCast(function.getFunctionalInterfaceType(), PsiClassType.class);
|
||||
PsiClassType type = ObjectUtils.tryCast(LambdaUtil.getFunctionalInterfaceType(function, true), PsiClassType.class);
|
||||
PsiMethod sam = LambdaUtil.getFunctionalInterfaceMethod(type);
|
||||
if (sam != null && index < sam.getParameterList().getParametersCount()) {
|
||||
PsiParameter parameter = sam.getParameterList().getParameters()[index];
|
||||
@@ -151,7 +164,7 @@ public class DfaPsiUtil {
|
||||
return nullness;
|
||||
}
|
||||
PsiType parameterType = type.resolveGenerics().getSubstitutor().substitute(parameter.getType());
|
||||
return getTypeNullability(parameterType);
|
||||
return getTypeNullability(GenericsUtil.eliminateWildcards(parameterType, false, true));
|
||||
}
|
||||
return Nullness.UNKNOWN;
|
||||
}
|
||||
|
||||
+13
-11
@@ -523,22 +523,24 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo
|
||||
PsiAnnotation annotation = isDeclaredNotNull == null ? isDeclaredNullable : isDeclaredNotNull;
|
||||
reportPrimitiveType(holder, annotation, annotation, parameter);
|
||||
}
|
||||
if (parameter.getParent() instanceof PsiForeachStatement) {
|
||||
PsiExpression iteratedValue = ((PsiForeachStatement)parameter.getParent()).getIteratedValue();
|
||||
Nullness itemTypeNullability = DfaPsiUtil.getTypeNullability(iteratedValue == null ? null : JavaGenericsUtil.getCollectionItemType(iteratedValue));
|
||||
if (isDeclaredNotNull != null && itemTypeNullability == Nullness.NULLABLE) {
|
||||
holder.registerProblem(isDeclaredNotNull, "Loop parameter can be null",
|
||||
new RemoveAnnotationQuickFix(isDeclaredNotNull, null));
|
||||
}
|
||||
else if (isDeclaredNullable != null && itemTypeNullability == Nullness.NOT_NULL) {
|
||||
holder.registerProblem(isDeclaredNullable, "Loop parameter is always not-null",
|
||||
new RemoveAnnotationQuickFix(isDeclaredNullable, null));
|
||||
}
|
||||
if (parameter instanceof PsiParameter) {
|
||||
checkLoopParameterNullability(holder, isDeclaredNotNull, isDeclaredNullable, DfaPsiUtil.inferParameterNullability((PsiParameter)parameter));
|
||||
}
|
||||
|
||||
return new Annotated(isDeclaredNotNull != null,isDeclaredNullable != null);
|
||||
}
|
||||
|
||||
private static void checkLoopParameterNullability(ProblemsHolder holder, @Nullable PsiAnnotation notNull, @Nullable PsiAnnotation nullable, Nullness expectedNullability) {
|
||||
if (notNull != null && expectedNullability == Nullness.NULLABLE) {
|
||||
holder.registerProblem(notNull, "Parameter can be null",
|
||||
new RemoveAnnotationQuickFix(notNull, null));
|
||||
}
|
||||
else if (nullable != null && expectedNullability == Nullness.NOT_NULL) {
|
||||
holder.registerProblem(nullable, "Parameter is always not-null",
|
||||
new RemoveAnnotationQuickFix(nullable, null));
|
||||
}
|
||||
}
|
||||
|
||||
private static void reportPrimitiveType(final ProblemsHolder holder, final PsiElement psiElement, final PsiAnnotation annotation,
|
||||
final PsiModifierListOwner listOwner) {
|
||||
holder.registerProblem(psiElement.isPhysical() ? psiElement : listOwner.getNavigationElement(),
|
||||
|
||||
+4
-2
@@ -11,11 +11,13 @@ class JC {
|
||||
}
|
||||
|
||||
void usage() {
|
||||
for (<warning descr="Loop parameter can be null">@NotNull</warning> Object o : getNullableStuff()) {
|
||||
for (<warning descr="Parameter can be null">@NotNull</warning> Object o : getNullableStuff()) {
|
||||
System.out.println(o.getClass());
|
||||
}
|
||||
for (<warning descr="Loop parameter is always not-null">@Nullable</warning> Object o : getNotNullStuff()) {
|
||||
for (<warning descr="Parameter is always not-null">@Nullable</warning> Object o : getNotNullStuff()) {
|
||||
System.out.println(o.getClass());
|
||||
}
|
||||
getNullableStuff().forEach((<warning descr="Parameter can be null">@NotNull</warning> Object s) -> System.out.println(s.hashCode()));
|
||||
getNotNullStuff().forEach((<warning descr="Parameter is always not-null">@Nullable</warning> Object s) -> System.out.println(s.hashCode()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user