[java] IDEA-359811 Support experimentally container annotation @NotNullByDefault

GitOrigin-RevId: 0f02149f8f9313357bab47e7d62d6f1ccfea6f9b
This commit is contained in:
Tagir Valeev
2024-09-27 10:28:38 +02:00
committed by intellij-monorepo-bot
parent 70b05eb272
commit 087825794e
4 changed files with 101 additions and 5 deletions

View File

@@ -3,12 +3,36 @@ package com.intellij.codeInsight.annoPackages;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.Nullability;
import com.intellij.codeInsight.NullabilityAnnotationInfo;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
final class JetBrainsAnnotationSupport implements AnnotationPackageSupport {
@Override
public @Nullable NullabilityAnnotationInfo getNullabilityByContainerAnnotation(@NotNull PsiAnnotation anno,
@NotNull PsiElement context,
PsiAnnotation.TargetType @NotNull [] types,
boolean superPackage) {
if (superPackage) return null;
if (ArrayUtil.contains(PsiAnnotation.TargetType.LOCAL_VARIABLE, types) ||
ArrayUtil.contains(PsiAnnotation.TargetType.TYPE_PARAMETER, types)) {
return null;
}
if (!anno.hasQualifiedName(AnnotationUtil.NOT_NULL_BY_DEFAULT)) return null;
PsiType targetType = context instanceof PsiMethod method ? method.getReturnType() :
context instanceof PsiVariable variable ? variable.getType() :
context instanceof PsiJavaCodeReferenceElement && context.getParent() instanceof PsiTypeElement typeElement ? typeElement.getType() :
null;
if (PsiUtil.resolveClassInClassTypeOnly(targetType) instanceof PsiTypeParameter) return null;
return new NullabilityAnnotationInfo(anno, Nullability.NOT_NULL, true);
}
@Override
public @NotNull List<String> getNullabilityAnnotations(@NotNull Nullability nullability) {
return switch (nullability) {

View File

@@ -24,6 +24,7 @@ public class AnnotationUtil {
public static final String NULLABLE = "org.jetbrains.annotations.Nullable";
public static final String UNKNOWN_NULLABILITY = "org.jetbrains.annotations.UnknownNullability";
public static final String NOT_NULL = "org.jetbrains.annotations.NotNull";
public static final String NOT_NULL_BY_DEFAULT = "org.jetbrains.annotations.NotNullByDefault";
public static final String NON_NLS = "org.jetbrains.annotations.NonNls";
public static final String NLS = "org.jetbrains.annotations.Nls";

View File

@@ -0,0 +1,60 @@
import org.jetbrains.annotations.*;
import java.util.List;
@NotNullByDefault
public class JetBrainsNotNullByDefault {
String field;
String test(String param) {
if (<warning descr="Condition 'param == null' is always 'false'">param == null</warning>) {}
if (<warning descr="Condition 'field == null' is always 'false'">field == null</warning>) {}
String local = System.getProperty("a");
if (local == null) {}
return <warning descr="'null' is returned by the method declared as @NotNullByDefault">null</warning>;
}
<T> T generic(T param) {
if (param == null) {
return <warning descr="'null' is returned by the method which is not declared as @Nullable">param</warning>;
}
return <warning descr="'null' is returned by the method which is not declared as @Nullable">null</warning>;
}
<T> List<T> genericList(List<T> param) {
for (T t : param) {
if (t == null) {
return <warning descr="'null' is returned by the method declared as @NotNullByDefault">null</warning>;
}
}
return param;
}
void use2(String s) {
// T is inferred as String from "hello" type
if (generic("hello") == null) {}
// T is inferred as @NotNull String from the `s` type
if (<warning descr="Condition 'generic(s) == null' is always 'false'">generic(s) == null</warning>) {}
}
void use(List<String> list) {
// T is inferred as @NotNull String from the `list` type
for (String s : genericList(list)) {
if (<warning descr="Condition 's == null' is always 'false'">s == null</warning>) {}
}
}
static class StaticInner implements NullableMember {
public String myGet() {
return <warning descr="'null' is returned by the method declared as @NotNullByDefault">null</warning>;
}
@Override
public String get() {
return null;
}
}
}
interface NullableMember {
@Nullable String get();
}

View File

@@ -53,11 +53,11 @@ public class DataFlowInspection21Test extends DataFlowInspectionTestCase {
public void testPatterns() {
doTest();
}
public void testDeconstructionNullability() {
doTest();
}
public void testUnnamedPatterns() {
doTest();
}
@@ -77,7 +77,7 @@ public class DataFlowInspection21Test extends DataFlowInspectionTestCase {
public void testNewStringWrongEquals() { doTest(); }
public void testSwitchWhenReturnBoolean() { doTest(); }
public void testSkipSwitchExpressionWithThrow() { doTest(); }
public void testStringTemplates() {
@@ -131,8 +131,19 @@ public class DataFlowInspection21Test extends DataFlowInspectionTestCase {
public void testArrayElementWrappedInPureMethod() { doTest(); }
public void testArrayAddedIntoCollection() { doTest(); }
public void testInstanceOfPatternAffectNullity() { doTest(); }
public void testNullabilityInEnumSwitch() { doTest(); }
public void testJetBrainsNotNullByDefault() {
myFixture.addClass("""
package org.jetbrains.annotations;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.PACKAGE})\s
public @interface NotNullByDefault {}""");
doTest();
}
}