[FIR] Implement UNNECESSARY_NOT_NULL_ASSERTION checker for java warning level types

This commit is contained in:
Kirill Rakhman
2024-01-03 10:39:59 +01:00
committed by Space Team
parent d6bd31b313
commit 7fb5cbd1f8
24 changed files with 52 additions and 823 deletions
@@ -1,91 +0,0 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: warn
// FILE: MyNullable.java
import javax.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Documented
@TypeQualifierNickname
@Nonnull(when = When.MAYBE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyNullable {
}
// FILE: MyCheckForNull.java
import javax.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Documented
@TypeQualifierNickname
@CheckForNull
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCheckForNull {
}
// FILE: MyNonnull.java
import javax.annotation.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Documented
@TypeQualifierNickname
@Nonnull(when = When.ALWAYS)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyNonnull {
}
// FILE: A.java
import javax.annotation.*;
public class A {
@MyNullable public String field = null;
@MyNullable
public String foo(@MyNonnull String x, @MyNullable CharSequence y) {
return "";
}
@MyNonnull
public String bar() {
return "";
}
@MyCheckForNull
public String baz(@MyNonnull String x, @MyCheckForNull CharSequence y) {
return "";
}
}
// FILE: main.kt
fun main(a: A) {
a.foo("", null)?.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo("", null)<!>.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "")<!>.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.baz("", null)<!>.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.baz(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "")<!>.length
a.bar().length
a.bar()!!.length
a.field?.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.field<!>.length
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: warn
@@ -1,181 +0,0 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: warn
// FILE: NonNullApi.java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public @interface NonNullApi {
}
// FILE: NullableApi.java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.CheckForNull;
import javax.annotation.meta.TypeQualifierDefault;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@CheckForNull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public @interface NullableApi {
}
// FILE: FieldsAreNullable.java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.CheckForNull;
import javax.annotation.meta.TypeQualifierDefault;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@CheckForNull
@TypeQualifierDefault({ElementType.FIELD})
public @interface FieldsAreNullable {
}
// FILE: A.java
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
@NonNullApi
public class A {
public String field = null;
public String foo(String x, @CheckForNull CharSequence y) {
return "";
}
@NullableApi
public String foobar(String x, @Nonnull CharSequence y) {
return "";
}
public String bar() {
return "";
}
@Nullable
public java.util.List<String> baz() {
return null;
}
@NullableApi
public class B {
public String field = null;
public String foo(String x, @Nonnull CharSequence y) {
return "";
}
@NonNullApi
public String foobar(String x, @Nullable CharSequence y) {
return "";
}
public String bar() {
return "";
}
@Nullable
public java.util.List<String> baz() {
return null;
}
}
@FieldsAreNullable
public class C {
public String field = null;
public String foo(String x, @Nullable CharSequence y) {
return "";
}
@NullableApi
public String foobar(String x, @Nullable CharSequence y) {
return "";
}
public String bar() {
return "";
}
@Nullable
public java.util.List<String> baz() {
return null;
}
}
}
// FILE: main.kt
fun main(a: A, b: A.B, c: A.C) {
a.foo("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.foo("", null).length
a.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "").length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.foobar(null, "")<!>.length
a.foobar("", <!NULL_FOR_NONNULL_TYPE!>null<!>)?.length
a.bar().length
a.bar()!!.length
a.field<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.field.length
a.baz()<!UNSAFE_CALL!>.<!>get(0)
a.baz()!!.get(0).get(0)
a.baz()!!.get(0)?.get(0)
// b
b.foo("", <!NULL_FOR_NONNULL_TYPE!>null<!>)?.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>b.foo("", <!NULL_FOR_NONNULL_TYPE!>null<!>)<!>.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>b.foo(null, "")<!>.length
b.foobar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "").length
b.foobar("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>b.bar()<!>.length
b.bar()!!.length
b.field?.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>b.field<!>.length
b.baz()<!UNSAFE_CALL!>.<!>get(0)
b.baz()!!.get(0).get(0)
b.baz()!!.get(0)?.get(0)
// c
c.foo("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
c.foo("", null).length
c.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "").length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>c.foobar(null, "")<!>.length
c.foobar("", null)?.length
c.bar().length
c.bar()!!.length
c.field?.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>c.field<!>.length
c.baz()<!UNSAFE_CALL!>.<!>get(0)
c.baz()!!.get(0).get(0)
c.baz()!!.get(0)?.get(0)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: warn
@@ -68,7 +68,7 @@ fun main(a: A) {
a.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "").length
a.bar().length
a.bar()!!.length
a.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
a.field?.length
a.field.length
@@ -1,84 +0,0 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: warn
// FILE: spr/Nullable.java
package spr;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierNickname;
import javax.annotation.meta.When;
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull(when = When.MAYBE)
@TypeQualifierNickname
public @interface Nullable {
}
// FILE: spr/NonNullApi.java
package spr;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;
@Target(ElementType.PACKAGE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
public @interface NonNullApi {
}
// FILE: test/package-info.java
@spr.NonNullApi()
package test;
// FILE: test/A.java
package test;
import spr.*;
public class A {
public String field = null;
public String foo(String x, @Nullable CharSequence y) {
return "";
}
public String bar() {
return "";
}
@Nullable
public java.util.List<String> baz() {
return null;
}
}
// FILE: main.kt
fun main(a: test.A) {
a.foo("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.foo("", null).length
a.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "").length
a.bar().length
a.bar()!!.length
a.field?.length
a.field.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>a.baz()<!>.get(0)
a.baz()!!.get(0).get(0)
a.baz()!!.get(0)?.get(0)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT: warn