Inliner: specify explicit lambda signature for calls with lambdas
So #KT-17213 Fixed So #KT-17395 Fixed
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
class Declaration {
|
||||
fun lambdaType(p: Int, f: (Int) -> Int) = f(p)
|
||||
}
|
||||
|
||||
fun call(declaration: Declaration) {
|
||||
declaration.<caret>lambdaType(6) { it + 7 }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Declaration {
|
||||
}
|
||||
|
||||
fun call(declaration: Declaration) {
|
||||
({ it: Int -> it + 7 })(6)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Declaration {
|
||||
fun lambdaType(p: Int, f: (Int) -> Int) = f(p)
|
||||
}
|
||||
|
||||
fun call(declaration: Declaration) {
|
||||
declaration.<caret>lambdaType(8) { x -> x + 9 }}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Declaration {
|
||||
}
|
||||
|
||||
fun call(declaration: Declaration) {
|
||||
({ x: Int -> x + 9 })(8)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class Declaration {
|
||||
fun lambdaType(p: Int, f: (Int) -> Int) = f(p)
|
||||
}
|
||||
|
||||
fun call(declaration: Declaration) {
|
||||
declaration.<caret>lambdaType(10) { _ -> 11 }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Declaration {
|
||||
}
|
||||
|
||||
fun call(declaration: Declaration) {
|
||||
({ _: Int -> 11 })(10)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun <T, U> operateLambda(p: T, f: (T) -> U) = f(p)
|
||||
fun returnLabel() {
|
||||
<caret>operateLambda(1) {}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fun returnLabel() {
|
||||
({ it: Int -> })(1)
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user