[kotlin] Port AddEqEqTrueFix to K2

Also provided AddExclExclCallFix for the CONDITION_TYPE_MISMATCH error.

^KTIJ-29577

GitOrigin-RevId: 7f21319738936e4f75f15a2862818d6405378767
This commit is contained in:
Andrey Cherkasov
2024-06-21 02:42:20 +00:00
committed by intellij-monorepo-bot
parent a879020198
commit a51085f923
17 changed files with 193 additions and 18 deletions
@@ -250,6 +250,7 @@ class KotlinK2QuickFixRegistrar : KotlinQuickFixRegistrar() {
registerFactory(TypeMismatchFactories.assignmentTypeMismatch)
registerFactory(TypeMismatchFactories.initializerTypeMismatch)
registerFactory(TypeMismatchFactories.smartcastImpossibleFactory)
registerFactory(TypeMismatchFactories.conditionTypeMismatchFactory)
registerFactory(WrapWithSafeLetCallFixFactories.forUnsafeCall)
registerFactory(WrapWithSafeLetCallFixFactories.forUnsafeImplicitInvokeCall)
@@ -1,13 +1,14 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.k2.codeinsight.fixes
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KaFirDiagnostic
import org.jetbrains.kotlin.analysis.api.types.KaType
import org.jetbrains.kotlin.analysis.api.types.KaTypeNullability
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KotlinQuickFixFactory
import org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix
import org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -39,12 +40,16 @@ object TypeMismatchFactories {
getFixesForTypeMismatch(psi, expectedType = diagnostic.desiredType, actualType = actualType)
}
val conditionTypeMismatchFactory = KotlinQuickFixFactory.IntentionBased { diagnostic: KaFirDiagnostic.ConditionTypeMismatch ->
getFixesForTypeMismatch(diagnostic.psi, expectedType = builtinTypes.boolean, actualType = diagnostic.actualType)
}
context(KaSession)
private fun getFixesForTypeMismatch(
psi: PsiElement,
expectedType: KaType,
actualType: KaType
): List<AddExclExclCallFix> {
): List<IntentionAction> {
// TODO: Add more fixes than just AddExclExclCallFix when available.
if (!expectedType.canBeNull && actualType.canBeNull) {
// We don't want to offer AddExclExclCallFix if we know the expression is definitely null, e.g.:
@@ -57,7 +62,12 @@ object TypeMismatchFactories {
}
val nullableExpectedType = expectedType.withNullability(KaTypeNullability.NULLABLE)
if (actualType.isSubtypeOf(nullableExpectedType)) {
return listOfNotNull(psi.asAddExclExclCallFix())
return buildList {
psi.asAddExclExclCallFix()?.let(::add)
if (expectedType.isBooleanType && psi is KtExpression) {
add(AddEqEqTrueFix(psi).asIntention())
}
}
}
}
return emptyList()
@@ -234,6 +234,11 @@ public abstract class HighLevelQuickFixTestGenerated extends AbstractHighLevelQu
runTest("../../../idea/tests/testData/quickfix/addExclExclCall/typeMismatch/assignmentRValue.kt");
}
@TestMetadata("condition.kt")
public void testCondition() throws Exception {
runTest("../../../idea/tests/testData/quickfix/addExclExclCall/typeMismatch/condition.kt");
}
@TestMetadata("initializer.kt")
public void testInitializer() throws Exception {
runTest("../../../idea/tests/testData/quickfix/addExclExclCall/typeMismatch/initializer.kt");
@@ -5407,7 +5412,54 @@ public abstract class HighLevelQuickFixTestGenerated extends AbstractHighLevelQu
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../../idea/tests/testData/quickfix/addEqEqTrue")
public static class AddEqEqTrue extends AbstractHighLevelQuickFixTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K2;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("argument.kt")
public void testArgument() throws Exception {
runTest("../../../idea/tests/testData/quickfix/addEqEqTrue/argument.kt");
}
@TestMetadata("assignment.kt")
public void testAssignment() throws Exception {
runTest("../../../idea/tests/testData/quickfix/addEqEqTrue/assignment.kt");
}
@TestMetadata("condition.kt")
public void testCondition() throws Exception {
runTest("../../../idea/tests/testData/quickfix/addEqEqTrue/condition.kt");
}
@TestMetadata("initializer.kt")
public void testInitializer() throws Exception {
runTest("../../../idea/tests/testData/quickfix/addEqEqTrue/initializer.kt");
}
@TestMetadata("notBoolean.kt")
public void testNotBoolean() throws Exception {
runTest("../../../idea/tests/testData/quickfix/addEqEqTrue/notBoolean.kt");
}
@TestMetadata("notBoolean2.kt")
public void testNotBoolean2() throws Exception {
runTest("../../../idea/tests/testData/quickfix/addEqEqTrue/notBoolean2.kt");
}
@TestMetadata("return.kt")
public void testReturn() throws Exception {
runTest("../../../idea/tests/testData/quickfix/addEqEqTrue/return.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../../idea/tests/testData/quickfix/addFunModifier")
@@ -6061,8 +6113,6 @@ public abstract class HighLevelQuickFixTestGenerated extends AbstractHighLevelQu
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../../idea/tests/testData/quickfix/changeObjectToClass")
public static class ChangeObjectToClass extends AbstractHighLevelQuickFixTest {
@@ -795,6 +795,26 @@ public abstract class K1QuickFixTestGenerated extends AbstractK1QuickFixTest {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("argument.kt")
public void testArgument() throws Exception {
runTest("testData/quickfix/addEqEqTrue/argument.kt");
}
@TestMetadata("assignment.kt")
public void testAssignment() throws Exception {
runTest("testData/quickfix/addEqEqTrue/assignment.kt");
}
@TestMetadata("condition.kt")
public void testCondition() throws Exception {
runTest("testData/quickfix/addEqEqTrue/condition.kt");
}
@TestMetadata("initializer.kt")
public void testInitializer() throws Exception {
runTest("testData/quickfix/addEqEqTrue/initializer.kt");
}
@TestMetadata("notBoolean.kt")
public void testNotBoolean() throws Exception {
runTest("testData/quickfix/addEqEqTrue/notBoolean.kt");
@@ -805,14 +825,9 @@ public abstract class K1QuickFixTestGenerated extends AbstractK1QuickFixTest {
runTest("testData/quickfix/addEqEqTrue/notBoolean2.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("testData/quickfix/addEqEqTrue/simple.kt");
}
@TestMetadata("simple2.kt")
public void testSimple2() throws Exception {
runTest("testData/quickfix/addEqEqTrue/simple2.kt");
@TestMetadata("return.kt")
public void testReturn() throws Exception {
runTest("testData/quickfix/addEqEqTrue/return.kt");
}
}
@@ -842,6 +857,11 @@ public abstract class K1QuickFixTestGenerated extends AbstractK1QuickFixTest {
runTest("testData/quickfix/addExclExclCall/typeMismatch/assignmentRValue.kt");
}
@TestMetadata("condition.kt")
public void testCondition() throws Exception {
runTest("testData/quickfix/addExclExclCall/typeMismatch/condition.kt");
}
@TestMetadata("initializer.kt")
public void testInitializer() throws Exception {
runTest("testData/quickfix/addExclExclCall/typeMismatch/initializer.kt");
@@ -9,4 +9,5 @@ fun test(foo: Foo?) {
baz(foo?.bar()<caret>)
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
@@ -9,4 +9,5 @@ fun test(foo: Foo?) {
baz(foo?.bar() == true)
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
@@ -0,0 +1,12 @@
// "Add '== true'" "true"
class Foo {
fun bar() = true
}
fun test(foo: Foo?) {
val flag: Boolean
flag = foo?.bar()<caret>
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
@@ -0,0 +1,12 @@
// "Add '== true'" "true"
class Foo {
fun bar() = true
}
fun test(foo: Foo?) {
val flag: Boolean
flag = foo?.bar() == true
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
@@ -8,4 +8,5 @@ fun test(foo: Foo?) {
}
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
@@ -8,4 +8,5 @@ fun test(foo: Foo?) {
}
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
@@ -0,0 +1,11 @@
// "Add '== true'" "true"
class Foo {
fun bar() = true
}
fun test(foo: Foo?) {
val flag: Boolean = foo?.bar()<caret>
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
@@ -0,0 +1,11 @@
// "Add '== true'" "true"
class Foo {
fun bar() = true
}
fun test(foo: Foo?) {
val flag: Boolean = foo?.bar() == true
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
@@ -0,0 +1,11 @@
// "Add '== true'" "true"
class Foo {
fun bar() = true
}
fun test(foo: Foo?): Boolean {
return foo?.bar()<caret>
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
@@ -0,0 +1,11 @@
// "Add '== true'" "true"
class Foo {
fun bar() = true
}
fun test(foo: Foo?): Boolean {
return foo?.bar() == true
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddEqEqTrueFix
@@ -0,0 +1,11 @@
// "Add non-null asserted (foo?.bar()!!) call" "true"
class Foo {
fun bar() = true
}
fun test(foo: Foo?) {
if (foo?.bar()<caret>) {
}
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix
@@ -0,0 +1,11 @@
// "Add non-null asserted (foo?.bar()!!) call" "true"
class Foo {
fun bar() = true
}
fun test(foo: Foo?) {
if (foo?.bar()!!) {
}
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix
@@ -67,7 +67,7 @@ internal fun MutableTWorkspace.generateK2FixTests() {
model("$idea/quickfix/addDefaultConstructor", pattern = pattern, isIgnored = true)
model("$idea/quickfix/addElseBranchToIf", pattern = pattern)
model("$idea/quickfix/addEmptyArgumentList", pattern = pattern, isIgnored = true)
model("$idea/quickfix/addEqEqTrue", pattern = pattern, isIgnored = true)
model("$idea/quickfix/addEqEqTrue", pattern = pattern)
model("$idea/quickfix/addFunModifier", pattern = pattern)
model("$idea/quickfix/addGenericUpperBound", pattern = pattern, isIgnored = true)
model("$idea/quickfix/addInline", pattern = pattern)