FIR checker: warn unnecessary non-null assertions

This commit is contained in:
Jinseong Jeon
2021-04-01 11:44:47 -07:00
committed by Mikhail Glukhikh
parent 5229d4e4f4
commit 2ecb6733ed
72 changed files with 268 additions and 246 deletions
@@ -11,7 +11,7 @@ fun takeB(b: B) {}
fun test_1() {
val flag = SomeEnum.A1
val b: B = when (flag!!) {
val b: B = when (flag<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {
SomeEnum.A1 -> B()
SomeEnum.A2 -> B()
}
@@ -21,7 +21,7 @@ fun test_1() {
fun test_2() {
val flag = SomeEnum.A1
val b = when (flag!!) {
val b = when (flag<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {
SomeEnum.A1 -> B()
SomeEnum.A2 -> B()
}
+3 -3
View File
@@ -16,7 +16,7 @@ fun get(f: Boolean) = if (f) {A.A1} else {""}
<!CONFLICTING_OVERLOADS!>fun case2()<!> {
val flag: Any = get(false) //string
val l1 = <!NO_ELSE_IN_WHEN!>when<!> (flag!!) { // should be NO_ELSE_IN_WHEN
val l1 = <!NO_ELSE_IN_WHEN!>when<!> (flag<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) { // should be NO_ELSE_IN_WHEN
A.A1 -> B()
A.A2 -> B()
}
@@ -30,7 +30,7 @@ fun get(f: Boolean) = if (f) {A.A1} else {""}
<!CONFLICTING_OVERLOADS!>fun case2()<!> {
val flag: Any = get(true) //A
val l1 = <!NO_ELSE_IN_WHEN!>when<!> (flag!!) {// should be NO_ELSE_IN_WHEN
val l1 = <!NO_ELSE_IN_WHEN!>when<!> (flag<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {// should be NO_ELSE_IN_WHEN
A.A1 -> B()
A.A2 -> B()
}
@@ -44,7 +44,7 @@ fun get(f: Boolean) = if (f) {A.A1} else {""}
fun case3() {
val flag = "" //A
val l1 = <!NO_ELSE_IN_WHEN!>when<!> (flag!!) {// should be NO_ELSE_IN_WHEN
val l1 = <!NO_ELSE_IN_WHEN!>when<!> (flag<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {// should be NO_ELSE_IN_WHEN
A.A1 -> B() //should be INCOMPATIBLE_TYPES
A.A2 -> B() //should be INCOMPATIBLE_TYPES
}
@@ -13,7 +13,7 @@ class C(val b: B)
// TESTCASE NUMBER: 1
fun case1() {
val flag = A.A1
val l0: B = when (flag!!) {
val l0: B = when (flag<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {
A.A1 -> B()
A.A2 -> B()
}
@@ -34,7 +34,7 @@ fun case2() {
fun case3() {
val flag = A.A1
val l1 = when (flag!!) {
val l1 = when (flag<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {
A.A1 -> B()
A.A2 -> B()
}
@@ -68,7 +68,7 @@ fun case5() {
// TESTCASE NUMBER: 6
fun case6() {
val flag: Any = A.A1
val l1 = when (flag!!) {
val l1 = when (flag<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {
A.A1 -> B()
A.A2 -> B()
else -> B()
@@ -91,7 +91,7 @@ fun case7() {
// TESTCASE NUMBER: 8
fun case8() {
val flag: Any = A.A1
val l1: B = when (flag!!) {
val l1: B = when (flag<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {
A.A1 -> B()
A.A2 -> B()
else -> B()
@@ -16,5 +16,5 @@ fun foo() {
var c: MutableSet<String>? = null
c = HashSet()
c!!.d = produce()
}
c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.d = produce()
}
@@ -1,4 +1,4 @@
fun foo() {
val inv = {{}}!!
val inv = {{}}<!NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION!>!!<!>
val bar = {{}}
}
@@ -560,6 +560,11 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
parameter<FirExpression>("rhs")
}
// TODO: val UNEXPECTED_SAFE_CALL by ...
val UNNECESSARY_NOT_NULL_ASSERTION by warning<FirSourceElement, KtExpression>(PositioningStrategy.OPERATOR) {
parameter<ConeKotlinType>("receiverType")
}
val NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION by warning<FirSourceElement, KtExpression>(PositioningStrategy.OPERATOR)
val NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE by warning<FirSourceElement, KtExpression>(PositioningStrategy.OPERATOR)
}
val WHEN_EXPRESSIONS by object : DiagnosticGroup("When expressions") {
@@ -331,6 +331,9 @@ object FirErrors {
val UNSAFE_IMPLICIT_INVOKE_CALL by error1<FirSourceElement, PsiElement, ConeKotlinType>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val UNSAFE_INFIX_CALL by error3<FirSourceElement, KtExpression, FirExpression, String, FirExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val UNSAFE_OPERATOR_CALL by error3<FirSourceElement, KtExpression, FirExpression, String, FirExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val UNNECESSARY_NOT_NULL_ASSERTION by warning1<FirSourceElement, KtExpression, ConeKotlinType>(SourceElementPositioningStrategies.OPERATOR)
val NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION by warning0<FirSourceElement, KtExpression>(SourceElementPositioningStrategies.OPERATOR)
val NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE by warning0<FirSourceElement, KtExpression>(SourceElementPositioningStrategies.OPERATOR)
// When expressions
val NO_ELSE_IN_WHEN by error1<FirSourceElement, KtWhenExpression, List<WhenMissingCase>>(SourceElementPositioningStrategies.WHEN_EXPRESSION)
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirCheckNotNullCall
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.types.*
object FirCheckNotNullCallChecker : FirBasicExpressionChecker() {
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
if (expression !is FirCheckNotNullCall) return
val argument = expression.argumentList.arguments.singleOrNull() ?: return
if (argument is FirAnonymousFunction && argument.isLambda) {
reporter.reportOn(expression.source, FirErrors.NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION, context)
return
}
if (argument is FirCallableReferenceAccess) {
reporter.reportOn(expression.source, FirErrors.NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE, context)
return
}
// TODO: use of Unit is subject to change.
// See BodyResolveComponents.typeForQualifier in ResolveUtils.kt which returns Unit for no value type.
if (argument is FirResolvedQualifier && argument.typeRef.isUnit) {
// Would be reported as NO_COMPANION_OBJECT
return
}
val type = argument.typeRef.coneType.fullyExpandedType(context.session)
if (!type.canBeNull) {
reporter.reportOn(expression.source, FirErrors.UNNECESSARY_NOT_NULL_ASSERTION, type, context)
}
}
}
@@ -149,6 +149,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOTHING_TO_OVERRI
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_AN_ANNOTATION_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_LOOP_LABEL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_SUPERTYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ELSE_IN_WHEN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_GET_METHOD
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_SET_METHOD
@@ -217,6 +219,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_ON_LHS_OF_DOT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_VARIABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNNECESSARY_LATEINIT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNNECESSARY_NOT_NULL_ASSERTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_LABEL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_REFERENCE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_CALL
@@ -745,6 +748,9 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
TO_STRING,
FIR
)
map.put(UNNECESSARY_NOT_NULL_ASSERTION, "Unnecessary non-null assertion (!!) on a non-null receiver of type {0}", RENDER_TYPE)
map.put(NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION, "Non-null assertion (!!) is called on a lambda expression")
map.put(NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE, "Non-null assertion (!!) is called on a callable reference expression")
// When expressions
map.put(NO_ELSE_IN_WHEN, "''when'' expression must be exhaustive, add necessary {0}", WHEN_MISSING_CASES)
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.*
object CommonExpressionCheckers : ExpressionCheckers() {
override val basicExpressionCheckers: Set<FirBasicExpressionChecker> = setOf(
FirAnonymousFunctionChecker,
FirCheckNotNullCallChecker,
FirGetClassCallChecker,
)
@@ -17,7 +17,7 @@ fun test() {
else -> ::baz
})
val x5: (Int) -> Int = bar(::baz!!)
val x5: (Int) -> Int = bar(::baz<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>)
(if (true) ::baz else ::baz)(1)
}
@@ -10,18 +10,18 @@ fun main() {
val x4 = <!UNRESOLVED_REFERENCE!>logger<!>?::info?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>
val x5 = <!UNRESOLVED_REFERENCE!>logger<!>::info?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>
val x6 = <!UNRESOLVED_REFERENCE!>logger<!>!!::<!UNRESOLVED_REFERENCE!>info<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>
val x7 = <!UNRESOLVED_REFERENCE!>logger<!>::info!!::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>
val x8 = <!UNRESOLVED_REFERENCE!>logger<!>?::info!!::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>
val x7 = <!UNRESOLVED_REFERENCE!>logger<!>::info<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>
val x8 = <!UNRESOLVED_REFERENCE!>logger<!>?::info<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>
val x9 = <!UNRESOLVED_REFERENCE!>logger<!>!!::<!UNRESOLVED_REFERENCE!>info<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>
val x10 = <!UNRESOLVED_REFERENCE!>logger<!>::info?::print!!::<!UNRESOLVED_REFERENCE!>print<!>
val x11 = <!UNRESOLVED_REFERENCE!>logger<!>!!::info!!::print!!::<!UNRESOLVED_REFERENCE!>print<!>
val x12 = <!UNRESOLVED_REFERENCE!>logger<!>?::info!!::print!!::<!UNRESOLVED_REFERENCE!>print<!>
val x10 = <!UNRESOLVED_REFERENCE!>logger<!>::info?::print<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>::<!UNRESOLVED_REFERENCE!>print<!>
val x11 = <!UNRESOLVED_REFERENCE!>logger<!>!!::info<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>::print<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>::<!UNRESOLVED_REFERENCE!>print<!>
val x12 = <!UNRESOLVED_REFERENCE!>logger<!>?::info<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>::print<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>::<!UNRESOLVED_REFERENCE!>print<!>
val x13 = 42?::<!UNRESOLVED_REFERENCE!>unresolved<!>?::<!UNRESOLVED_REFERENCE!>print<!>
val x14 = <!UNRESOLVED_REFERENCE!>logger<!><!SYNTAX!>?!!::info?::print?::print<!>
val x15 = <!UNRESOLVED_REFERENCE!>logger<!>::info<!SYNTAX!>?!!::print?::print<!>
val x16 = <!UNRESOLVED_REFERENCE!>logger<!>!!?::<!UNRESOLVED_REFERENCE!>info<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>
val x17 = <!UNRESOLVED_REFERENCE!>logger<!>::info!!?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>
val x17 = <!UNRESOLVED_REFERENCE!>logger<!>::info<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>?::<!UNRESOLVED_REFERENCE!>print<!>?::<!UNRESOLVED_REFERENCE!>print<!>
// It must be OK
val x18 = String?::hashCode ?: ::foo
@@ -2,7 +2,7 @@
fun testCompound() {
operator fun Nothing.get(i: Int) {}
todo()!![12]
todo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>[12]
}
fun testCompound1() {
@@ -10,4 +10,4 @@ fun testCompound1() {
(todo() * "")[1]
}
fun todo(): Nothing = throw Exception()
fun todo(): Nothing = throw Exception()
@@ -9,7 +9,7 @@ fun testPostfixWithCall(n: Nothing) {
}
fun testPostfixSpecial() {
todo()!!
todo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
fun todo(): Nothing = throw Exception()
fun todo(): Nothing = throw Exception()
@@ -4,8 +4,8 @@
fun use(a: Any?) = a
fun test() {
{ }!!
use({ }!!);
{ }<!NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION!>!!<!>
use({ }<!NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION!>!!<!>);
// KT-KT-9070
{ } ?: 1
@@ -6,7 +6,7 @@ interface G {
}
fun foo1(a: Int?, b: G) {
b[a!!, a!!] = a
b[a!!, a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>] = a
checkSubtype<Int>(a)
}
@@ -1,7 +1,7 @@
// !CHECK_TYPE
fun foo1(a: Int?, b: Array<Array<Int>>) {
b[a!!][a!!] = a
b[a!!][a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>] = a
checkSubtype<Int>(a)
}
@@ -2,7 +2,7 @@ fun bar(x: Int) = x + 1
fun f1(x: Int?) {
<!INAPPLICABLE_CANDIDATE!>bar<!>(x)
if (x != null) bar(x!!)
if (x != null) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
if (x == null) bar(x!!)
}
@@ -11,13 +11,13 @@ fun f2(x: Int?) {
}
fun f3(x: Int?) {
if (x != null) bar(x!!) else x!!
if (x != null) bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) else x!!
}
fun f4(x: Int?) {
if (x == null) x!! else bar(x!!)
if (x == null) x!! else bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
}
fun f5(x: Int?) {
if (x == null) else bar(x!!)
if (x == null) else bar(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
}
@@ -26,5 +26,5 @@ fun foo() {
if (z != null) bar(z)
<!INAPPLICABLE_CANDIDATE!>bar<!>(z)
bar(z!!)
if (z != null) bar(z!!)
if (z != null) bar(z<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
}
@@ -11,6 +11,6 @@ fun <T> foo(b: B, f: () -> T): T = f()
fun test(c: C) {
<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>(c) f@ {
c!!
c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
}
@@ -388,49 +388,49 @@ fun poll66(): Flow<String> {
fun poll7(): Flow<String> {
return flow {
val inv = ::bar!!
val inv = ::bar<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv(<!NO_VALUE_FOR_PARAMETER!>)<!>
}
}
fun poll71(): Flow<String> {
return flow {
val inv = ::bar2!!
val inv = ::bar2<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv()
}
}
fun poll72(): Flow<String> {
return flow {
val inv = ::bar3!!
val inv = ::bar3<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv()
}
}
fun poll73(): Flow<String> {
return flow {
val inv = ::bar4!!
val inv = ::bar4<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
}
fun poll74(): Flow<String> {
return flow {
val inv = ::bar5!!
val inv = ::bar5<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
}
fun poll75(): Flow<String> {
return flow {
val inv = ::Foo6!!
val inv = ::Foo6<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
}
fun poll76(): Flow<String> {
return flow {
val inv = ::Foo7!!
val inv = ::Foo7<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
}
@@ -36,21 +36,21 @@ class Flow<out R>(private val block: suspend FlowCollector<R>.() -> Unit)
fun poll71(): Flow<String> {
return flow {
val inv = ::bar2!!
val inv = ::bar2<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv()
}
}
fun poll73(): Flow<String> {
return flow {
val inv = ::bar4!!
val inv = ::bar4<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
}
fun poll75(): Flow<String> {
return flow {
val inv = ::Foo6!!
val inv = ::Foo6<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
}
@@ -37,49 +37,49 @@ class Flow<out R>(private val block: suspend FlowCollector<R>.() -> Unit)
fun poll7(): Flow<String> {
return flow {
val inv = ::bar!!
val inv = ::bar<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv(<!NO_VALUE_FOR_PARAMETER!>)<!>
}
}
fun poll71(): Flow<String> {
return flow {
val inv = ::bar2!!
val inv = ::bar2<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv()
}
}
fun poll72(): Flow<String> {
return flow {
val inv = ::bar3!!
val inv = ::bar3<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv()
}
}
fun poll73(): Flow<String> {
return flow {
val inv = ::bar4!!
val inv = ::bar4<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
}
fun poll74(): Flow<String> {
return flow {
val inv = ::bar5!!
val inv = ::bar5<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
}
fun poll75(): Flow<String> {
return flow {
val inv = ::Foo6!!
val inv = ::Foo6<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
}
fun poll76(): Flow<String> {
return flow {
val inv = ::Foo7!!
val inv = ::Foo7<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
}
@@ -119,28 +119,28 @@ fun poll5(): Flow<String> {
fun poll7(): Flow<String> {
return flow {
val inv = {}!!
val inv = {}<!NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION!>!!<!>
inv()
}
}
fun poll71(): Flow<String> {
return flow {
val inv = {1f}!!
val inv = {1f}<!NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION!>!!<!>
inv()
}
}
fun poll72(): Flow<String> {
return flow {
val inv = {{}}!!
val inv = {{}}<!NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION!>!!<!>
inv()
}
}
fun poll73(): Flow<String> {
return flow {
val inv = ({})!!
val inv = ({})<!NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION!>!!<!>
inv
}
}
@@ -189,7 +189,7 @@ fun poll85(): Flow<String> {
fun poll86(): Flow<String> {
return flow {
val inv = {({"1"})}!! in setOf({({"1f"})}!!)
val inv = {({"1"})}<!NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION!>!!<!> in setOf({({"1f"})}<!NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION!>!!<!>)
<!UNRESOLVED_REFERENCE!>inv<!>()
}
}
@@ -11,23 +11,23 @@ interface B {
fun test(u: A?, x: A?, y: A?, z: A?, w: A, v: A?) {
u?.b?.foo()!! // was UNNECESSARY_SAFE_CALL everywhere, because result type (of 'foo()') wasn't made nullable
u!!.b?.foo()!!
x?.b!!.foo()!!
u!!.b?.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
x?.b!!.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
// x?.b is not null
x!!.b!!.foo()!!
x!!.b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
y?.nb?.foo()!!
y!!.nb?.foo()!!
z?.nb!!.foo()!!
z?.nb!!.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
// z?.nb is not null
z!!.nb!!.foo()!!
z!!.nb!!.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
w.b?.foo()!!
w.b!!.foo()!!
w.b?.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
w.b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
w.nb?.foo()!!
w.nb!!.foo()!!
w.nb!!.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
v!!.b.foo()!!
v!!.b.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
fun B?.bar(): Int = 1
@@ -36,6 +36,6 @@ fun B?.baz(): Int? = 1
fun doInt(i: Int) = i
fun test(a: A?) {
doInt(a?.b.bar()!!)
doInt(a?.b.bar()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
doInt(a?.b.baz()!!)
}
}
@@ -5,7 +5,7 @@ import java.lang.Exception
fun <K> id(arg: K): K = arg
fun test() {
id(<!UNRESOLVED_REFERENCE!>unresolved<!>)!!
id(<!UNRESOLVED_REFERENCE!>unresolved<!>)<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
<!UNRESOLVED_REFERENCE!>unresolved<!>!!!!
try {
id(<!UNRESOLVED_REFERENCE!>unresolved<!>)
@@ -234,37 +234,37 @@ fun poll66() {
}
fun poll7() {
val inv = ::bar!!
val inv = ::bar<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv(<!NO_VALUE_FOR_PARAMETER!>)<!>
}
fun poll71() {
val inv = ::bar2!!
val inv = ::bar2<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv()
}
fun poll72() {
val inv = ::bar3!!
val inv = ::bar3<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv(<!NO_VALUE_FOR_PARAMETER!>)<!>
}
fun poll73() {
val inv = ::bar4!!
val inv = ::bar4<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
fun poll74() {
val inv = ::bar5!!
val inv = ::bar5<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
fun poll75() {
val inv = ::Foo6!!
val inv = ::Foo6<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
fun poll76() {
val inv = ::Foo7!!
val inv = ::Foo7<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
inv
}
@@ -5,35 +5,35 @@ fun main() {
val a : Int? = null
val b : Int? = null
checkSubtype<Int>(a!!)
a!! + 2
a!!.plus(2)
a!!.plus(b!!)
2.plus(b!!)
2 + b!!
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!> + 2
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.plus(2)
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.plus(b!!)
2.plus(b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
2 + b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
val c = 1
c!!
c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
val d : Any? = null
if (d != null) {
d!!
d<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
// smart cast isn't needed, but is reported due to KT-4294
if (d is String) {
d!!
d<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
if (d is String?) {
if (d != null) {
d!!
d<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
if (d is String) {
d!!
d<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
}
val f : String = a!!
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><String>(a!!)
val f : String = a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><String>(a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
}
@@ -10,7 +10,7 @@ fun main() {
x<!UNSAFE_CALL!>.<!>foo(y)
x!!.<!INAPPLICABLE_CANDIDATE!>foo<!>(y)
x.foo(y!!)
x!!.foo(y!!)
x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(y<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
val a: Foo? = null
val b: Foo? = null
@@ -19,12 +19,12 @@ fun main() {
a<!UNSAFE_CALL!>.<!>foo(b<!UNSAFE_CALL!>.<!>foo(c))
a!!.foo(b<!UNSAFE_CALL!>.<!>foo(c))
a.foo(b!!.<!INAPPLICABLE_CANDIDATE!>foo<!>(c))
a!!.foo(b!!.<!INAPPLICABLE_CANDIDATE!>foo<!>(c))
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.<!INAPPLICABLE_CANDIDATE!>foo<!>(c))
a.foo(b.foo(c!!))
a!!.foo(b.foo(c!!))
a.foo(b!!.foo(c!!))
a!!.foo(b!!.foo(c!!))
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(b.foo(c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>))
a.foo(b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>))
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo(c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>))
val z: Foo? = null
z!!.foo(z!!)
z!!.foo(z<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
}
@@ -11,7 +11,7 @@ fun main() {
if (x != null) {
foo(x)
foo(x!!)
foo(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
foo(x)
}
@@ -19,7 +19,7 @@ fun main() {
if (x != null) {
foo(x)
foo(x!!)
foo(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
foo(x)
} else {
<!INAPPLICABLE_CANDIDATE!>foo<!>(x)
@@ -28,12 +28,12 @@ fun main() {
}
foo(x)
foo(x!!)
foo(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
foo(x)
val y: Int? = null
y!!
y!!
y<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
foo(y)
foo(y!!)
foo(y<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
}
@@ -11,7 +11,7 @@ fun f1(a: String?) {
}
fun f2(a: String) {
a!!
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
checkSubtype<String>(a)
}
@@ -4,5 +4,5 @@ package kt2212
fun main() {
val x: Int? = 1
if (x == null) return
System.out.println(x.plus(x!!))
System.out.println(x.plus(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>))
}
@@ -11,7 +11,7 @@ fun foo() {
bar(if (x != null) x else return, x)
x + 2
bar(x, x!!)
bar(x, x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
val y: Int? = 0
val z: Int? = 0
@@ -11,14 +11,14 @@ class Pair<A, B>(val a: A, val b: B)
fun main() {
val d : Long = 1
val period : Int? = null
if (period != null) Pair(d, checkSubtype<Int>(period!!)) else Pair(d, 1)
if (period != null) Pair(d, checkSubtype<Int>(period<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)) else Pair(d, 1)
if (period != null) Pair(d, checkSubtype<Int>(period)) else Pair(d, 1)
}
fun foo() {
val x : Int? = 3
if (x != null) {
val u = checkSubtype<Int>(x!!)
val u = checkSubtype<Int>(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
val y = checkSubtype<Int>(x)
val z : Int = y
}
@@ -3,7 +3,7 @@ fun main() {
if (b != null) {
if (!b) {} // OK
if (b) {} // Error: Condition must be of type kotlin.Boolean, but is of type kotlin.Boolean?
if (b!!) {} // WARN: Unnecessary non-null assertion (!!) on a non-null receiver of type kotlin.Boolean?
if (b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {} // WARN: Unnecessary non-null assertion (!!) on a non-null receiver of type kotlin.Boolean?
foo(b) // OK
}
}
@@ -17,8 +17,8 @@ fun test() {
takeNotNull(dependOn(dependOn(x!!)))
if (x != null) {
takeNotNull(dependOn(x)!!)
takeNotNull(dependOn(dependOn(x))!!)
takeNotNull(dependOn(dependOn(x)!!))
takeNotNull(dependOn(x)<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
takeNotNull(dependOn(dependOn(x))<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)
takeNotNull(dependOn(dependOn(x)<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>))
}
}
}
@@ -6,7 +6,7 @@ fun <D> makeDefinitelyNotNull(arg: D?): D = TODO()
fun <N : Number?> test(arg: N) {
makeDefinitelyNotNull(arg) ?: 1
makeDefinitelyNotNull(arg)!!
makeDefinitelyNotNull(arg)<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
makeDefinitelyNotNull(arg)?.toInt()
@@ -14,4 +14,4 @@ fun <N : Number?> test(arg: N) {
null -> false
else -> true
}
}
}
@@ -1,14 +1,14 @@
// !WITH_NEW_INFERENCE
fun <T> test(t: T): T {
if (t != null) {
return t!!
return t<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
return t!!
}
fun <T> T.testThis(): String {
if (this != null) {
return this!!.toString()
return this<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.toString()
}
return this!!.toString()
}
@@ -1,40 +0,0 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -SENSELESS_COMPARISON -UNUSED_PARAMETER
// FILE: J.java
import org.jetbrains.annotations.*;
public class J {
@NotNull
public static J staticNN;
@Nullable
public static J staticN;
public static J staticJ;
}
// FILE: k.kt
fun test() {
// @NotNull platform type
val platformNN = J.staticNN
// @Nullable platform type
val platformN = J.staticN
// platform type with no annotation
val platformJ = J.staticJ
if (platformNN != null) {
platformNN!!
}
if (platformN != null) {
platformN!!
}
if (platformJ != null) {
platformJ!!
}
platformNN!!
platformN!!
platformJ!!
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_EXPRESSION -SENSELESS_COMPARISON -UNUSED_PARAMETER
// FILE: J.java
@@ -1,27 +0,0 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: J.java
import org.jetbrains.annotations.*;
public class J {
@NotNull
public static J staticNN;
}
// FILE: k.kt
fun test() {
// @NotNull platform type
val platformNN = J.staticNN
foo(platformNN!!)
val bar = Bar()
bar(platformNN!!)
}
fun foo(a: Any) {}
class Bar {
operator fun invoke(a: Any) {}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: J.java
@@ -15,7 +15,7 @@ fun list(j: J): Any {
a?.get(0)
if (a == null) {}
a!!
a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
a.get(0)
return a
@@ -5,4 +5,4 @@ fun lambda(x : Int?) = x?.<!UNRESOLVED_REFERENCE!>let<!> <!UNRESOLVED_REFERENCE!
y ->
if (y <!UNRESOLVED_REFERENCE!>><!> 0) return@l x
y
}!!
}<!NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION!>!!<!>
@@ -28,7 +28,7 @@ fun testElvis(x: Any?) {
}
fun testExclExcl() {
val y = :: unresolved!!
val y = :: unresolved<!NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE!>!!<!>
}
fun testTry() {
@@ -1,24 +0,0 @@
//KT-4204 ConstraintSystem erased after resolution completion
package c
public abstract class TestBug1() {
public fun m3(position: Int) {
position(m1().second!!)
}
public fun m4(position: (Int)->Int) {
position(m1().second)
}
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>abstract<!> fun m1(): Pair<Int, Int>
private fun position(p: Int) {}
}
//from library
public class Pair<out A, out B> (
public val first: A,
public val second: B
)
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
//KT-4204 ConstraintSystem erased after resolution completion
package c
@@ -25,5 +25,5 @@ fun testDataFlowInfoAfterExclExcl(a: Int?) {
}
fun testUnnecessaryExclExcl(a: Int) {
doInt(a!!) //should be warning
doInt(a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) //should be warning
}
@@ -27,13 +27,13 @@ fun bar(o: Any) {
}
else {
order!!.doSomething()
order<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.doSomething()
}
if (order?.notExpired() ?: true) {
}
else {
order!!.doSomething()
order<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.doSomething()
}
}
@@ -25,7 +25,7 @@ public data class Tag(public var tagName: String) {
attributes.remove("id")
}
else {
attributes["id"] = value!!
attributes["id"] = value<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
attributes["id"] = value
}
}
@@ -5,7 +5,7 @@ fun main() {
val value: String? = ""
if (value != null) {
foo(Pair("val", value))
foo(Pair("val", value!!))
foo(Pair("val", value<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>))
foo(Pair<String, String>("val", value))
}
}
@@ -3,10 +3,10 @@ operator fun <K, V> MutableMap<K, V>.set(k: K, v: V) {}
fun foo(a: MutableMap<String, String>, x: String?) {
a[x!!] = x
a[x] = x!!
a[x] = x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
fun foo1(a: MutableMap<String, String>, x: String?) {
<!INAPPLICABLE_CANDIDATE!>a[x]<!> = x!!
a[x!!] = x
a[x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>] = x
}
@@ -1,6 +0,0 @@
fun calc(x: List<String>?): Int {
// After KT-5840 fix !! assertion should become unnecessary here
x?.get(x!!.size - 1)
// x?. or x!! above should not provide smart cast here
return x<!UNSAFE_CALL!>.<!>size
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun calc(x: List<String>?): Int {
// After KT-5840 fix !! assertion should become unnecessary here
x?.get(x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.size - 1)
@@ -10,5 +10,5 @@ fun foo(y: MyClass?): Int {
fun bar(y: MyClass?) {
y?.x!!.length
// !! is NOT necessary here, because y?.x != null
y!!.x
}
y<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.x
}
@@ -10,7 +10,7 @@ fun test1(s: String?) {
fun test2(s: String?) {
assert(s!!.isEmpty())
s!!.length
s<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
}
fun test3(s: String?) {
@@ -27,7 +27,7 @@ fun test4() {
fun test5() {
val s: String? = null;
assert(s!!.isEmpty())
s!!.length
s<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length
}
fun test6() {
@@ -1,5 +1,5 @@
fun foo1(p: Pair<Int?, Int>): Int {
if (p.first != null) return p.first!!
if (p.first != null) return p.first<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
return p.second
}
@@ -20,26 +20,26 @@ import libModule.*
// TESTCASE NUMBER: 1
fun case1() {
val res = JavaClass.FALSE!!
val res = JavaClass.FALSE<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
// TESTCASE NUMBER: 2
fun case2() {
val x = JavaClass.obj!!
val x = JavaClass.obj<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
// TESTCASE NUMBER: 3
fun case3() {
val a = false
val x = a!!
val x = a<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
// TESTCASE NUMBER: 4
fun case4() {
val x = "weds"!!
val x = "weds"<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
// TESTCASE NUMBER: 5
fun case5(nothing: Nothing) {
val y = nothing!!
val y = nothing<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
@@ -55,7 +55,7 @@ fun case_1(value_1: Int?) {
// TESTCASE NUMBER: 2
fun case_2(value_1: Int?) {
if (!contracts.case_2(value_1)!!) {
if (!contracts.case_2(value_1)<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {
value_1<!UNSAFE_CALL!>.<!>inv()
}
}
@@ -159,6 +159,6 @@ class case_10_class {
*/
fun case_11(value_1: Any?, value_2: Any?, value_3: Any?) {
funWithReturnsAndInvertCondition(value_1 !is String || value_2 !is Number || value_3 !is Any?)
println(value_1!!.length)
println(value_1<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.length)
println(value_2?.toByte())
}
@@ -339,7 +339,7 @@ fun case_25(x: Boolean?) {
*/
fun case_26(x: Boolean?) {
while (true) {
for (i in listOf(break, x!!, x!!)) {
for (i in listOf(break, x!!, x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)) {
}
}
@@ -339,7 +339,7 @@ fun case_25(x: Boolean?) {
*/
fun case_26(x: Boolean?) {
while (true) {
for (i in listOf(break, x as Boolean, x!!)) {
for (i in listOf(break, x as Boolean, x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>)) {
}
}
@@ -98,7 +98,7 @@ fun case_6(x: Class?) {
* ISSUES: KT-30376
*/
fun case_7(x: Class) {
if (x!!.prop_8?.prop_8?.prop_8?.prop_8 != null) {
if (x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.prop_8?.prop_8?.prop_8?.prop_8 != null) {
<!DEBUG_INFO_EXPRESSION_TYPE("Class")!>x<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Class")!>x<!>.prop_8
<!DEBUG_INFO_EXPRESSION_TYPE("Class")!>x<!>.prop_8<!UNSAFE_CALL!>.<!>prop_8
@@ -113,7 +113,7 @@ fun case_7(x: Class) {
* ISSUES: KT-30376
*/
fun case_8(x: Class) {
if (x!!.prop_8?.prop_8?.prop_8?.prop_8 != null) {
if (x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.prop_8?.prop_8?.prop_8?.prop_8 != null) {
<!DEBUG_INFO_EXPRESSION_TYPE("Class")!>x<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Class")!>x<!>.prop_8
<!DEBUG_INFO_EXPRESSION_TYPE("Class")!>x<!>.prop_8<!UNSAFE_CALL!>.<!>prop_8
@@ -137,7 +137,7 @@ fun case_10(x: Any?, z: Any, b: Boolean?) {
// TESTCASE NUMBER: 11
fun case_11(x: Any?, z: Any, b: Boolean?) {
while (true) {
var y = x ?: if (b == true) continue!! else if (!(b != false)) return else break ?: break::class
var y = x ?: if (b == true) continue<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!> else if (!(b != false)) return else break ?: break::class
z !== y && if (b == true) return else if (b === false) null!!else throw Exception()
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & kotlin.Any")!>x<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any")!>y<!>
@@ -148,7 +148,7 @@ fun case_11(x: Any?, z: Any, b: Boolean?) {
// TESTCASE NUMBER: 12
fun case_12(x: Any?, z: Any, b: Boolean?) {
while (true) {
var y = select(x) ?: if (b == true) continue!! else if (!(b != false)) return else break ?: break::class
var y = select(x) ?: if (b == true) continue<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!> else if (!(b != false)) return else break ?: break::class
select(z) !== y && if (b == true) return else if (b === false) null!!else throw Exception()
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any")!>y<!>
@@ -31,7 +31,7 @@ fun case_3(x: ClassWithThreeTypeParameters<*, *, *>) {
<!DEBUG_INFO_EXPRESSION_TYPE("ClassWithThreeTypeParameters<*, *, *> & InterfaceWithTwoTypeParameters<*, *> & ClassWithThreeTypeParameters<*, *, *>")!>x<!>.x
x.y
x.z
<!DEBUG_INFO_EXPRESSION_TYPE("InterfaceWithTwoTypeParameters<*, *> & ClassWithThreeTypeParameters<*, *, *>")!>x!!<!>.ip2test()
<!DEBUG_INFO_EXPRESSION_TYPE("InterfaceWithTwoTypeParameters<*, *> & ClassWithThreeTypeParameters<*, *, *>")!>x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!><!>.ip2test()
<!DEBUG_INFO_EXPRESSION_TYPE("ClassWithThreeTypeParameters<*, *, *> & InterfaceWithTwoTypeParameters<*, *> & ClassWithThreeTypeParameters<*, *, *>")!>x<!>
<!DEBUG_INFO_EXPRESSION_TYPE("ClassWithThreeTypeParameters<*, *, *> & InterfaceWithTwoTypeParameters<*, *> & ClassWithThreeTypeParameters<*, *, *>")!>x<!>.x
}
@@ -45,7 +45,7 @@ fun case_4(x: ClassWithSixTypeParameters<*, *, *, *, *, *>?) {
x.y
x.z
x.u
<!DEBUG_INFO_EXPRESSION_TYPE("InterfaceWithTwoTypeParameters<*, *> & ClassWithSixTypeParameters<*, *, *, *, *, *>")!>x!!<!>.ip2test()
<!DEBUG_INFO_EXPRESSION_TYPE("InterfaceWithTwoTypeParameters<*, *> & ClassWithSixTypeParameters<*, *, *, *, *, *>")!>x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!><!>.ip2test()
<!DEBUG_INFO_EXPRESSION_TYPE("ClassWithSixTypeParameters<*, *, *, *, *, *>? & InterfaceWithTwoTypeParameters<*, *> & ClassWithSixTypeParameters<*, *, *, *, *, *>")!>x<!>
<!DEBUG_INFO_EXPRESSION_TYPE("ClassWithSixTypeParameters<*, *, *, *, *, *>? & InterfaceWithTwoTypeParameters<*, *> & ClassWithSixTypeParameters<*, *, *, *, *, *>")!>x<!>.x
}
@@ -60,7 +60,7 @@ fun case_6(x: Any?) {
// TESTCASE NUMBER: 7
fun case_7(x: Boolean?) {
if (x != null && x!!) {
if (x != null && x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Boolean? & kotlin.Boolean")!>x<!>.not()
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Boolean")!>select(x)<!>.not()
}
@@ -263,7 +263,7 @@ fun case_22(z: Any?) {
fun case_23(z: Any?) {
val y = z.run {
when (this) {
true -> this!!
true -> this<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
0.0 -> this as Any
else -> this!!
}
@@ -276,7 +276,7 @@ fun case_23(z: Any?) {
fun case_24(z: Any?) {
val y = z.let {
when (it) {
true -> it!!
true -> it<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
0.0 -> it as Any
else -> it!!
}
@@ -292,7 +292,7 @@ fun case_25(z: Any?) {
true -> this
if (true) this as Int else this as Float -> this
return@run this as Float -> this
else -> this!!
else -> this<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
}
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any")!>y<!>
@@ -306,7 +306,7 @@ fun case_26(z: Any?) {
true -> it
if (true) it as Int else it as Float -> it
return@let it as Int -> it
else -> it!!
else -> it<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
}
}
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any")!>y<!>
@@ -8,7 +8,7 @@
*/
fun case_1(x: Any) {
if (x is String) {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>x!!<!>.length
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!><!>.length
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.String")!>x<!>
}
}
@@ -30,7 +30,7 @@ fun case_2(x: Any?) {
*/
fun case_3(x: Any) {
if (x is Map.Entry<*, *>) {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.Map.Entry<*, *>")!>x!!<!>.key
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.Map.Entry<*, *>")!>x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!><!>.key
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.collections.Map.Entry<*, *>")!>x<!>
}
}
@@ -35,7 +35,7 @@ fun case_4(x: Any?) {
// TESTCASE NUMBER: 5
fun case_5(x: Class) {
if (x!!.prop_8 != null) {
if (x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.prop_8 != null) {
<!DEBUG_INFO_EXPRESSION_TYPE("Class")!>x<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Class")!>x<!>.prop_8<!UNSAFE_CALL!>.<!>prop_8
}
@@ -1535,6 +1535,25 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.UNNECESSARY_NOT_NULL_ASSERTION) { firDiagnostic ->
UnnecessaryNotNullAssertionImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION) { firDiagnostic ->
NotNullAssertionOnLambdaExpressionImpl(
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE) { firDiagnostic ->
NotNullAssertionOnCallableReferenceImpl(
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.NO_ELSE_IN_WHEN) { firDiagnostic ->
NoElseInWhenImpl(
firDiagnostic.a.map { whenMissingCase ->
@@ -1087,6 +1087,19 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val rhs: KtExpression
}
abstract class UnnecessaryNotNullAssertion : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = UnnecessaryNotNullAssertion::class
abstract val receiverType: KtType
}
abstract class NotNullAssertionOnLambdaExpression : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = NotNullAssertionOnLambdaExpression::class
}
abstract class NotNullAssertionOnCallableReference : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = NotNullAssertionOnCallableReference::class
}
abstract class NoElseInWhen : KtFirDiagnostic<KtWhenExpression>() {
override val diagnosticClass get() = NoElseInWhen::class
abstract val missingWhenCases: List<WhenMissingCase>
@@ -1754,6 +1754,28 @@ internal class UnsafeOperatorCallImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class UnnecessaryNotNullAssertionImpl(
override val receiverType: KtType,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.UnnecessaryNotNullAssertion(), KtAbstractFirDiagnostic<KtExpression> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class NotNullAssertionOnLambdaExpressionImpl(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.NotNullAssertionOnLambdaExpression(), KtAbstractFirDiagnostic<KtExpression> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class NotNullAssertionOnCallableReferenceImpl(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.NotNullAssertionOnCallableReference(), KtAbstractFirDiagnostic<KtExpression> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class NoElseInWhenImpl(
override val missingWhenCases: List<WhenMissingCase>,
firDiagnostic: FirPsiDiagnostic<*>,