Add intention for replacing explicit function literal parameter with 'it'
Kotlin's function literals have a shortcut for one-argument literals:
the single argument doesn't need to be explicitly named, but can be
referred via the 'it' contextual keyword.
For example, 'array(1, 2, 3).filter { x -> x % 2 == 0 }'
-> 'array(1, 2, 3).filter { it % 2 == 0 }'
Add an intention action for this transformation.
This commit is contained in:
committed by
Nikolay Krasko
parent
1dd57b5f6e
commit
c6d6a32314
@@ -369,6 +369,7 @@ fun main(args: Array<String>) {
|
||||
model("intentions/insertCurlyBracestsToTemplate", testMethod = "doTestInsertCurlyToTemplate")
|
||||
model("intentions/moveLambdaInsideParentheses", testMethod = "doTestMoveLambdaInsideParentheses")
|
||||
model("intentions/moveLambdaOutsideParentheses", testMethod = "doTestMoveLambdaOutsideParentheses")
|
||||
model("intentions/replaceExplicitFunctionLiteralParamWithIt", testMethod = "doTestReplaceExplicitFunctionLiteralParamWithIt")
|
||||
}
|
||||
|
||||
testClass(javaClass<AbstractHierarchyTest>()) {
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
array(1, 2, 3).filter <spot>{ it % 2 == 0 }</spot>
|
||||
+1
@@ -0,0 +1 @@
|
||||
array(1, 2, 3).filter <spot>{ x -> x % 2 == 0 }</spot>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention replaces the explicit parameter of a single-parameter function literal with the implicit 'it' parameter.
|
||||
</body>
|
||||
</html>
|
||||
@@ -528,6 +528,11 @@
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.jet.plugin.intentions.ReplaceExplicitFunctionLiteralParamWithItIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<project.converterProvider implementation="org.jetbrains.jet.plugin.converters.JetRunConfigurationSettingsFormatConverterProvider"/>
|
||||
|
||||
</extensions>
|
||||
|
||||
@@ -233,6 +233,8 @@ replace.with.dot.qualified.method.call.intention=Replace with simple method call
|
||||
replace.with.dot.qualified.method.call.intention.family=Replace with simple method call
|
||||
replace.with.infix.function.call.intention=Replace with infix function call
|
||||
replace.with.infix.function.call.intention.family=Replace with infix function call
|
||||
replace.explicit.function.literal.param.with.it=Replace explicit parameter ''{0}'' with ''it''
|
||||
replace.explicit.function.literal.param.with.it.family=Replace Explicit Parameter With 'it'
|
||||
move.lambda.inside.parentheses=Move lambda function into parentheses
|
||||
move.lambda.inside.parentheses.family=Move lambda function into parentheses
|
||||
move.lambda.outside.parentheses=Move lambda expression out of parentheses
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.jet.plugin.intentions
|
||||
|
||||
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.refactoring.rename.RenameProcessor
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import org.jetbrains.jet.lang.psi.*
|
||||
import org.jetbrains.jet.plugin.JetBundle
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
||||
import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils
|
||||
import org.jetbrains.jet.plugin.references.JetReference
|
||||
import org.jetbrains.jet.plugin.codeInsight.firstOrNull
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor
|
||||
|
||||
public class ReplaceExplicitFunctionLiteralParamWithItIntention() : PsiElementBaseIntentionAction() {
|
||||
override fun invoke(project: Project, editor: Editor, element: PsiElement) {
|
||||
val funcExpr = findFunctionLiteralToActOn(element)!!
|
||||
val cursorWasOverParameterList = PsiTreeUtil.getParentOfType(element, javaClass<JetParameter>()) != null
|
||||
ParamRenamingProcessor(editor, funcExpr, cursorWasOverParameterList).run()
|
||||
}
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor, element: PsiElement): Boolean {
|
||||
val funcExpr = findFunctionLiteralToActOn(element)
|
||||
if (funcExpr == null || funcExpr.getValueParameters().size() != 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
val parameter = funcExpr.getValueParameters().first()
|
||||
if (parameter.getTypeReference() != null) {
|
||||
return false
|
||||
}
|
||||
|
||||
setText(JetBundle.message("replace.explicit.function.literal.param.with.it", parameter.getName()))
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getFamilyName(): String {
|
||||
return JetBundle.message("replace.explicit.function.literal.param.with.it.family")
|
||||
}
|
||||
|
||||
private fun findFunctionLiteralToActOn(element: PsiElement): JetFunctionLiteral? {
|
||||
if (PsiTreeUtil.getParentOfType(element, javaClass<JetFunctionLiteralExpression>()) == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val expression = PsiTreeUtil.getParentOfType(element, javaClass<JetSimpleNameExpression>(), javaClass<JetParameter>())
|
||||
if (expression == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
when (expression) {
|
||||
is JetParameter -> {
|
||||
return PsiTreeUtil.skipParentsOfType(expression, javaClass<JetParameterList>()) as? JetFunctionLiteral
|
||||
}
|
||||
is JetSimpleNameExpression -> {
|
||||
val reference = expression.getReference() as JetReference?
|
||||
val variableDescriptor = reference?.resolveToDescriptors()?.firstOrNull() as? VariableDescriptor?
|
||||
if (variableDescriptor != null) {
|
||||
val containingDescriptor = variableDescriptor.getContainingDeclaration()
|
||||
if (containingDescriptor is AnonymousFunctionDescriptor) {
|
||||
val context = AnalyzerFacadeWithCache.getContextForElement(expression)
|
||||
return BindingContextUtils.descriptorToDeclaration(context, containingDescriptor) as? JetFunctionLiteral
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
|
||||
private class ParamRenamingProcessor(
|
||||
val editor: Editor,
|
||||
val funcLiteral: JetFunctionLiteral,
|
||||
val cursorWasOverParameterList: Boolean) : RenameProcessor(editor.getProject(),
|
||||
funcLiteral.getValueParameters().first(),
|
||||
"it",
|
||||
false,
|
||||
false
|
||||
) {
|
||||
public override fun performRefactoring(usages: Array<out UsageInfo>?) {
|
||||
super.performRefactoring(usages)
|
||||
funcLiteral.deleteChildRange(funcLiteral.getValueParameterList(), funcLiteral.getArrowNode()!!.getPsi())
|
||||
if (cursorWasOverParameterList) {
|
||||
editor.getCaretModel().moveToOffset(funcLiteral.getBodyExpression()!!.getTextOffset())
|
||||
}
|
||||
|
||||
CodeStyleManager.getInstance(editor.getProject()!!)!!.reformatText(funcLiteral.getContainingFile()!!,
|
||||
funcLiteral.getTextRange()!!.getStartOffset(),
|
||||
funcLiteral.getTextRange()!!.getEndOffset())
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
fun foo(a: (Int) -> Int): Int = a(1)
|
||||
val x = foo { p -> foo { y -> <caret>p } }
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
fun foo(a: (Int) -> Int): Int = a(1)
|
||||
val x = foo { foo { y -> <caret>it } }
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
fun applyTwice<A>(f: (A) -> A, x: A) = f(f(x))
|
||||
val x = applyTwice({ <caret>x -> 1 + x }, 40)
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
fun applyTwice<A>(f: (A) -> A, x: A) = f(f(x))
|
||||
val x = applyTwice({ <caret>1 + it }, 40)
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
fun applyTwice<A>(f: (A) -> A, x: A) = f(f(x))
|
||||
val x = applyTwice({ x -> <caret>x + 1 }, 40)
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
fun applyTwice<A>(f: (A) -> A, x: A) = f(f(x))
|
||||
val x = applyTwice({ <caret>it + 1 }, 40)
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
fun foo(i: (Int) -> Unit) {}
|
||||
fun test() {
|
||||
foo { <caret>x ->
|
||||
array(1, 2, 3).filter { x -> x % 2 == 0 }
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
fun foo(i: (Int) -> Unit) {}
|
||||
fun test() {
|
||||
foo {
|
||||
<caret>array(1, 2, 3).filter { x -> x % 2 == 0 }
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
fun applyTwice<A>(f: (A) -> A, x: A) = f(f(x))
|
||||
val x = applyTwice({ i<caret>t + 1 }, 40)
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
fun call2(f: (Int, Int) -> Int, x: Int, y: Int) = f(x, y)
|
||||
val foo = call2({ <caret>x, y -> x + y }, 40, 2)
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
val foo = { (x: Int) ->
|
||||
class Inner() {
|
||||
fun temp(<caret>y: Int) : Int { return x + y }
|
||||
}
|
||||
Inner()
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
// IS_APPLICABLE: false
|
||||
val incr = { (<caret>x: Int) -> x + 1}
|
||||
@@ -142,6 +142,10 @@ public abstract class AbstractCodeTransformationTest extends LightCodeInsightTes
|
||||
doTestIntention(path, new ReplaceWithInfixFunctionCallIntention());
|
||||
}
|
||||
|
||||
public void doTestReplaceExplicitFunctionLiteralParamWithIt(@NotNull String path) throws Exception {
|
||||
doTestIntention(path, new ReplaceExplicitFunctionLiteralParamWithItIntention());
|
||||
}
|
||||
|
||||
private void doTestIntention(@NotNull String path, @NotNull IntentionAction intentionAction) throws Exception {
|
||||
configureByFile(path);
|
||||
|
||||
|
||||
+50
-1
@@ -30,7 +30,7 @@ import org.jetbrains.jet.plugin.intentions.AbstractCodeTransformationTest;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@InnerTestClasses({CodeTransformationTestGenerated.IfToAssignment.class, CodeTransformationTestGenerated.IfToReturn.class, CodeTransformationTestGenerated.IfToReturnAsymmetrically.class, CodeTransformationTestGenerated.WhenToAssignment.class, CodeTransformationTestGenerated.WhenToReturn.class, CodeTransformationTestGenerated.AssignmentToIf.class, CodeTransformationTestGenerated.AssignmentToWhen.class, CodeTransformationTestGenerated.PropertyToIf.class, CodeTransformationTestGenerated.PropertyToWhen.class, CodeTransformationTestGenerated.ReturnToIf.class, CodeTransformationTestGenerated.ReturnToWhen.class, CodeTransformationTestGenerated.IfToWhen.class, CodeTransformationTestGenerated.WhenToIf.class, CodeTransformationTestGenerated.Flatten.class, CodeTransformationTestGenerated.Merge.class, CodeTransformationTestGenerated.IntroduceSubject.class, CodeTransformationTestGenerated.EliminateSubject.class, CodeTransformationTestGenerated.Split.class, CodeTransformationTestGenerated.Join.class, CodeTransformationTestGenerated.ConvertMemberToExtension.class, CodeTransformationTestGenerated.ReconstructedType.class, CodeTransformationTestGenerated.RemoveUnnecessaryParentheses.class, CodeTransformationTestGenerated.ReplaceWithDotQualifiedMethodCall.class, CodeTransformationTestGenerated.ReplaceWithInfixFunctionCall.class, CodeTransformationTestGenerated.RemoveCurlyBracesFromTemplate.class, CodeTransformationTestGenerated.MoveLambdaInsideParentheses.class, CodeTransformationTestGenerated.MoveLambdaOutsideParentheses.class})
|
||||
@InnerTestClasses({CodeTransformationTestGenerated.IfToAssignment.class, CodeTransformationTestGenerated.IfToReturn.class, CodeTransformationTestGenerated.IfToReturnAsymmetrically.class, CodeTransformationTestGenerated.WhenToAssignment.class, CodeTransformationTestGenerated.WhenToReturn.class, CodeTransformationTestGenerated.AssignmentToIf.class, CodeTransformationTestGenerated.AssignmentToWhen.class, CodeTransformationTestGenerated.PropertyToIf.class, CodeTransformationTestGenerated.PropertyToWhen.class, CodeTransformationTestGenerated.ReturnToIf.class, CodeTransformationTestGenerated.ReturnToWhen.class, CodeTransformationTestGenerated.IfToWhen.class, CodeTransformationTestGenerated.WhenToIf.class, CodeTransformationTestGenerated.Flatten.class, CodeTransformationTestGenerated.Merge.class, CodeTransformationTestGenerated.IntroduceSubject.class, CodeTransformationTestGenerated.EliminateSubject.class, CodeTransformationTestGenerated.Split.class, CodeTransformationTestGenerated.Join.class, CodeTransformationTestGenerated.ConvertMemberToExtension.class, CodeTransformationTestGenerated.ReconstructedType.class, CodeTransformationTestGenerated.RemoveUnnecessaryParentheses.class, CodeTransformationTestGenerated.ReplaceWithDotQualifiedMethodCall.class, CodeTransformationTestGenerated.ReplaceWithInfixFunctionCall.class, CodeTransformationTestGenerated.RemoveCurlyBracesFromTemplate.class, CodeTransformationTestGenerated.MoveLambdaInsideParentheses.class, CodeTransformationTestGenerated.MoveLambdaOutsideParentheses.class, CodeTransformationTestGenerated.ReplaceExplicitFunctionLiteralParamWithIt.class})
|
||||
public class CodeTransformationTestGenerated extends AbstractCodeTransformationTest {
|
||||
@TestMetadata("idea/testData/intentions/branched/folding/ifToAssignment")
|
||||
public static class IfToAssignment extends AbstractCodeTransformationTest {
|
||||
@@ -1478,6 +1478,54 @@ public class CodeTransformationTestGenerated extends AbstractCodeTransformationT
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt")
|
||||
public static class ReplaceExplicitFunctionLiteralParamWithIt extends AbstractCodeTransformationTest {
|
||||
public void testAllFilesPresentInReplaceExplicitFunctionLiteralParamWithIt() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_cursofOverParamInInnerLiteral.kt")
|
||||
public void testApplicable_cursofOverParamInInnerLiteral() throws Exception {
|
||||
doTestReplaceExplicitFunctionLiteralParamWithIt("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_cursofOverParamInInnerLiteral.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_cursorOverParameterDeclaration.kt")
|
||||
public void testApplicable_cursorOverParameterDeclaration() throws Exception {
|
||||
doTestReplaceExplicitFunctionLiteralParamWithIt("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_cursorOverParameterDeclaration.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_cursorOverParameterUse.kt")
|
||||
public void testApplicable_cursorOverParameterUse() throws Exception {
|
||||
doTestReplaceExplicitFunctionLiteralParamWithIt("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_cursorOverParameterUse.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("applicable_formatsProperly.kt")
|
||||
public void testApplicable_formatsProperly() throws Exception {
|
||||
doTestReplaceExplicitFunctionLiteralParamWithIt("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/applicable_formatsProperly.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_alreadyUsesImplicitIt.kt")
|
||||
public void testNotApplicable_alreadyUsesImplicitIt() throws Exception {
|
||||
doTestReplaceExplicitFunctionLiteralParamWithIt("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_alreadyUsesImplicitIt.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_hasMultipleParameters.kt")
|
||||
public void testNotApplicable_hasMultipleParameters() throws Exception {
|
||||
doTestReplaceExplicitFunctionLiteralParamWithIt("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_hasMultipleParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_notFunctionLiteralParameter.kt")
|
||||
public void testNotApplicable_notFunctionLiteralParameter() throws Exception {
|
||||
doTestReplaceExplicitFunctionLiteralParamWithIt("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_notFunctionLiteralParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notApplicable_parameterHasExplicitType.kt")
|
||||
public void testNotApplicable_parameterHasExplicitType() throws Exception {
|
||||
doTestReplaceExplicitFunctionLiteralParamWithIt("idea/testData/intentions/replaceExplicitFunctionLiteralParamWithIt/notApplicable_parameterHasExplicitType.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite("CodeTransformationTestGenerated");
|
||||
suite.addTestSuite(IfToAssignment.class);
|
||||
@@ -1507,6 +1555,7 @@ public class CodeTransformationTestGenerated extends AbstractCodeTransformationT
|
||||
suite.addTestSuite(RemoveCurlyBracesFromTemplate.class);
|
||||
suite.addTestSuite(MoveLambdaInsideParentheses.class);
|
||||
suite.addTestSuite(MoveLambdaOutsideParentheses.class);
|
||||
suite.addTestSuite(ReplaceExplicitFunctionLiteralParamWithIt.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user