Replace explicit parameter with it: don't suggest if overload resolution ambiguity error occurs

#KT-20795 Fixed
This commit is contained in:
Toshiaki Kameyama
2020-05-07 12:42:18 +09:00
committed by Yan Zhulanow
parent 69a2697598
commit 5b927d798c
8 changed files with 81 additions and 6 deletions
@@ -27,14 +27,16 @@ import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.analysis.analyzeAsReplacement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.copied
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class ReplaceExplicitFunctionLiteralParamWithItIntention : PsiElementBaseIntentionAction() {
override fun getFamilyName() = KotlinBundle.message("replace.explicit.lambda.parameter.with.it")
@@ -50,6 +52,19 @@ class ReplaceExplicitFunctionLiteralParamWithItIntention : PsiElementBaseIntenti
literal.usesName(element.text) && (!literal.hasParameterSpecification() || literal.usesName("it"))
}) return false
val lambda = functionLiteral.parent as? KtLambdaExpression ?: return false
val call = lambda.getStrictParentOfType<KtCallExpression>()
if (call != null) {
val argumentIndex = call.valueArguments.indexOfFirst { it.getArgumentExpression() == lambda }
val callOrQualified = call.getQualifiedExpressionForSelectorOrThis()
val newCallOrQualified = callOrQualified.copied()
val newCall = newCallOrQualified.safeAs<KtQualifiedExpression>()?.callExpression ?: newCallOrQualified.safeAs() ?: return false
val newArgument = newCall.valueArguments.getOrNull(argumentIndex) ?: newCall.lambdaArguments.singleOrNull() ?: return false
newArgument.replace(KtPsiFactory(element).createLambdaExpression("", "TODO()"))
val newContext = newCallOrQualified.analyzeAsReplacement(callOrQualified, callOrQualified.analyze(BodyResolveMode.PARTIAL))
if (newCallOrQualified.getResolvedCall(newContext)?.resultingDescriptor == null) return false
}
text = KotlinBundle.message("replace.explicit.parameter.0.with.it", parameter.name.toString())
return true
}
@@ -0,0 +1,5 @@
fun foo() {
val a: (Int) -> Unit = { <caret>a -> bar(a) }
}
fun bar(i: Int) {}
@@ -0,0 +1,5 @@
fun foo() {
val a: (Int) -> Unit = { bar(it) }
}
fun bar(i: Int) {}
@@ -0,0 +1,7 @@
fun test() {
C().foo { <caret>i -> i + 1 }
}
class C {
fun foo(f: (Int) -> Int) {}
}
@@ -0,0 +1,7 @@
fun test() {
C().foo { it + 1 }
}
class C {
fun foo(f: (Int) -> Int) {}
}
@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
fun test() {
foo { <caret>i -> i + 1 }
}
fun foo(f: (Int) -> Int) {}
fun foo(f: (Int, Int) -> Int) {}
@@ -0,0 +1,9 @@
// IS_APPLICABLE: false
fun test() {
C().foo { <caret>i -> i + 1 }
}
class C {
fun foo(f: (Int) -> Int) {}
fun foo(f: (Int, Int) -> Int) {}
}
@@ -14634,11 +14634,21 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_formatsProperly.kt");
}
@TestMetadata("applicable_inPropertyInitializer.kt")
public void testApplicable_inPropertyInitializer() throws Exception {
runTest("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_inPropertyInitializer.kt");
}
@TestMetadata("applicable_nestedLiteralsNoUseInside.kt")
public void testApplicable_nestedLiteralsNoUseInside() throws Exception {
runTest("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_nestedLiteralsNoUseInside.kt");
}
@TestMetadata("applicable_qualifiedExpression.kt")
public void testApplicable_qualifiedExpression() throws Exception {
runTest("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_qualifiedExpression.kt");
}
@TestMetadata("notApplicable_alreadyUsesImplicitIt.kt")
public void testNotApplicable_alreadyUsesImplicitIt() throws Exception {
runTest("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_alreadyUsesImplicitIt.kt");
@@ -14674,6 +14684,16 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_notFunctionLiteralParameter.kt");
}
@TestMetadata("notApplicable_overloadResolutionAmbiguity.kt")
public void testNotApplicable_overloadResolutionAmbiguity() throws Exception {
runTest("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_overloadResolutionAmbiguity.kt");
}
@TestMetadata("notApplicable_overloadResolutionAmbiguity2.kt")
public void testNotApplicable_overloadResolutionAmbiguity2() throws Exception {
runTest("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_overloadResolutionAmbiguity2.kt");
}
@TestMetadata("notApplicable_parameterHasExplicitType.kt")
public void testNotApplicable_parameterHasExplicitType() throws Exception {
runTest("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_parameterHasExplicitType.kt");