diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/UsageReplacementStrategy.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/UsageReplacementStrategy.kt index 2af6d76a365..8abe88bbc83 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/UsageReplacementStrategy.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/UsageReplacementStrategy.kt @@ -27,9 +27,12 @@ import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.ui.GuiUtils import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.core.targetDescriptors import org.jetbrains.kotlin.idea.intentions.ConvertReferenceToLambdaIntention +import org.jetbrains.kotlin.idea.intentions.SpecifyExplicitLambdaSignatureIntention import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope @@ -122,7 +125,7 @@ fun UsageReplacementStrategy.replaceUsages( val targetDeclaration = targetPsiElement as? KtNamedDeclaration val usagesChildrenFirst = usages.sortChildrenFirst() - for (usage in usagesChildrenFirst) { + usages@ for (usage in usagesChildrenFirst) { try { if (!usage.isValid) { invalidUsagesFound = true @@ -130,11 +133,35 @@ fun UsageReplacementStrategy.replaceUsages( } val usageParent = usage.parent - if (usageParent is KtCallableReferenceExpression) { - val grandParent = usageParent.parent - ConvertReferenceToLambdaIntention().applyTo(usageParent, null) - (grandParent as? KtElement)?.let { doRefactoringInside(it, targetDeclaration?.name, targetDeclaration?.descriptor) } - continue + when (usageParent) { + is KtCallableReferenceExpression -> { + val grandParent = usageParent.parent + ConvertReferenceToLambdaIntention().applyTo(usageParent, null) + (grandParent as? KtElement)?.let { + doRefactoringInside(it, targetDeclaration?.name, targetDeclaration?.descriptor) + } + continue@usages + } + is KtCallElement -> { + val lambdaArguments = usageParent.lambdaArguments + if (lambdaArguments.isNotEmpty()) { + val grandParent = usageParent.parent + val specifySignature = SpecifyExplicitLambdaSignatureIntention() + for (lambdaArgument in lambdaArguments) { + val lambdaExpression = lambdaArgument.getLambdaExpression() + val functionDescriptor = + lambdaExpression.functionLiteral.resolveToDescriptorIfAny() as? FunctionDescriptor ?: continue + if (functionDescriptor.valueParameters.isNotEmpty()) { + specifySignature.applyTo(lambdaExpression, null) + } + } + (grandParent as? KtElement)?.let { + doRefactoringInside(it, targetDeclaration?.name, targetDeclaration?.descriptor) + } + continue@usages + } + } + } //TODO: keep the import if we don't know how to replace some of the usages diff --git a/idea/testData/refactoring/inline/function/expressionBody/Lambda.kt b/idea/testData/refactoring/inline/function/expressionBody/Lambda.kt new file mode 100644 index 00000000000..f0b9cc7d3f2 --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/Lambda.kt @@ -0,0 +1,7 @@ +class Declaration { + fun lambdaType(p: Int, f: (Int) -> Int) = f(p) +} + +fun call(declaration: Declaration) { + declaration.lambdaType(6) { it + 7 } +} \ No newline at end of file diff --git a/idea/testData/refactoring/inline/function/expressionBody/Lambda.kt.after b/idea/testData/refactoring/inline/function/expressionBody/Lambda.kt.after new file mode 100644 index 00000000000..8fa176ecf0c --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/Lambda.kt.after @@ -0,0 +1,6 @@ +class Declaration { +} + +fun call(declaration: Declaration) { + ({ it: Int -> it + 7 })(6) +} \ No newline at end of file diff --git a/idea/testData/refactoring/inline/function/expressionBody/Lambda1.kt b/idea/testData/refactoring/inline/function/expressionBody/Lambda1.kt new file mode 100644 index 00000000000..526720e2af5 --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/Lambda1.kt @@ -0,0 +1,6 @@ +class Declaration { + fun lambdaType(p: Int, f: (Int) -> Int) = f(p) +} + +fun call(declaration: Declaration) { + declaration.lambdaType(8) { x -> x + 9 }} \ No newline at end of file diff --git a/idea/testData/refactoring/inline/function/expressionBody/Lambda1.kt.after b/idea/testData/refactoring/inline/function/expressionBody/Lambda1.kt.after new file mode 100644 index 00000000000..1c5110938ad --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/Lambda1.kt.after @@ -0,0 +1,6 @@ +class Declaration { +} + +fun call(declaration: Declaration) { + ({ x: Int -> x + 9 })(8) +} \ No newline at end of file diff --git a/idea/testData/refactoring/inline/function/expressionBody/Lambda2.kt b/idea/testData/refactoring/inline/function/expressionBody/Lambda2.kt new file mode 100644 index 00000000000..3d16ee96d42 --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/Lambda2.kt @@ -0,0 +1,7 @@ +class Declaration { + fun lambdaType(p: Int, f: (Int) -> Int) = f(p) +} + +fun call(declaration: Declaration) { + declaration.lambdaType(10) { _ -> 11 } +} \ No newline at end of file diff --git a/idea/testData/refactoring/inline/function/expressionBody/Lambda2.kt.after b/idea/testData/refactoring/inline/function/expressionBody/Lambda2.kt.after new file mode 100644 index 00000000000..2f6d5229d93 --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/Lambda2.kt.after @@ -0,0 +1,6 @@ +class Declaration { +} + +fun call(declaration: Declaration) { + ({ _: Int -> 11 })(10) +} \ No newline at end of file diff --git a/idea/testData/refactoring/inline/function/expressionBody/LambdaGeneric.kt b/idea/testData/refactoring/inline/function/expressionBody/LambdaGeneric.kt new file mode 100644 index 00000000000..7af526124bf --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/LambdaGeneric.kt @@ -0,0 +1,4 @@ +fun operateLambda(p: T, f: (T) -> U) = f(p) +fun returnLabel() { + operateLambda(1) {} +} \ No newline at end of file diff --git a/idea/testData/refactoring/inline/function/expressionBody/LambdaGeneric.kt.after b/idea/testData/refactoring/inline/function/expressionBody/LambdaGeneric.kt.after new file mode 100644 index 00000000000..2862d7d0e4c --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/LambdaGeneric.kt.after @@ -0,0 +1,3 @@ +fun returnLabel() { + ({ it: Int -> })(1) +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java index eb1c174a5ef..4076dc0f9f5 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java @@ -142,6 +142,30 @@ public class InlineTestGenerated extends AbstractInlineTest { doTest(fileName); } + @TestMetadata("Lambda.kt") + public void testLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/Lambda.kt"); + doTest(fileName); + } + + @TestMetadata("Lambda1.kt") + public void testLambda1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/Lambda1.kt"); + doTest(fileName); + } + + @TestMetadata("Lambda2.kt") + public void testLambda2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/Lambda2.kt"); + doTest(fileName); + } + + @TestMetadata("LambdaGeneric.kt") + public void testLambdaGeneric() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/LambdaGeneric.kt"); + doTest(fileName); + } + @TestMetadata("MultipleInComposition.kt") public void testMultipleInComposition() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/MultipleInComposition.kt");