FIR: add equality call checker
Added checker for FirEqualityOperatorCall. It's surfaced as one of the following diagnostics depending on the PSI structure and types under comparison: * INCOMPATIBLE_TYPES(_WARNING) * EQUALITY_NOT_APPLICABLE(_WARNING) * INCOMPATIBLE_ENUM_COMPARISON_ERROR Comparing with FE1.0, the current implementation is more conservative and only highlights error if the types are known to follow certain contracts with `equals` method. Otherwise, the checker reports warnings instead. However, the current checker is more strict in the following situations: 1. it now rejects incompatible enum types like `Enum<E1>` and `Enum<E2>`, which was previously accepted 2. it now rejects incompatible class types like `Class<String>` and `Class<Int>`, which was previously accepted 3. the check now takes smart cast into consideration, so `if (x is String) x == 3` is now rejected
This commit is contained in:
committed by
teamcityserver
parent
787c743333
commit
7bb81ef157
Vendored
+2
-2
@@ -3,8 +3,8 @@
|
||||
// TESTCASE NUMBER: 1
|
||||
fun case_1(value_1: Int, value_2: TypesProvider): String {
|
||||
when (value_1) {
|
||||
-1000L..100 -> return ""
|
||||
value_2.getInt()..getLong() -> return ""
|
||||
<!INCOMPATIBLE_TYPES!>-1000L..100<!> -> return ""
|
||||
<!INCOMPATIBLE_TYPES!>value_2.getInt()..getLong()<!> -> return ""
|
||||
}
|
||||
|
||||
return ""
|
||||
|
||||
@@ -55,7 +55,7 @@ fun case_4(x: Char?) {
|
||||
fun case_5() {
|
||||
val x: Unit? = null
|
||||
|
||||
if (x !== <!USELESS_IS_CHECK!>null is Boolean?<!>) <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Unit?")!>x<!>
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>x !== <!USELESS_IS_CHECK!>null is Boolean?<!>) <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Unit?")!>x<!>
|
||||
if (x !== null == null) <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Unit?")!>x<!><!UNSAFE_CALL!>.<!>equals(null)
|
||||
if (x !== null == null) <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Unit?")!>x<!>.propT
|
||||
if (x !== null == null) <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Unit?")!>x<!><!UNSAFE_CALL!>.<!>propAny
|
||||
@@ -87,7 +87,7 @@ fun case_6(x: EmptyClass?) {
|
||||
|
||||
// TESTCASE NUMBER: 7
|
||||
fun case_7() {
|
||||
if (nullableNumberProperty != null || <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number?")!>nullableNumberProperty<!> != null is Boolean) {
|
||||
if (nullableNumberProperty != null || <!EQUALITY_NOT_APPLICABLE!><!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number?")!>nullableNumberProperty<!> != null is Boolean<!>) {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number?")!>nullableNumberProperty<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number?")!>nullableNumberProperty<!><!UNSAFE_CALL!>.<!>equals(null)
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Number?")!>nullableNumberProperty<!>.propT
|
||||
@@ -141,12 +141,12 @@ fun case_10() {
|
||||
fun case_11(x: TypealiasNullableStringIndirect?, y: TypealiasNullableStringIndirect) {
|
||||
val t: TypealiasNullableStringIndirect = null
|
||||
|
||||
if (x == null is Boolean) {
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>x == null is Boolean<!>) {
|
||||
|
||||
} else {
|
||||
if (y != null is Boolean == true) {
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>y != null is Boolean<!> == true) {
|
||||
if (<!USELESS_IS_CHECK!>(nullableStringProperty == null) !is Boolean<!>) {
|
||||
if (t != null is Boolean) {
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>t != null is Boolean<!>) {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypealiasNullableStringIndirect?")!>x<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypealiasNullableStringIndirect?")!>x<!>.equals(null)
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypealiasNullableStringIndirect?")!>x<!>.propT
|
||||
@@ -236,7 +236,7 @@ fun case_14() {
|
||||
|
||||
// TESTCASE NUMBER: 15
|
||||
fun case_15(x: EmptyObject) {
|
||||
val t = if (x === <!USELESS_IS_CHECK!><!USELESS_IS_CHECK!>null is Boolean is Boolean<!> is Boolean<!>) "" else {
|
||||
val t = if (<!EQUALITY_NOT_APPLICABLE!>x === <!USELESS_IS_CHECK!><!USELESS_IS_CHECK!>null is Boolean is Boolean<!> is Boolean<!>) "" else {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("EmptyObject")!>x<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("EmptyObject")!>x<!>.equals(null)
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("EmptyObject")!>x<!>.propT
|
||||
@@ -254,7 +254,7 @@ fun case_15(x: EmptyObject) {
|
||||
fun case_16() {
|
||||
val x: TypealiasNullableNothing = null
|
||||
|
||||
if (x != <!USELESS_IS_CHECK!><!USELESS_IS_CHECK!><!USELESS_IS_CHECK!><!USELESS_IS_CHECK!>null !is Boolean !is Boolean<!> !is Boolean<!> !is Boolean<!> !is Boolean<!>) {
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>x != <!USELESS_IS_CHECK!><!USELESS_IS_CHECK!><!USELESS_IS_CHECK!><!USELESS_IS_CHECK!>null !is Boolean !is Boolean<!> !is Boolean<!> !is Boolean<!> !is Boolean<!>) {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypealiasNullableNothing")!>x<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypealiasNullableNothing")!>x<!><!UNSAFE_CALL!>.<!>java
|
||||
}
|
||||
@@ -302,7 +302,7 @@ fun case_19(b: Boolean) {
|
||||
}
|
||||
} else null
|
||||
|
||||
if (a != null !is Boolean && a<!UNSAFE_CALL!>.<!>B19 != null is Boolean && a<!UNSAFE_CALL!>.<!>B19<!UNSAFE_CALL!>.<!>C19 != null is Boolean && a<!UNSAFE_CALL!>.<!>B19<!UNSAFE_CALL!>.<!>C19<!UNSAFE_CALL!>.<!>D19 != null == null && a<!UNSAFE_CALL!>.<!>B19<!UNSAFE_CALL!>.<!>C19<!UNSAFE_CALL!>.<!>D19<!UNSAFE_CALL!>.<!>x != null !== null) {
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>a != null !is Boolean<!> && <!EQUALITY_NOT_APPLICABLE!>a<!UNSAFE_CALL!>.<!>B19 != null is Boolean<!> && <!EQUALITY_NOT_APPLICABLE!>a<!UNSAFE_CALL!>.<!>B19<!UNSAFE_CALL!>.<!>C19 != null is Boolean<!> && a<!UNSAFE_CALL!>.<!>B19<!UNSAFE_CALL!>.<!>C19<!UNSAFE_CALL!>.<!>D19 != null == null && a<!UNSAFE_CALL!>.<!>B19<!UNSAFE_CALL!>.<!>C19<!UNSAFE_CALL!>.<!>D19<!UNSAFE_CALL!>.<!>x != null !== null) {
|
||||
a<!UNSAFE_CALL!>.<!>B19<!UNSAFE_CALL!>.<!>C19<!UNSAFE_CALL!>.<!>D19<!UNSAFE_CALL!>.<!>x
|
||||
a<!UNSAFE_CALL!>.<!>B19<!UNSAFE_CALL!>.<!>C19<!UNSAFE_CALL!>.<!>D19<!UNSAFE_CALL!>.<!>x<!UNSAFE_CALL!>.<!>equals(null)
|
||||
a<!UNSAFE_CALL!>.<!>B19<!UNSAFE_CALL!>.<!>C19<!UNSAFE_CALL!>.<!>D19<!UNSAFE_CALL!>.<!>x.propT
|
||||
@@ -328,7 +328,7 @@ fun case_20(b: Boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
if (a.B19.C19.D19 !== null !is Boolean) {
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>a.B19.C19.D19 !== null !is Boolean<!>) {
|
||||
a.B19.C19.D19
|
||||
a.B19.C19.D19<!UNSAFE_CALL!>.<!>equals(null)
|
||||
a.B19.C19.D19.propT
|
||||
@@ -344,7 +344,7 @@ fun case_20(b: Boolean) {
|
||||
|
||||
// TESTCASE NUMBER: 21
|
||||
fun case_21() {
|
||||
if (EnumClassWithNullableProperty.B.prop_1 !== null is Boolean == <!USELESS_IS_CHECK!>true !is Boolean<!> != true) {
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>EnumClassWithNullableProperty.B.prop_1 !== null is Boolean<!> == <!USELESS_IS_CHECK!>true !is Boolean<!> != true) {
|
||||
EnumClassWithNullableProperty.B.prop_1
|
||||
EnumClassWithNullableProperty.B.prop_1<!UNSAFE_CALL!>.<!>equals(null)
|
||||
EnumClassWithNullableProperty.B.prop_1.propT
|
||||
@@ -360,7 +360,7 @@ fun case_21() {
|
||||
|
||||
// TESTCASE NUMBER: 22
|
||||
fun case_22(a: (() -> Unit)?) {
|
||||
if (a != null !is Boolean) {
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>a != null !is Boolean<!>) {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Unit")!><!UNSAFE_IMPLICIT_INVOKE_CALL!>a<!>()<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Unit")!><!UNSAFE_IMPLICIT_INVOKE_CALL!>a<!>()<!>.equals(null)
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Unit")!><!UNSAFE_IMPLICIT_INVOKE_CALL!>a<!>()<!>.propT
|
||||
@@ -376,7 +376,7 @@ fun case_22(a: (() -> Unit)?) {
|
||||
|
||||
// TESTCASE NUMBER: 23
|
||||
fun case_23(a: ((Float) -> Int?)?, b: Float?) {
|
||||
if (a != null !is Boolean && b !== null is Boolean) {
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>a != null !is Boolean<!> && <!EQUALITY_NOT_APPLICABLE!>b !== null is Boolean<!>) {
|
||||
val x = <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!><!UNSAFE_IMPLICIT_INVOKE_CALL!>a<!>(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Float?")!>b<!>)<!>
|
||||
if (x != null) {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Int")!>x<!>
|
||||
@@ -395,7 +395,7 @@ fun case_23(a: ((Float) -> Int?)?, b: Float?) {
|
||||
|
||||
// TESTCASE NUMBER: 24
|
||||
fun case_24(a: ((() -> Unit) -> Unit)?, b: (() -> Unit)?) =
|
||||
if (a !== null is Boolean && b !== null !is Boolean) {
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>a !== null is Boolean<!> && <!EQUALITY_NOT_APPLICABLE!>b !== null !is Boolean<!>) {
|
||||
<!UNSAFE_IMPLICIT_INVOKE_CALL!>a<!>(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function0<kotlin.Unit>?")!>b<!>)
|
||||
<!UNSAFE_IMPLICIT_INVOKE_CALL!>a<!>(b)
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function0<kotlin.Unit>?")!>b<!><!UNSAFE_CALL!>.<!>equals(null)
|
||||
|
||||
@@ -577,7 +577,7 @@ fun case_29(x: Boolean) {
|
||||
if (false || false || false || false || y !== v) {
|
||||
val t = <!DEBUG_INFO_EXPRESSION_TYPE("<anonymous>?")!><!UNSAFE_IMPLICIT_INVOKE_CALL!>y<!>()<!>
|
||||
|
||||
if (z !== t || false) {
|
||||
if (<!EQUALITY_NOT_APPLICABLE_WARNING!>z !== t<!> || false) {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("<anonymous>?")!>t<!><!UNSAFE_CALL!>.<!>a
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("<anonymous>?")!>t<!><!UNSAFE_CALL!>.<!>equals(null)
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("<anonymous>?")!>t<!>.propT
|
||||
|
||||
Reference in New Issue
Block a user