Fix NPE in JavaNullabilityChecker when checking equals-calls

This NPE was introduced in ce41b5745a
Prior to the latter change there was a synthetic PSI element for each
equals-related call, thus callOperationNode was not null here.

== are intentionally treated as safe calls, but for nullability checker
it's not relevant, it only should report warnings on real safe-calls
This commit is contained in:
Denis Zharkov
2017-12-14 14:29:47 +03:00
parent d64e8e3b33
commit fa6285d32a
7 changed files with 96 additions and 1 deletions
@@ -109,8 +109,9 @@ class JavaNullabilityChecker : AdditionalTypeChecker {
}
if (safeAccess) {
val safeAccessElement = c.call.callOperationNode?.psi ?: return
doIfNotNull(receiverArgument.type, { dataFlowValue }, c) {
c.trace.report(Errors.UNNECESSARY_SAFE_CALL.on(c.call.callOperationNode!!.psi, receiverArgument.type))
c.trace.report(Errors.UNNECESSARY_SAFE_CALL.on(safeAccessElement, receiverArgument.type))
}
return
@@ -0,0 +1,49 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// JSR305_GLOBAL_REPORT warn
// 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.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Nonnull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
public @interface NonNullApi {
}
// FILE: A.java
import spr.*;
@NonNullApi
public class A {
public String getBar() {
return "";
}
}
// FILE: main.kt
fun main(a: A) {
if (a.getBar() == "1" && a.hashCode() != 0) return
if (a.getBar() != "2" && a.hashCode() != 0) return
if (<!SENSELESS_COMPARISON!>a.getBar() == null<!> && a.hashCode() != 0) return
if (<!SENSELESS_COMPARISON!>a.getBar() != null<!> && a.hashCode() != 0) return
if (a.bar == "1" && a.hashCode() != 0) return
if (a.bar != "2" && a.hashCode() != 0) return
if (<!SENSELESS_COMPARISON!>a.bar == null<!> && a.hashCode() != 0) return
if (<!SENSELESS_COMPARISON!>a.bar != null<!> && a.hashCode() != 0) return
}
@@ -0,0 +1,21 @@
package
public fun main(/*0*/ a: A): kotlin.Unit
@spr.NonNullApi public open class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun getBar(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
package spr {
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FILE}) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) @kotlin.annotation.MustBeDocumented @javax.annotation.Nonnull @javax.annotation.meta.TypeQualifierDefault(value = {ElementType.METHOD, ElementType.PARAMETER}) public final annotation class NonNullApi : kotlin.Annotation {
public constructor NonNullApi()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@@ -294,6 +294,12 @@ public class ForeignAnnotationsNoAnnotationInClasspathTestGenerated extends Abst
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/typeQualifierDefault"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("equalsOnNonNull.kt")
public void testEqualsOnNonNull() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/typeQualifierDefault/equalsOnNonNull.kt");
doTest(fileName);
}
@TestMetadata("fieldsAreNullable.kt")
public void testFieldsAreNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/typeQualifierDefault/fieldsAreNullable.kt");
@@ -294,6 +294,12 @@ public class ForeignAnnotationsNoAnnotationInClasspathWithFastClassReadingTestGe
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/typeQualifierDefault"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("equalsOnNonNull.kt")
public void testEqualsOnNonNull() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/typeQualifierDefault/equalsOnNonNull.kt");
doTest(fileName);
}
@TestMetadata("fieldsAreNullable.kt")
public void testFieldsAreNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/typeQualifierDefault/fieldsAreNullable.kt");
@@ -294,6 +294,12 @@ public class ForeignAnnotationsTestGenerated extends AbstractForeignAnnotationsT
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/typeQualifierDefault"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("equalsOnNonNull.kt")
public void testEqualsOnNonNull() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/typeQualifierDefault/equalsOnNonNull.kt");
doTest(fileName);
}
@TestMetadata("fieldsAreNullable.kt")
public void testFieldsAreNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/typeQualifierDefault/fieldsAreNullable.kt");
@@ -294,6 +294,12 @@ public class JavacForeignAnnotationsTestGenerated extends AbstractJavacForeignAn
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/typeQualifierDefault"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("equalsOnNonNull.kt")
public void testEqualsOnNonNull() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/typeQualifierDefault/equalsOnNonNull.kt");
doTest(fileName);
}
@TestMetadata("fieldsAreNullable.kt")
public void testFieldsAreNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/foreignAnnotations/tests/jsr305/nullabilityWarnings/typeQualifierDefault/fieldsAreNullable.kt");