diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties index 47f26d9cbbb..e9eab708f07 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties @@ -290,10 +290,6 @@ add.name.to.argument.single=Add name to argument\: ''{0}'' add.name.to.argument.multiple=Add name to argument... add.name.to.argument.action=Add name to argument... add.name.to.parameter.name.chooser.title=Choose parameter name -replace.with.infix.function.call.intention=Replace with infix function call -replace.with.infix.function.call.intention.family=Replace with Infix Function Call -replace.with.infix.function.call.intention.error.resolution.failed=The element cannot be resolved -replace.with.infix.function.call.intention.error.package.call=Cannot be applied with a package as the receiver split.if=Split into 2 if's split.if.family=Split If replace.with.operator.assign.intention=Replace with an operator-assign expression diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceWithInfixFunctionCallIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceWithInfixFunctionCallIntention.kt index 663e10244aa..34efd2aa9d7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceWithInfixFunctionCallIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceWithInfixFunctionCallIntention.kt @@ -16,92 +16,42 @@ package org.jetbrains.kotlin.idea.intentions -import org.jetbrains.kotlin.psi.JetCallExpression import com.intellij.openapi.editor.Editor -import org.jetbrains.kotlin.psi.JetDotQualifiedExpression -import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.idea.JetBundle -import org.jetbrains.kotlin.psi.JetValueArgument -import org.jetbrains.kotlin.psi.JetPsiUnparsingUtils -import org.jetbrains.kotlin.psi.JetPsiFactory -import com.intellij.codeInsight.hint.HintManager -import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.psi.JetBinaryExpression +import org.jetbrains.kotlin.psi.JetCallExpression +import org.jetbrains.kotlin.psi.JetDotQualifiedExpression +import org.jetbrains.kotlin.psi.JetPsiFactory -public open class ReplaceWithInfixFunctionCallIntention : JetSelfTargetingIntention("replace.with.infix.function.call.intention", javaClass()) { +public class ReplaceWithInfixFunctionCallIntention : JetSelfTargetingIntention(javaClass(), "Replace with infix function call") { override fun isApplicableTo(element: JetCallExpression, caretOffset: Int): Boolean { - val calleeExpr = element.getCalleeExpression() - if (calleeExpr == null) return false + val calleeExpr = element.getCalleeExpression() ?: return false + if (!calleeExpr.getTextRange().containsOffset(caretOffset)) return false - val textRange = calleeExpr.getTextRange() - if (textRange == null) return false + val dotQualified = element.getParent() as? JetDotQualifiedExpression ?: return false - if (caretOffset !in textRange) return false + if (element.getTypeArgumentList() != null) return false - val parent = element.getParent() + val argument = element.getValueArguments().singleOrNull() ?: return false + if (argument.isNamed()) return false + if (argument.getArgumentExpression() == null) return false - if (parent is JetDotQualifiedExpression) { - val typeArguments = element.getTypeArgumentList() - val valueArguments = element.getValueArgumentList() - val functionLiteralArguments = element.getFunctionLiteralArguments() - val numOfTotalValueArguments = (valueArguments?.getArguments()?.size() ?: 0) + functionLiteralArguments.size() + val receiver = dotQualified.getReceiverExpression() + if (element.analyze().getType(receiver) == null) return false - if (typeArguments?.getArguments()?.size() ?: 0 == 0 && - numOfTotalValueArguments == 1) { - - if (valueArguments?.getArguments()?.size() == 1 && valueArguments?.getArguments()?.first()?.isNamed() ?: false) { - val file = element.getContainingJetFile() - val bindingContext = file.analyzeFully() - val resolvedCall = element.getResolvedCall(bindingContext) - val valueArgumentsMap = resolvedCall?.getValueArguments() - val firstArgument = valueArguments?.getArguments()?.first() - - return valueArgumentsMap?.keySet()?.any { it.getName().asString() == firstArgument?.getArgumentName()?.getText() && it.getIndex() == 0 } ?: false - } else { - return true - } - } else { - return false - } - } else { - return false - } - } - - open fun intentionFailed(editor: Editor, messageID: String) { - val message = "Intention failed: ${JetBundle.message("replace.with.infix.function.call.intention.error.$messageID")}" - HintManager.getInstance().showErrorHint(editor, message) + return true } override fun applyTo(element: JetCallExpression, editor: Editor) { - val parent = element.getParent() as JetDotQualifiedExpression - val receiver = parent.getReceiverExpression() - val leftHandText = parent.getReceiverExpression().getText() - val rightHandTextStringBuilder = StringBuilder() + val dotQualified = element.getParent() as JetDotQualifiedExpression + val receiver = dotQualified.getReceiverExpression() + val operatorText = element.getCalleeExpression()!!.getText() - val valueArguments = element.getValueArgumentList()?.getArguments() ?: listOf() - val functionLiteralArguments = element.getFunctionLiteralArguments() - val bindingContext = parent.analyze() - val receiverType = bindingContext.getType(receiver) - if (receiverType == null) { - if (bindingContext[BindingContext.QUALIFIER, receiver] != null) { - intentionFailed(editor, "package.call") - return - } - intentionFailed(editor, "resolution.failed") - return - } - rightHandTextStringBuilder.append( - if (valueArguments.size() > 0) - JetPsiUnparsingUtils.parenthesizeIfNeeded(valueArguments.first().getArgumentExpression()) - else - functionLiteralArguments.first().getText() - ) + val newCall = JetPsiFactory(element).createExpression("${receiver.getText()} $operatorText x") as JetBinaryExpression + val argument = element.getValueArguments().single() + newCall.getRight()!!.replace(argument.getArgumentExpression()!!) - val replacement = JetPsiFactory(element).createExpression("$leftHandText $operatorText ${rightHandTextStringBuilder.toString()}") - - parent.replace(replacement) + dotQualified.replace(newCall) } } diff --git a/idea/testData/intentions/replaceWithInfixFunctionCall/.intention b/idea/testData/intentions/replaceWithInfixFunctionCall/.intention index 781a2f5c83c..b8aaae1c0b3 100644 --- a/idea/testData/intentions/replaceWithInfixFunctionCall/.intention +++ b/idea/testData/intentions/replaceWithInfixFunctionCall/.intention @@ -1 +1 @@ -org.jetbrains.kotlin.idea.intentions.TestableReplaceWithInfixFunctionCallIntention +org.jetbrains.kotlin.idea.intentions.ReplaceWithInfixFunctionCallIntention diff --git a/idea/testData/intentions/replaceWithInfixFunctionCall/binaryExpressionArgument.kt.after b/idea/testData/intentions/replaceWithInfixFunctionCall/binaryExpressionArgument.kt.after index b014afd2cbd..ae8d6d9e685 100644 --- a/idea/testData/intentions/replaceWithInfixFunctionCall/binaryExpressionArgument.kt.after +++ b/idea/testData/intentions/replaceWithInfixFunctionCall/binaryExpressionArgument.kt.after @@ -1,3 +1,3 @@ fun foo(x: Int) { - x compareTo (1 + 2) + x compareTo 1 + 2 } diff --git a/idea/testData/intentions/replaceWithInfixFunctionCall/firstParameterLabeled.kt b/idea/testData/intentions/replaceWithInfixFunctionCall/firstParameterLabeled.kt deleted file mode 100644 index 7cbd2db8368..00000000000 --- a/idea/testData/intentions/replaceWithInfixFunctionCall/firstParameterLabeled.kt +++ /dev/null @@ -1,11 +0,0 @@ -fun doSomething(a: T) {} - -class Foo { - fun foo(x: Int) { - doSomething("lol") - } -} - -fun bar(baz: Foo) { - baz.foo(x = 1) -} diff --git a/idea/testData/intentions/replaceWithInfixFunctionCall/firstParameterLabeled.kt.after b/idea/testData/intentions/replaceWithInfixFunctionCall/firstParameterLabeled.kt.after deleted file mode 100644 index 7e619b0fbe5..00000000000 --- a/idea/testData/intentions/replaceWithInfixFunctionCall/firstParameterLabeled.kt.after +++ /dev/null @@ -1,11 +0,0 @@ -fun doSomething(a: T) {} - -class Foo { - fun foo(x: Int) { - doSomething("lol") - } -} - -fun bar(baz: Foo) { - baz foo 1 -} diff --git a/idea/testData/intentions/replaceWithInfixFunctionCall/packageFunctionCall.kt b/idea/testData/intentions/replaceWithInfixFunctionCall/packageFunctionCall.kt index 7b9cf5de6b6..d1d3e674e10 100644 --- a/idea/testData/intentions/replaceWithInfixFunctionCall/packageFunctionCall.kt +++ b/idea/testData/intentions/replaceWithInfixFunctionCall/packageFunctionCall.kt @@ -1,5 +1,5 @@ +// IS_APPLICABLE: false // WITH_RUNTIME -// SHOULD_FAIL_WITH: package.call fun main() { kotlin.io.println("") } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index fa14e733316..90cde1a0883 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -5393,12 +5393,6 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } - @TestMetadata("firstParameterLabeled.kt") - public void testFirstParameterLabeled() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/replaceWithInfixFunctionCall/firstParameterLabeled.kt"); - doTest(fileName); - } - @TestMetadata("functionLiteralArgument.kt") public void testFunctionLiteralArgument() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/replaceWithInfixFunctionCall/functionLiteralArgument.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/TestableReplaceWithInfixFunctionCallIntention.kt b/idea/tests/org/jetbrains/kotlin/idea/intentions/TestableReplaceWithInfixFunctionCallIntention.kt deleted file mode 100644 index 8cc4c2ac855..00000000000 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/TestableReplaceWithInfixFunctionCallIntention.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.idea.intentions - -import com.intellij.openapi.editor.Editor - -public class TestableReplaceWithInfixFunctionCallIntention : ReplaceWithInfixFunctionCallIntention() { - override fun intentionFailed(editor: Editor, messageID: String) { - throw IntentionTestException(messageID) - } -}