mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] Port ReplaceExplicitFunctionLiteralParamWithItIntention for K2
^KTIJ-30542 GitOrigin-RevId: 04c20b21e48b497a15f1a5b71696554005cb2ffd
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8964bcba12
commit
47a4785a87
+7
@@ -351,5 +351,12 @@
|
||||
<bundleName>messages.KotlinBundle</bundleName>
|
||||
<categoryKey>group.names.kotlin</categoryKey>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<language>kotlin</language>
|
||||
<className>org.jetbrains.kotlin.idea.k2.codeinsight.intentions.ReplaceExplicitFunctionLiteralParamWithItIntention</className>
|
||||
<bundleName>messages.KotlinBundle</bundleName>
|
||||
<categoryKey>group.names.kotlin</categoryKey>
|
||||
</intentionAction>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.k2.codeinsight.intentions
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces
|
||||
import com.intellij.openapi.actionSystem.impl.Utils.computeWithProgressIcon
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.ui.awt.RelativePoint
|
||||
import com.intellij.util.application
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.api.resolution.singleFunctionCallOrNull
|
||||
import org.jetbrains.kotlin.analysis.api.resolution.symbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaAnonymousFunctionSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaValueParameterSymbol
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.classic.intentions.SelfTargetingIntention
|
||||
import org.jetbrains.kotlin.idea.codeinsight.utils.findExistingEditor
|
||||
import org.jetbrains.kotlin.idea.codeinsights.impl.base.intentions.ReplaceExplicitLambdaParameterWithItUtils.ParamRenamingProcessor
|
||||
import org.jetbrains.kotlin.idea.codeinsights.impl.base.intentions.ReplaceExplicitLambdaParameterWithItUtils.createAnalyzableExpression
|
||||
import org.jetbrains.kotlin.idea.codeinsights.impl.base.intentions.ReplaceExplicitLambdaParameterWithItUtils.getLambda
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFunctionLiteral
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getPossiblyQualifiedCallExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
|
||||
|
||||
internal class ReplaceExplicitFunctionLiteralParamWithItIntention : SelfTargetingIntention<KtElement>(
|
||||
KtElement::class.java,
|
||||
KotlinBundle.lazyMessage("replace.explicit.lambda.parameter.with.it"),
|
||||
) {
|
||||
|
||||
override fun startInWriteAction(): Boolean = false
|
||||
|
||||
override fun isApplicableTo(element: KtElement, caretOffset: Int): Boolean {
|
||||
val functionLiteral = targetFunctionLiteral(element, caretOffset) ?: return false
|
||||
val explicitParameterName = functionLiteral.valueParameters.singleOrNull()?.name ?: return false
|
||||
val lambda = getLambda(element, functionLiteral) ?: return false
|
||||
val call = lambda.getStrictParentOfType<KtCallExpression>()
|
||||
|
||||
if (call != null) {
|
||||
val argumentIndex = call.valueArguments.indexOfFirst { it.getArgumentExpression() == lambda }
|
||||
val callOrQualified = call.getQualifiedExpressionForSelectorOrThis()
|
||||
val newCallOrQualified = createAnalyzableExpression(element.project, argumentIndex, callOrQualified) ?: return false
|
||||
val codeFragment = KtPsiFactory(element.project).createExpressionCodeFragment(newCallOrQualified.text, element)
|
||||
val contentElement = codeFragment.getContentElement()!!
|
||||
|
||||
return computeWithProgressIconIfNeeded(element.findExistingEditor()!!, caretOffset) {
|
||||
analyze(contentElement) {
|
||||
val resolveToCall = contentElement.getPossiblyQualifiedCallExpression()?.resolveToCall()
|
||||
resolveToCall?.singleFunctionCallOrNull()?.partiallyAppliedSymbol?.symbol != null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setTextGetter { KotlinBundle.message("replace.explicit.parameter.0.with.it", explicitParameterName) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun applyTo(element: KtElement, editor: Editor?) {
|
||||
val caretOffset = editor?.caretModel?.offset ?: return
|
||||
val functionLiteral = targetFunctionLiteral(element, editor.caretModel.offset) ?: return
|
||||
val cursorInParameterList = functionLiteral.valueParameterList?.textRange?.containsOffset(caretOffset) ?: return
|
||||
ParamRenamingProcessor(editor, functionLiteral, cursorInParameterList).run()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun targetFunctionLiteral(element: KtElement, caretOffset: Int): KtFunctionLiteral? {
|
||||
val expression = element.getParentOfType<KtNameReferenceExpression>(false)
|
||||
if (expression != null) {
|
||||
return computeWithProgressIconIfNeeded(element.findExistingEditor()!!, caretOffset) {
|
||||
analyze(expression) {
|
||||
val target = expression.mainReference.resolveToSymbols().singleOrNull() as? KaValueParameterSymbol ?: return@analyze null
|
||||
val functionDescriptor = target.containingSymbol as? KaAnonymousFunctionSymbol ?: return@analyze null
|
||||
functionDescriptor.psi as? KtFunctionLiteral
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val functionLiteral = element.getParentOfType<KtFunctionLiteral>(true) ?: return null
|
||||
val arrow = functionLiteral.arrow ?: return null
|
||||
if (caretOffset > arrow.endOffset) return null
|
||||
return functionLiteral
|
||||
}
|
||||
|
||||
private fun <T> computeWithProgressIconIfNeeded(editor: Editor, caretOffset: Int, action: () -> T): T {
|
||||
return if (application.isDispatchThread()) {
|
||||
val aComponent = editor.contentComponent
|
||||
val point = RelativePoint(aComponent, editor.logicalPositionToXY(editor.offsetToLogicalPosition(caretOffset)))
|
||||
computeWithProgressIcon(point, aComponent, ActionPlaces.UNKNOWN) {
|
||||
readAction { action() }
|
||||
}
|
||||
}
|
||||
else {
|
||||
action()
|
||||
}
|
||||
}
|
||||
+142
@@ -7076,7 +7076,149 @@ public abstract class K2IntentionTestGenerated extends AbstractK2IntentionTest {
|
||||
|
||||
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt")
|
||||
public static class ReplaceExplicitFunctionLiteralParamWithIt extends AbstractK2IntentionTest {
|
||||
@java.lang.Override
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final KotlinPluginMode getPluginMode() {
|
||||
return KotlinPluginMode.K2;
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_InIf.kt")
|
||||
public void testApplicable_InIf() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_InIf.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_InIfElse.kt")
|
||||
public void testApplicable_InIfElse() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_InIfElse.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_cursofOverParamInInnerLiteral.kt")
|
||||
public void testApplicable_cursofOverParamInInnerLiteral() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_cursofOverParamInInnerLiteral.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_cursorOverParameterDeclaration.kt")
|
||||
public void testApplicable_cursorOverParameterDeclaration() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_cursorOverParameterDeclaration.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_cursorOverParameterUse.kt")
|
||||
public void testApplicable_cursorOverParameterUse() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_cursorOverParameterUse.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_formatsProperly.kt")
|
||||
public void testApplicable_formatsProperly() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_formatsProperly.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_inPropertyInitializer.kt")
|
||||
public void testApplicable_inPropertyInitializer() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_inPropertyInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_inWhenEntry.kt")
|
||||
public void testApplicable_inWhenEntry() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_inWhenEntry.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_nestedLiteralsNoUseInside.kt")
|
||||
public void testApplicable_nestedLiteralsNoUseInside() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_nestedLiteralsNoUseInside.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_overloadResolutionUnambiguity.kt")
|
||||
public void testApplicable_overloadResolutionUnambiguity() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_overloadResolutionUnambiguity.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_overloadResolutionUnambiguity2.kt")
|
||||
public void testApplicable_overloadResolutionUnambiguity2() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_overloadResolutionUnambiguity2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_qualifiedExpression.kt")
|
||||
public void testApplicable_qualifiedExpression() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_qualifiedExpression.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_InIf.kt")
|
||||
public void testNotApplicable_InIf() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_InIf.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_InIfElse.kt")
|
||||
public void testNotApplicable_InIfElse() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_InIfElse.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_alreadyUsesImplicitIt.kt")
|
||||
public void testNotApplicable_alreadyUsesImplicitIt() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_alreadyUsesImplicitIt.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_hasDestructuringDeclaration.kt")
|
||||
public void testNotApplicable_hasDestructuringDeclaration() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_hasDestructuringDeclaration.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_hasMultipleParameters.kt")
|
||||
public void testNotApplicable_hasMultipleParameters() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_hasMultipleParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_inWhenEntry.kt")
|
||||
public void testNotApplicable_inWhenEntry() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_inWhenEntry.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_itFromOuterLambda.kt")
|
||||
public void testNotApplicable_itFromOuterLambda() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_itFromOuterLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_nestedLiterals.kt")
|
||||
public void testNotApplicable_nestedLiterals() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_nestedLiterals.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_nestedLiteralsNoIt.kt")
|
||||
public void testNotApplicable_nestedLiteralsNoIt() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_nestedLiteralsNoIt.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_notFunctionLiteralParameter.kt")
|
||||
public void testNotApplicable_notFunctionLiteralParameter() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_notFunctionLiteralParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_overloadResolutionAmbiguity.kt")
|
||||
public void testNotApplicable_overloadResolutionAmbiguity() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_overloadResolutionAmbiguity.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_overloadResolutionAmbiguity2.kt")
|
||||
public void testNotApplicable_overloadResolutionAmbiguity2() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_overloadResolutionAmbiguity2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_parameterHasExplicitType.kt")
|
||||
public void testNotApplicable_parameterHasExplicitType() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_parameterHasExplicitType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_wrongPosition.kt")
|
||||
public void testNotApplicable_wrongPosition() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_wrongPosition.kt");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+10
@@ -17200,6 +17200,16 @@ public abstract class K1IntentionTestGenerated extends AbstractK1IntentionTest {
|
||||
runTest("testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_nestedLiteralsNoUseInside.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_overloadResolutionUnambiguity.kt")
|
||||
public void testApplicable_overloadResolutionUnambiguity() throws Exception {
|
||||
runTest("testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_overloadResolutionUnambiguity.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_overloadResolutionUnambiguity2.kt")
|
||||
public void testApplicable_overloadResolutionUnambiguity2() throws Exception {
|
||||
runTest("testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_overloadResolutionUnambiguity2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_qualifiedExpression.kt")
|
||||
public void testApplicable_qualifiedExpression() throws Exception {
|
||||
runTest("testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_qualifiedExpression.kt");
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.k2.codeinsight.intentions.ReplaceExplicitFunctionLiteralParamWithItIntention
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
fun test() {
|
||||
foo { <caret>i -> i + 1 }
|
||||
}
|
||||
|
||||
fun foo(f: (Int) -> Int) {}
|
||||
fun foo(f: (Int, Int) -> Int) {}
|
||||
|
||||
// IGNORE_K1
|
||||
// the intention is inapplicable for K1, see the paired testNotApplicable_overloadResolutionAmbiguity
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
fun test() {
|
||||
foo { it + 1 }
|
||||
}
|
||||
|
||||
fun foo(f: (Int) -> Int) {}
|
||||
fun foo(f: (Int, Int) -> Int) {}
|
||||
|
||||
// IGNORE_K1
|
||||
// the intention is inapplicable for K1, see the paired testNotApplicable_overloadResolutionAmbiguity
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fun test() {
|
||||
C().foo { <caret>i -> i + 1 }
|
||||
}
|
||||
|
||||
class C {
|
||||
fun foo(f: (Int) -> Int) {}
|
||||
fun foo(f: (Int, Int) -> Int) {}
|
||||
}
|
||||
|
||||
// IGNORE_K1
|
||||
// the intention is inapplicable for K1, see the paired testNotApplicable_overloadResolutionAmbiguity2
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fun test() {
|
||||
C().foo { it + 1 }
|
||||
}
|
||||
|
||||
class C {
|
||||
fun foo(f: (Int) -> Int) {}
|
||||
fun foo(f: (Int, Int) -> Int) {}
|
||||
}
|
||||
|
||||
// IGNORE_K1
|
||||
// the intention is inapplicable for K1, see the paired testNotApplicable_overloadResolutionAmbiguity2
|
||||
+4
-1
@@ -4,4 +4,7 @@ fun test() {
|
||||
}
|
||||
|
||||
fun foo(f: (Int) -> Int) {}
|
||||
fun foo(f: (Int, Int) -> Int) {}
|
||||
fun foo(f: (Int, Int) -> Int) {}
|
||||
|
||||
// IGNORE_K2
|
||||
// the intention is applicable for K2, see the paired applicable_overloadResolutionUnambiguity
|
||||
+4
-1
@@ -6,4 +6,7 @@ fun test() {
|
||||
class C {
|
||||
fun foo(f: (Int) -> Int) {}
|
||||
fun foo(f: (Int, Int) -> Int) {}
|
||||
}
|
||||
}
|
||||
|
||||
// IGNORE_K2
|
||||
// the intention is applicable for K2, see the paired applicable_overloadResolutionUnambiguity2
|
||||
+1
-1
@@ -79,7 +79,7 @@ internal fun MutableTWorkspace.generateK2IntentionTests() {
|
||||
model("${idea}intentions/replaceUntilWithRangeTo", pattern = pattern, isIgnored = true)
|
||||
model("${idea}intentions/convertLateinitPropertyToNullable", pattern = pattern, isIgnored = true)
|
||||
model("${idea}intentions/swapStringEqualsIgnoreCase", pattern = pattern, isIgnored = true)
|
||||
model("${idea}intentions/replaceExplicitFunctionLiteralParamWithIt", pattern = pattern, isIgnored = true)
|
||||
model("${idea}intentions/replaceExplicitFunctionLiteralParamWithIt", pattern = pattern)
|
||||
model("${idea}intentions/nullableBooleanEqualityCheckToElvis", pattern = pattern, isIgnored = true)
|
||||
model("${idea}intentions/convertOrdinaryPropertyToLazy", pattern = pattern, isIgnored = true)
|
||||
model("${idea}intentions/replaceWithOrdinaryAssignment", pattern = pattern, isIgnored = true)
|
||||
|
||||
Reference in New Issue
Block a user