From b53cb91e8824f1fe95ef6c3542faca6b7e6f5084 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 11 Aug 2016 15:39:55 +0300 Subject: [PATCH] Do not suggest "Replace infix with safe call" inside conditions or binary / unary expressions #KT-13328 Fixed --- .../quickfix/ReplaceInfixOrOperatorCallFix.kt | 12 +++++++++- .../nullables/unsafeInfixCall/operator.kt | 2 +- .../unsafeInfixCall/operator.kt.after | 2 +- .../unsafeComparisonInCondition.kt | 11 +++++++++ .../unsafeComparisonInLogic.kt | 12 ++++++++++ .../unsafeInfixCall/unsafeComparisonInWhen.kt | 13 ++++++++++ .../unsafeComparisonInWhile.kt | 11 +++++++++ .../idea/quickfix/QuickFixTestGenerated.java | 24 +++++++++++++++++++ 8 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInCondition.kt create mode 100644 idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInLogic.kt create mode 100644 idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInWhen.kt create mode 100644 idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInWhile.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ReplaceInfixOrOperatorCallFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ReplaceInfixOrOperatorCallFix.kt index 74334b956ad..3ddb8afbd7d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ReplaceInfixOrOperatorCallFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ReplaceInfixOrOperatorCallFix.kt @@ -19,12 +19,18 @@ package org.jetbrains.kotlin.idea.quickfix import com.intellij.codeInsight.intention.IntentionAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project +import com.intellij.psi.tree.TokenSet import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType +import org.jetbrains.kotlin.psi.psiUtil.parents +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.types.expressions.OperatorConventions +import org.jetbrains.kotlin.types.typeUtil.isBoolean class ReplaceInfixOrOperatorCallFix(element: KtExpression) : KotlinQuickFixAction(element) { @@ -87,7 +93,11 @@ class ReplaceInfixOrOperatorCallFix(element: KtExpression) : KotlinQuickFixActio return when (parent) { is KtBinaryExpression -> { if (parent.left == null || parent.right == null) null - else ReplaceInfixOrOperatorCallFix(parent) + else { + if (parent.operationToken in OperatorConventions.COMPARISON_OPERATIONS && + parent.analyze()[BindingContext.EXPECTED_EXPRESSION_TYPE, parent]?.isBoolean() ?: false) null + else ReplaceInfixOrOperatorCallFix(parent) + } } is KtCallExpression -> { if (parent.calleeExpression == null) null diff --git a/idea/testData/quickfix/nullables/unsafeInfixCall/operator.kt b/idea/testData/quickfix/nullables/unsafeInfixCall/operator.kt index b20070b06bd..978dd64e9c2 100644 --- a/idea/testData/quickfix/nullables/unsafeInfixCall/operator.kt +++ b/idea/testData/quickfix/nullables/unsafeInfixCall/operator.kt @@ -2,6 +2,6 @@ // ERROR: Infix call corresponds to a dot-qualified call 'value?.compareTo(1).compareTo(0)' which is not allowed on a nullable receiver 'value?.compareTo(1)'. Use '?.'-qualified call instead var foo: Int? = null set(value) { - if(value < 1) { + if((value < 1) ?: false) { } } \ No newline at end of file diff --git a/idea/testData/quickfix/nullables/unsafeInfixCall/operator.kt.after b/idea/testData/quickfix/nullables/unsafeInfixCall/operator.kt.after index 595dcfc3393..7217ba54619 100644 --- a/idea/testData/quickfix/nullables/unsafeInfixCall/operator.kt.after +++ b/idea/testData/quickfix/nullables/unsafeInfixCall/operator.kt.after @@ -2,6 +2,6 @@ // ERROR: Infix call corresponds to a dot-qualified call 'value?.compareTo(1).compareTo(0)' which is not allowed on a nullable receiver 'value?.compareTo(1)'. Use '?.'-qualified call instead var foo: Int? = null set(value) { - if(value?.compareTo(1) < 0) { + if((value?.compareTo(1) < 0) ?: false) { } } \ No newline at end of file diff --git a/idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInCondition.kt b/idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInCondition.kt new file mode 100644 index 00000000000..2714895ba42 --- /dev/null +++ b/idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInCondition.kt @@ -0,0 +1,11 @@ +// "Replace with safe (?.) call" "false" +// ACTION: Add non-null asserted (!!) call +// ACTION: Flip '<' +// ACTION: Replace overloaded operator with function call +// ERROR: Infix call corresponds to a dot-qualified call 'w?.x.compareTo(42)' which is not allowed on a nullable receiver 'w?.x'. Use '?.'-qualified call instead + +class Wrapper(val x: Int) + +fun test(w: Wrapper?) { + if (w?.x < 42) {} +} \ No newline at end of file diff --git a/idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInLogic.kt b/idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInLogic.kt new file mode 100644 index 00000000000..1d9be5fa60a --- /dev/null +++ b/idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInLogic.kt @@ -0,0 +1,12 @@ +// "Replace with safe (?.) call" "false" +// ACTION: Add non-null asserted (!!) call +// ACTION: Flip '>' +// ACTION: Replace overloaded operator with function call +// ACTION: Simplify boolean expression +// ERROR: Infix call corresponds to a dot-qualified call 'w?.x.compareTo(42)' which is not allowed on a nullable receiver 'w?.x'. Use '?.'-qualified call instead + +class Wrapper(val x: Int) + +fun test(w: Wrapper?) { + val t = 1 < 2 && w?.x > 42 +} \ No newline at end of file diff --git a/idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInWhen.kt b/idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInWhen.kt new file mode 100644 index 00000000000..09c13cca28f --- /dev/null +++ b/idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInWhen.kt @@ -0,0 +1,13 @@ +// "Replace with safe (?.) call" "false" +// ACTION: Add non-null asserted (!!) call +// ACTION: Flip '<=' +// ACTION: Replace overloaded operator with function call +// ERROR: Infix call corresponds to a dot-qualified call 'w?.x.compareTo(42)' which is not allowed on a nullable receiver 'w?.x'. Use '?.'-qualified call instead + +class Wrapper(val x: Int) + +fun test(w: Wrapper?) { + when { + w?.x <= 42 -> {} + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInWhile.kt b/idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInWhile.kt new file mode 100644 index 00000000000..7177842cc77 --- /dev/null +++ b/idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInWhile.kt @@ -0,0 +1,11 @@ +// "Replace with safe (?.) call" "false" +// ACTION: Add non-null asserted (!!) call +// ACTION: Flip '>=' +// ACTION: Replace overloaded operator with function call +// ERROR: Infix call corresponds to a dot-qualified call 'w?.x.compareTo(42)' which is not allowed on a nullable receiver 'w?.x'. Use '?.'-qualified call instead + +class Wrapper(val x: Int) + +fun test(w: Wrapper?) { + while (w?.x >= 42) {} +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 8efe786c017..2a79ac14784 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -6153,6 +6153,30 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("unsafeComparisonInCondition.kt") + public void testUnsafeComparisonInCondition() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInCondition.kt"); + doTest(fileName); + } + + @TestMetadata("unsafeComparisonInLogic.kt") + public void testUnsafeComparisonInLogic() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInLogic.kt"); + doTest(fileName); + } + + @TestMetadata("unsafeComparisonInWhen.kt") + public void testUnsafeComparisonInWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInWhen.kt"); + doTest(fileName); + } + + @TestMetadata("unsafeComparisonInWhile.kt") + public void testUnsafeComparisonInWhile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/nullables/unsafeInfixCall/unsafeComparisonInWhile.kt"); + doTest(fileName); + } + @TestMetadata("unsafeGet.kt") public void testUnsafeGet() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/nullables/unsafeInfixCall/unsafeGet.kt");