mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-171248 Nullabiltiy: missing warning in for-each cycle
This commit is contained in:
@@ -69,18 +69,8 @@ public class DfaPsiUtil {
|
||||
|
||||
@NotNull
|
||||
public static Nullness getElementNullability(@Nullable PsiType resultType, @Nullable PsiModifierListOwner owner) {
|
||||
if (resultType != null) {
|
||||
for (PsiAnnotation annotation : resultType.getAnnotations()) {
|
||||
String qualifiedName = annotation.getQualifiedName();
|
||||
NullableNotNullManager nnn = NullableNotNullManager.getInstance(annotation.getProject());
|
||||
if (nnn.getNullables().contains(qualifiedName)) {
|
||||
return Nullness.NULLABLE;
|
||||
}
|
||||
if (nnn.getNotNulls().contains(qualifiedName)) {
|
||||
return Nullness.NOT_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
Nullness x = getTypeNullability(resultType);
|
||||
if (x != Nullness.UNKNOWN) return x;
|
||||
|
||||
if (owner == null || resultType instanceof PsiPrimitiveType) {
|
||||
return Nullness.UNKNOWN;
|
||||
@@ -109,6 +99,23 @@ public class DfaPsiUtil {
|
||||
return Nullness.UNKNOWN;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Nullness getTypeNullability(@Nullable PsiType type) {
|
||||
if (type != null) {
|
||||
for (PsiAnnotation annotation : type.getAnnotations()) {
|
||||
String qualifiedName = annotation.getQualifiedName();
|
||||
NullableNotNullManager nnn = NullableNotNullManager.getInstance(annotation.getProject());
|
||||
if (nnn.getNullables().contains(qualifiedName)) {
|
||||
return Nullness.NULLABLE;
|
||||
}
|
||||
if (nnn.getNotNulls().contains(qualifiedName)) {
|
||||
return Nullness.NOT_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Nullness.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nullness of functional expression parameter
|
||||
*
|
||||
|
||||
+15
@@ -19,10 +19,12 @@ import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.NullableNotNullManager;
|
||||
import com.intellij.codeInsight.daemon.GroupNames;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
|
||||
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
|
||||
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.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
@@ -390,6 +392,19 @@ 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));
|
||||
}
|
||||
}
|
||||
|
||||
return new Annotated(isDeclaredNotNull != null,isDeclaredNullable != null);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import typeUse.*;
|
||||
import java.util.*;
|
||||
|
||||
class JC {
|
||||
|
||||
public static Collection<@Nullable Object> getNullableStuff() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
public static Collection<@NotNull Object> getNotNullStuff() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
void usage() {
|
||||
for (<warning descr="Loop 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()) {
|
||||
System.out.println(o.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import com.intellij.testFramework.IdeaTestUtil;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor;
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -128,9 +129,13 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase {
|
||||
}
|
||||
|
||||
private void setupCustomAnnotations() {
|
||||
myFixture.addClass("package foo;\n\nimport java.lang.annotation.*;\n\n@Target({ElementType.TYPE_USE}) public @interface Nullable { }");
|
||||
myFixture.addClass("package foo;\n\nimport java.lang.annotation.*;\n\n@Target({ElementType.TYPE_USE}) public @interface NotNull { }");
|
||||
setCustomAnnotations(getProject(), myFixture.getTestRootDisposable(), "foo.NotNull", "foo.Nullable");
|
||||
setupTypeUseAnnotations("foo", myFixture);
|
||||
}
|
||||
|
||||
static void setupTypeUseAnnotations(String pkg, JavaCodeInsightTestFixture fixture) {
|
||||
fixture.addClass("package " + pkg + ";\n\nimport java.lang.annotation.*;\n\n@Target({ElementType.TYPE_USE}) public @interface Nullable { }");
|
||||
fixture.addClass("package " + pkg + ";\n\nimport java.lang.annotation.*;\n\n@Target({ElementType.TYPE_USE}) public @interface NotNull { }");
|
||||
setCustomAnnotations(fixture.getProject(), fixture.getTestRootDisposable(), pkg + ".NotNull", pkg + ".Nullable");
|
||||
}
|
||||
|
||||
static void setCustomAnnotations(Project project, Disposable parentDisposable, String notNull, String nullable) {
|
||||
|
||||
@@ -202,4 +202,9 @@ public class NullableStuffInspectionTest extends LightCodeInsightFixtureTestCase
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testForeachParameterNullability() {
|
||||
DataFlowInspection8Test.setupTypeUseAnnotations("typeUse", myFixture);
|
||||
doTest();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user