mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
check that primitive types can't be nullity-annotated (IDEA-176629)
This commit is contained in:
+50
-16
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.codeInspection.nullable;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationTargetUtil;
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.NullableNotNullManager;
|
||||
import com.intellij.codeInsight.daemon.GroupNames;
|
||||
@@ -47,6 +48,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
@@ -140,6 +142,31 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo
|
||||
check(parameter, holder, parameter.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeElement(PsiTypeElement type) {
|
||||
NullableNotNullManager manager = NullableNotNullManager.getInstance(type.getProject());
|
||||
List<PsiAnnotation> annotations = getExclusiveAnnotations(type);
|
||||
|
||||
checkType(null, holder, type.getType(),
|
||||
ContainerUtil.find(annotations, a -> manager.getNotNulls().contains(a.getQualifiedName())),
|
||||
ContainerUtil.find(annotations, a -> manager.getNullables().contains(a.getQualifiedName())));
|
||||
}
|
||||
|
||||
private List<PsiAnnotation> getExclusiveAnnotations(PsiTypeElement type) {
|
||||
List<PsiAnnotation> annotations = ContainerUtil.newArrayList(type.getAnnotations());
|
||||
PsiTypeElement topMost = Objects.requireNonNull(SyntaxTraverser.psiApi().parents(type).filter(PsiTypeElement.class).last());
|
||||
PsiElement parent = topMost.getParent();
|
||||
if (parent instanceof PsiModifierListOwner && type.getType().equals(topMost.getType().getDeepComponentType())) {
|
||||
PsiModifierList modifierList = ((PsiModifierListOwner)parent).getModifierList();
|
||||
if (modifierList != null) {
|
||||
PsiAnnotation.TargetType[] targets = ArrayUtil.remove(AnnotationTargetUtil.getTargetsForLocation(modifierList), PsiAnnotation.TargetType.TYPE_USE);
|
||||
annotations.addAll(ContainerUtil.filter(modifierList.getAnnotations(),
|
||||
a -> AnnotationTargetUtil.isTypeAnnotation(a) && AnnotationTargetUtil.findAnnotationTarget(a, targets) == null));
|
||||
}
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAnnotation(PsiAnnotation annotation) {
|
||||
if (!AnnotationUtil.NOT_NULL.equals(annotation.getQualifiedName())) return;
|
||||
@@ -508,24 +535,31 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo
|
||||
this.isDeclaredNullable = isDeclaredNullable;
|
||||
}
|
||||
}
|
||||
private static Annotated check(final PsiModifierListOwner parameter, final ProblemsHolder holder, PsiType type) {
|
||||
private static Annotated check(final PsiModifierListOwner owner, final ProblemsHolder holder, PsiType type) {
|
||||
final NullableNotNullManager manager = NullableNotNullManager.getInstance(holder.getProject());
|
||||
PsiAnnotation isDeclaredNotNull = AnnotationUtil.findAnnotation(parameter, manager.getNotNulls());
|
||||
PsiAnnotation isDeclaredNullable = AnnotationUtil.findAnnotation(parameter, manager.getNullables());
|
||||
if (isDeclaredNullable != null && isDeclaredNotNull != null) {
|
||||
reportNullableNotNullConflict(holder, parameter, isDeclaredNullable, isDeclaredNotNull);
|
||||
}
|
||||
if ((isDeclaredNotNull != null || isDeclaredNullable != null) && type != null && TypeConversionUtil.isPrimitive(type.getCanonicalText())) {
|
||||
PsiAnnotation annotation = isDeclaredNotNull == null ? isDeclaredNullable : isDeclaredNotNull;
|
||||
reportPrimitiveType(holder, annotation, annotation, parameter);
|
||||
}
|
||||
if (parameter instanceof PsiParameter) {
|
||||
checkLoopParameterNullability(holder, isDeclaredNotNull, isDeclaredNullable, DfaPsiUtil.inferParameterNullability((PsiParameter)parameter));
|
||||
}
|
||||
PsiAnnotation isDeclaredNotNull = AnnotationUtil.findAnnotation(owner, manager.getNotNulls());
|
||||
PsiAnnotation isDeclaredNullable = AnnotationUtil.findAnnotation(owner, manager.getNullables());
|
||||
checkType(owner, holder, type, isDeclaredNotNull, isDeclaredNullable);
|
||||
|
||||
return new Annotated(isDeclaredNotNull != null,isDeclaredNullable != null);
|
||||
}
|
||||
|
||||
private static void checkType(@Nullable PsiModifierListOwner listOwner,
|
||||
ProblemsHolder holder,
|
||||
PsiType type,
|
||||
@Nullable PsiAnnotation notNull, @Nullable PsiAnnotation nullable) {
|
||||
if (nullable != null && notNull != null) {
|
||||
reportNullableNotNullConflict(holder, listOwner, nullable, notNull);
|
||||
}
|
||||
if ((notNull != null || nullable != null) && type != null && TypeConversionUtil.isPrimitive(type.getCanonicalText())) {
|
||||
PsiAnnotation annotation = notNull == null ? nullable : notNull;
|
||||
reportPrimitiveType(holder, annotation, listOwner);
|
||||
}
|
||||
if (listOwner instanceof PsiParameter) {
|
||||
checkLoopParameterNullability(holder, notNull, nullable, DfaPsiUtil.inferParameterNullability((PsiParameter)listOwner));
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
@@ -537,9 +571,9 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo
|
||||
}
|
||||
}
|
||||
|
||||
private static void reportPrimitiveType(final ProblemsHolder holder, final PsiElement psiElement, final PsiAnnotation annotation,
|
||||
final PsiModifierListOwner listOwner) {
|
||||
holder.registerProblem(psiElement.isPhysical() ? psiElement : listOwner.getNavigationElement(),
|
||||
private static void reportPrimitiveType(ProblemsHolder holder, PsiAnnotation annotation,
|
||||
@Nullable PsiModifierListOwner listOwner) {
|
||||
holder.registerProblem(!annotation.isPhysical() && listOwner != null ? listOwner.getNavigationElement() : annotation,
|
||||
InspectionsBundle.message("inspection.nullable.problems.primitive.type.annotation"),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new RemoveAnnotationQuickFix(annotation, listOwner));
|
||||
}
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class Y {
|
||||
public static @withTypeUse.Nullable byte @withTypeUse.Nullable [] getData3() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class Y {
|
||||
public static <warning descr="Primitive type members cannot be annotated">@typeUse.Nullable</warning> byte @typeUse.Nullable [] getData2() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -176,10 +176,14 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase {
|
||||
public void testIgnoreNullabilityOnPrimitiveCast() { doTestWithCustomAnnotations();}
|
||||
|
||||
public void testArrayComponentAndMethodAnnotationConflict() {
|
||||
setupCustomAnnotations("withTypeUse", "{ElementType.METHOD, ElementType.TYPE_USE}", myFixture);
|
||||
setupAmbiguousAnnotations("withTypeUse", myFixture);
|
||||
doTest();
|
||||
}
|
||||
|
||||
static void setupAmbiguousAnnotations(String pkg, JavaCodeInsightTestFixture fixture) {
|
||||
setupCustomAnnotations(pkg, "{ElementType.METHOD, ElementType.TYPE_USE}", fixture);
|
||||
}
|
||||
|
||||
public void testLambdaInlining() { doTest(); }
|
||||
|
||||
public void testOptionalInlining() {
|
||||
@@ -190,7 +194,7 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase {
|
||||
public void testStreamKnownSource() { doTest(); }
|
||||
|
||||
public void testMethodVsExpressionTypeAnnotationConflict() {
|
||||
setupCustomAnnotations("withTypeUse", "{ElementType.METHOD, ElementType.TYPE_USE}", myFixture);
|
||||
setupAmbiguousAnnotations("withTypeUse", myFixture);
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
+12
-1
@@ -65,7 +65,18 @@ public class NullableStuffInspectionTest extends LightCodeInsightFixtureTestCase
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testProblems() { doTest(); }
|
||||
public void testProblems() { doTest();}
|
||||
|
||||
public void testAnnotatingPrimitivesTypeUse() {
|
||||
DataFlowInspection8Test.setupTypeUseAnnotations("typeUse", myFixture);
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAnnotatingPrimitivesAmbiguous() {
|
||||
DataFlowInspection8Test.setupAmbiguousAnnotations("withTypeUse", myFixture);
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testProblems2() { doTest(); }
|
||||
public void testNullableFieldNotnullParam() { doTest(); }
|
||||
public void testNotNullFieldNullableParam() { doTest(); }
|
||||
|
||||
Reference in New Issue
Block a user