[FIR] Implement UNNECESSARY_SAFE_CALL checker for java warning level types

#KT-63528 Fixed
This commit is contained in:
Kirill Rakhman
2024-01-02 17:22:55 +01:00
committed by Space Team
parent 9c0ac27307
commit d6bd31b313
17 changed files with 66 additions and 288 deletions
@@ -43,10 +43,10 @@ fun main(a: A<String>, a1: A<String?>) {
a1.baz(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>)!!.length
a.baz2("").length
a.baz2("")?.length
a.baz2("")<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.baz2("")!!.length
a.baz2(null).length
a.baz2(null)?.length
a.baz2(null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.baz2(null)!!.length
}
@@ -1,38 +0,0 @@
// FILE: ClassWithExternalAnnotatedMembers.java
import org.jetbrains.annotations.NotNull;
public class ClassWithExternalAnnotatedMembers {
public String externalNotNullField;
@NotNull
public String explicitNotNullField;
public static String staticExternalNotNullField;
@NotNull
public static String staticExplicitNotNullField;
}
// FILE: usage.kt
fun test() {
val x = ClassWithExternalAnnotatedMembers()
x.externalNotNullField?.foo()
x.explicitNotNullField<!UNNECESSARY_SAFE_CALL!>?.<!>foo()
ClassWithExternalAnnotatedMembers.staticExternalNotNullField?.foo()
ClassWithExternalAnnotatedMembers.staticExplicitNotNullField<!UNNECESSARY_SAFE_CALL!>?.<!>foo()
}
fun String.foo() {
}
// FILE: annotations.xml
<root>
<item name='ClassWithExternalAnnotatedMembers externalNotNullField'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='ClassWithExternalAnnotatedMembers staticExternalNotNullField'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// FILE: ClassWithExternalAnnotatedMembers.java
import org.jetbrains.annotations.NotNull;
@@ -1,44 +0,0 @@
// FILE: one/two/ClassWithExternalAnnotatedMembers.java
package one.two;
import org.jetbrains.annotations.NotNull;
public class ClassWithExternalAnnotatedMembers {
public String externalNotNullField;
@NotNull
public String explicitNotNullField;
public static String staticExternalNotNullField;
@NotNull
public static String staticExplicitNotNullField;
}
// FILE: one/usage.kt
package one
import one.two.ClassWithExternalAnnotatedMembers
fun test() {
val x = ClassWithExternalAnnotatedMembers()
x.externalNotNullField?.foo()
x.explicitNotNullField<!UNNECESSARY_SAFE_CALL!>?.<!>foo()
ClassWithExternalAnnotatedMembers.staticExternalNotNullField?.foo()
ClassWithExternalAnnotatedMembers.staticExplicitNotNullField<!UNNECESSARY_SAFE_CALL!>?.<!>foo()
}
fun String.foo() {
}
// FILE: one/two/annotations.xml
<root>
<item name='one.two.ClassWithExternalAnnotatedMembers externalNotNullField'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='one.two.ClassWithExternalAnnotatedMembers staticExternalNotNullField'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// FILE: one/two/ClassWithExternalAnnotatedMembers.java
package one.two;
@@ -1,46 +0,0 @@
// FILE: ClassWithExternalAnnotatedMembers.java
import org.jetbrains.annotations.NotNull;
public class ClassWithExternalAnnotatedMembers {
public String externalNotNullMethod() {
return "";
}
@NotNull
public String explicitNotNullMethod() {
return "";
}
public static String staticExternalNotNullMethod() {
return "";
}
@NotNull
public static String staticExplicitNotNullMethod() {
return "";
}
}
// FILE: usage.kt
fun test() {
val x = ClassWithExternalAnnotatedMembers()
x.externalNotNullMethod()?.foo()
x.explicitNotNullMethod()<!UNNECESSARY_SAFE_CALL!>?.<!>foo()
ClassWithExternalAnnotatedMembers.staticExternalNotNullMethod()?.foo()
ClassWithExternalAnnotatedMembers.staticExplicitNotNullMethod()<!UNNECESSARY_SAFE_CALL!>?.<!>foo()
}
fun String.foo() {
}
// FILE: annotations.xml
<root>
<item name='ClassWithExternalAnnotatedMembers java.lang.String externalNotNullMethod()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='ClassWithExternalAnnotatedMembers java.lang.String staticExternalNotNullMethod()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// FILE: ClassWithExternalAnnotatedMembers.java
import org.jetbrains.annotations.NotNull;
@@ -1,71 +0,0 @@
// MODULE: javaModule
// FILE: one/two/FirstModuleClass.java
package one.two;
import org.jetbrains.annotations.NotNull;
public class FirstModuleClass {
public String externalNotNullMethod() {
return "";
}
@NotNull
public String explicitNotNullMethod() {
return "";
}
}
// FILE: one/two/annotations.xml
<root>
<item name='one.two.FirstModuleClass java.lang.String externalNotNullMethod()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
// FILE: usage.kt
package usage1
import one.two.FirstModuleClass
fun test() {
val x = FirstModuleClass()
x.externalNotNullMethod()?.foo()
x.explicitNotNullMethod()<!UNNECESSARY_SAFE_CALL!>?.<!>foo()
}
fun String.foo() {
}
// MODULE: javaModule2
// FILE: three/SecondModuleClass.java
package three;
import org.jetbrains.annotations.NotNull;
public class SecondModuleClass {
public static String staticExternalNotNullMethod() {
return "";
}
@NotNull
public static String staticExplicitNotNullMethod() {
return "";
}
}
// FILE: three/annotations.xml
<root>
<item name='three.SecondModuleClass java.lang.String staticExternalNotNullMethod()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
// FILE: my/pack/usage.kt
package my.pack
import three.SecondModuleClass
fun test() {
SecondModuleClass.staticExternalNotNullMethod()?.foo()
SecondModuleClass.staticExplicitNotNullMethod()<!UNNECESSARY_SAFE_CALL!>?.<!>foo()
}
fun String.foo() {
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// MODULE: javaModule
// FILE: one/two/FirstModuleClass.java
package one.two;
@@ -1,72 +0,0 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
// JSR305_GLOBAL_REPORT: warn
// FILE: MyNotNull.java
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierNickname;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Nonnull
@TypeQualifierNickname
@Retention(RetentionPolicy.RUNTIME)
public @interface MyNotNull {}
// FILE: AnnotatedWithJsr.java
public class AnnotatedWithJsr {
@MyNotNull
public String getString() {
return null;
}
public void consumeString(@MyNotNull String s) { }
}
// FILE: AnnotatedWithJB.java
import org.jetbrains.annotations.NotNull;
public class AnnotatedWithJB {
public @NotNull String getString() {
return "hello";
}
public void consumeString(@NotNull String s) { }
}
// FILE: PlainJava.java
public class PlainJava {
public String getString() {
return null;
}
public void consumeString(String s) { }
}
// FILE: main.kt
val jsr: AnnotatedWithJsr = AnnotatedWithJsr()
val jsrNullable: AnnotatedWithJsr? = null
val jb: AnnotatedWithJB = AnnotatedWithJB()
val jbNullable: AnnotatedWithJB? = null
val platform: PlainJava = PlainJava()
val platformNullable: PlainJava? = null
fun safeCalls() {
val a = jsr.string?.length
val b = jsrNullable?.string?.length
val c = jb.string<!UNNECESSARY_SAFE_CALL!>?.<!>length
val d = jbNullable?.string?.length
val e = platform.string?.length
val f = platformNullable?.string?.length
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_VARIABLE
// JSR305_GLOBAL_REPORT: warn
@@ -126,7 +126,7 @@ public class A {
// FILE: main.kt
fun main(a: A, b: A.B, c: A.C) {
a.foo("", null)?.length
a.foo("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.foo("", null).length
a.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "").length
@@ -136,7 +136,7 @@ fun main(a: A, b: A.B, c: A.C) {
a.bar().length
a.bar()!!.length
a.field?.length
a.field<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.field.length
a.baz()<!UNSAFE_CALL!>.<!>get(0)
@@ -149,7 +149,7 @@ fun main(a: A, b: A.B, c: A.C) {
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>b.foo(null, "")<!>.length
b.foobar(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "").length
b.foobar("", null)?.length
b.foobar("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>b.bar()<!>.length
b.bar()!!.length
@@ -162,7 +162,7 @@ fun main(a: A, b: A.B, c: A.C) {
b.baz()!!.get(0)?.get(0)
// c
c.foo("", null)?.length
c.foo("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
c.foo("", null).length
c.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "").length
@@ -63,7 +63,7 @@ public class A {
// FILE: main.kt
fun main(a: A) {
a.foo("", null)?.length
a.foo("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.foo("", null).length
a.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "").length
@@ -68,7 +68,7 @@ public class A {
// FILE: main.kt
fun main(a: test.A) {
a.foo("", null)?.length
a.foo("", null)<!UNNECESSARY_SAFE_CALL!>?.<!>length
a.foo("", null).length
a.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, "").length