From efdeb7b449b4761d113b5c0b908d63dca01b9f01 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Thu, 2 Jul 2020 15:55:36 +0900 Subject: [PATCH] Introduce "Add '== true'" quick fix for TYPE_MISMATCH #KT-39930 Fixed --- .../messages/KotlinBundle.properties | 1 + .../kotlin/idea/quickfix/AddEqEqTrueFix.kt | 25 ++++++++++++++ .../QuickFixFactoryForTypeMismatchError.kt | 11 ++++--- .../quickfix/addEqEqTrue/notBoolean.kt | 10 ++++++ .../quickfix/addEqEqTrue/notBoolean2.kt | 14 ++++++++ idea/testData/quickfix/addEqEqTrue/simple.kt | 9 +++++ .../quickfix/addEqEqTrue/simple.kt.after | 9 +++++ idea/testData/quickfix/addEqEqTrue/simple2.kt | 10 ++++++ .../quickfix/addEqEqTrue/simple2.kt.after | 10 ++++++ .../QuickFixMultiFileTestGenerated.java | 13 ++++++++ .../idea/quickfix/QuickFixTestGenerated.java | 33 +++++++++++++++++++ 11 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/AddEqEqTrueFix.kt create mode 100644 idea/testData/quickfix/addEqEqTrue/notBoolean.kt create mode 100644 idea/testData/quickfix/addEqEqTrue/notBoolean2.kt create mode 100644 idea/testData/quickfix/addEqEqTrue/simple.kt create mode 100644 idea/testData/quickfix/addEqEqTrue/simple.kt.after create mode 100644 idea/testData/quickfix/addEqEqTrue/simple2.kt create mode 100644 idea/testData/quickfix/addEqEqTrue/simple2.kt.after diff --git a/idea/resources-en/messages/KotlinBundle.properties b/idea/resources-en/messages/KotlinBundle.properties index 0a605c9ac29..c53f84c71d9 100644 --- a/idea/resources-en/messages/KotlinBundle.properties +++ b/idea/resources-en/messages/KotlinBundle.properties @@ -2240,6 +2240,7 @@ title.import.layout=Import Layout title.packages.to.use.import.with=Packages to Use Import with '*' redundant.qualifier.unnecessary.non.direct.parent.class.qualifier=Unnecessary non-direct parent classes qualifiers fix.add.exception.to.throws=Add ''{0}'' +fix.add.eq.eq.true=Add '== true' hints.title.codevision=Code Vision hints.title.codevision.show.hints.for=Show hints for: diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddEqEqTrueFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddEqEqTrueFix.kt new file mode 100644 index 00000000000..74cb5abed8b --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddEqEqTrueFix.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2020 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.idea.quickfix + +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.idea.KotlinBundle +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.createExpressionByPattern + +class AddEqEqTrueFix(expression: KtExpression) : KotlinQuickFixAction(expression) { + override fun getText() = KotlinBundle.message("fix.add.eq.eq.true") + + override fun getFamilyName() = text + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val expression = element ?: return + expression.replace(KtPsiFactory(expression).createExpressionByPattern("$0 == true", expression)) + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixFactoryForTypeMismatchError.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixFactoryForTypeMismatchError.kt index 6722cacfde6..86276399c8b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixFactoryForTypeMismatchError.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixFactoryForTypeMismatchError.kt @@ -50,10 +50,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE -import org.jetbrains.kotlin.types.typeUtil.isInterface -import org.jetbrains.kotlin.types.typeUtil.isSignedOrUnsignedNumberType -import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf -import org.jetbrains.kotlin.types.typeUtil.makeNullable +import org.jetbrains.kotlin.types.typeUtil.* import java.util.* //TODO: should use change signature to deal with cases of multiple overridden descriptors @@ -168,7 +165,11 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() { if (!expectedType.isMarkedNullable && TypeUtils.isNullableType(expressionType)) { val nullableExpected = expectedType.makeNullable() if (expressionType.isSubtypeOf(nullableExpected)) { - actions.add(AddExclExclCallFix(diagnosticElement.getTopMostQualifiedForSelectorIfAny())) + val targetExpression = diagnosticElement.getTopMostQualifiedForSelectorIfAny() + actions.add(AddExclExclCallFix(targetExpression)) + if (expectedType.isBoolean()) { + actions.add(AddEqEqTrueFix(targetExpression)) + } } } diff --git a/idea/testData/quickfix/addEqEqTrue/notBoolean.kt b/idea/testData/quickfix/addEqEqTrue/notBoolean.kt new file mode 100644 index 00000000000..4fef121f70b --- /dev/null +++ b/idea/testData/quickfix/addEqEqTrue/notBoolean.kt @@ -0,0 +1,10 @@ +// "Add '== true'" "false" +// DISABLE-ERRORS +class Foo { + fun bar() = "" +} + +fun test(foo: Foo?) { + if (foo?.bar()) { + } +} diff --git a/idea/testData/quickfix/addEqEqTrue/notBoolean2.kt b/idea/testData/quickfix/addEqEqTrue/notBoolean2.kt new file mode 100644 index 00000000000..12a650c453c --- /dev/null +++ b/idea/testData/quickfix/addEqEqTrue/notBoolean2.kt @@ -0,0 +1,14 @@ +// "Add '== true'" "false" +// DISABLE-ERRORS +// ACTION: Add 'toString()' call +// ACTION: Change parameter 's' type of function 'baz' to 'Boolean?' +// ACTION: Create function 'baz' +class Foo { + fun bar() = true +} + +fun baz(s: String) {} + +fun test(foo: Foo?) { + baz(foo?.bar()) +} diff --git a/idea/testData/quickfix/addEqEqTrue/simple.kt b/idea/testData/quickfix/addEqEqTrue/simple.kt new file mode 100644 index 00000000000..36cb724a5cd --- /dev/null +++ b/idea/testData/quickfix/addEqEqTrue/simple.kt @@ -0,0 +1,9 @@ +// "Add '== true'" "true" +class Foo { + fun bar() = true +} + +fun test(foo: Foo?) { + if (foo?.bar()) { + } +} diff --git a/idea/testData/quickfix/addEqEqTrue/simple.kt.after b/idea/testData/quickfix/addEqEqTrue/simple.kt.after new file mode 100644 index 00000000000..0cf74078c18 --- /dev/null +++ b/idea/testData/quickfix/addEqEqTrue/simple.kt.after @@ -0,0 +1,9 @@ +// "Add '== true'" "true" +class Foo { + fun bar() = true +} + +fun test(foo: Foo?) { + if (foo?.bar() == true) { + } +} diff --git a/idea/testData/quickfix/addEqEqTrue/simple2.kt b/idea/testData/quickfix/addEqEqTrue/simple2.kt new file mode 100644 index 00000000000..2d3ac151e40 --- /dev/null +++ b/idea/testData/quickfix/addEqEqTrue/simple2.kt @@ -0,0 +1,10 @@ +// "Add '== true'" "true" +class Foo { + fun bar() = true +} + +fun baz(b: Boolean) {} + +fun test(foo: Foo?) { + baz(foo?.bar()) +} diff --git a/idea/testData/quickfix/addEqEqTrue/simple2.kt.after b/idea/testData/quickfix/addEqEqTrue/simple2.kt.after new file mode 100644 index 00000000000..986547bdcf8 --- /dev/null +++ b/idea/testData/quickfix/addEqEqTrue/simple2.kt.after @@ -0,0 +1,10 @@ +// "Add '== true'" "true" +class Foo { + fun bar() = true +} + +fun baz(b: Boolean) {} + +fun test(foo: Foo?) { + baz(foo?.bar() == true) +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index 091eb3ddf94..c771acb36eb 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -111,6 +111,19 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/addEqEqTrue") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddEqEqTrue extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, this, testDataFilePath); + } + + public void testAllFilesPresentInAddEqEqTrue() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/addEqEqTrue"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), null, true); + } + } + @TestMetadata("idea/testData/quickfix/addExclExclCall") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index db7e5251822..9916740657d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -576,6 +576,39 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/addEqEqTrue") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddEqEqTrue extends AbstractQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInAddEqEqTrue() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/addEqEqTrue"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("notBoolean.kt") + public void testNotBoolean() throws Exception { + runTest("idea/testData/quickfix/addEqEqTrue/notBoolean.kt"); + } + + @TestMetadata("notBoolean2.kt") + public void testNotBoolean2() throws Exception { + runTest("idea/testData/quickfix/addEqEqTrue/notBoolean2.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("idea/testData/quickfix/addEqEqTrue/simple.kt"); + } + + @TestMetadata("simple2.kt") + public void testSimple2() throws Exception { + runTest("idea/testData/quickfix/addEqEqTrue/simple2.kt"); + } + } + @TestMetadata("idea/testData/quickfix/addExclExclCall") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)