FIR IDE: Enable ReplaceInfixOrOperatorCallFix for

UNSAFE_IMPLICIT_INVOKE_CALL.
This commit is contained in:
Mark Punzalan
2021-05-24 22:13:42 +00:00
committed by teamcityserver
parent 6de1000818
commit ef923d4cfe
9 changed files with 30 additions and 18 deletions
@@ -111,6 +111,7 @@ class MainKtQuickFixRegistrar : KtQuickFixRegistrar() {
registerApplicator(ReplaceCallFixFactories.unsafeCallFactory)
registerApplicator(ReplaceCallFixFactories.unsafeInfixCallFactory)
registerApplicator(ReplaceCallFixFactories.unsafeOperatorCallFactory)
registerApplicator(ReplaceCallFixFactories.unsafeImplicitInvokeCallFactory)
registerApplicator(AddExclExclCallFixFactories.unsafeCallFactory)
registerApplicator(AddExclExclCallFixFactories.unsafeInfixCallFactory)
registerApplicator(AddExclExclCallFixFactories.unsafeOperatorCallFactory)
@@ -66,6 +66,26 @@ object ReplaceCallFixFactories {
listOf(ReplaceInfixOrOperatorCallFix(target, shouldHaveNotNullType(target), diagnostic.operator))
}
val unsafeImplicitInvokeCallFactory =
diagnosticFixFactory<KtFirDiagnostic.UnsafeImplicitInvokeCall> { diagnostic ->
val target = diagnostic.psi as? KtNameReferenceExpression ?: return@diagnosticFixFactory emptyList()
val callExpression = target.parent as? KtCallExpression ?: return@diagnosticFixFactory emptyList()
val qualifiedExpression = callExpression.parent as? KtQualifiedExpression
if (qualifiedExpression == null) {
// TODO: This matches FE 1.0 behavior (see ReplaceInfixOrOperatorCallFixFactory.kt) but we should be able to do the fix
// when the call is a qualified expression. We just need to make sure to pass any extension receiver as an argument, e.g.:
//
// fun test(exec: (String.() -> Unit)?) = "".exec() // Can be fixed to exec?.invoke("")
//
// This should be differentiated from this case without an extension receiver:
//
// class A(val exec: (() -> Unit)?)
// fun test(a: A) = a.exec() // Can be fixed to a.exec?.invoke()
listOf(ReplaceInfixOrOperatorCallFix(callExpression, shouldHaveNotNullType(callExpression)))
} else emptyList()
}
private fun KtAnalysisSession.shouldHaveNotNullType(expression: KtExpression): Boolean {
// This function is used to determine if we may need to add an elvis operator after the safe call. For example, to replace
// `s.length` in `val x: Int = s.length` with a safe call, it should be replaced with `s.length ?: <caret>`.
@@ -0,0 +1,3 @@
// "Replace with safe (?.) call" "true"
fun foo(exec: (() -> Unit)?) = exec?.invoke() ?: <caret>
@@ -1,5 +1,3 @@
// "Replace with safe (?.) call" "true"
fun foo(exec: (() -> Unit)?) = exec<caret>()
/* IGNORE_FIR */
fun foo(exec: (() -> Unit)?) = exec<caret>()
@@ -1,5 +1,3 @@
// "Replace with safe (?.) call" "true"
fun foo(exec: (() -> Unit)?) = exec?.invoke()
/* IGNORE_FIR */
fun foo(exec: (() -> Unit)?) = exec?.invoke()
@@ -5,6 +5,4 @@ fun bar() {
val fff: (() -> Int)? = { 1 }
var i: Int = 1
i = fff<caret>()
}
/* IGNORE_FIR */
}
@@ -5,6 +5,4 @@ fun bar() {
val fff: (() -> Int)? = { 1 }
var i: Int = 1
i = fff?.invoke() ?: <caret>
}
/* IGNORE_FIR */
}
@@ -6,6 +6,4 @@ fun foo() {}
fun bar() {
val fff: (() -> Unit)? = ::foo
<caret>fff()
}
/* IGNORE_FIR */
}
@@ -6,6 +6,4 @@ fun foo() {}
fun bar() {
val fff: (() -> Unit)? = ::foo
fff?.invoke()
}
/* IGNORE_FIR */
}