From daebf569ab20eeda6e15d37ee2f9919e94aad7d3 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Mon, 13 Apr 2015 14:37:18 +0300 Subject: [PATCH] Extract Function: Allow capturing local function references as lambda parameters --- .../org/jetbrains/kotlin/psi/JetPsiFactory.kt | 4 ++ .../ExtractableCodeDescriptor.kt | 12 +++++- .../extractionEngine/ExtractionData.kt | 3 +- .../extractableAnalysisUtil.kt | 31 +++++++++++++-- .../outputValues/tooManyOutputValuesAsList.kt | 2 +- .../tooManyOutputValuesAsList.kt.after | 2 +- .../capturedFunctions/deeplyLocalFun.kt | 16 ++++++++ .../capturedFunctions/deeplyLocalFun.kt.after | 18 +++++++++ .../capturedFunctions/localExtensionFun.kt | 10 +++++ .../localExtensionFun.kt.after | 12 ++++++ .../localExtensionFunChainedCalls.kt | 13 +++++++ .../localExtensionFunChainedCalls.kt.after | 15 +++++++ .../localExtensionFunInfixCall.kt | 10 +++++ .../localExtensionFunInfixCall.kt.after | 12 ++++++ .../parameters/capturedFunctions/localFun.kt | 10 +++++ .../capturedFunctions/localFun.kt.after | 12 ++++++ .../introduce/JetExtractionTestGenerated.java | 39 +++++++++++++++++++ 17 files changed, 212 insertions(+), 9 deletions(-) create mode 100644 idea/testData/refactoring/extractFunction/parameters/capturedFunctions/deeplyLocalFun.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/capturedFunctions/deeplyLocalFun.kt.after create mode 100644 idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFun.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFun.kt.after create mode 100644 idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunChainedCalls.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunChainedCalls.kt.after create mode 100644 idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunInfixCall.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunInfixCall.kt.after create mode 100644 idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localFun.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localFun.kt.after diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt index 3ae27fba819..5c1d122ee04 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt @@ -195,6 +195,10 @@ public class JetPsiFactory(private val project: Project) { return createProperty(name, null, false, name).getInitializer() as JetSimpleNameExpression } + public fun createOperationName(name: String): JetSimpleNameExpression { + return (createExpression("0 $name 0") as JetBinaryExpression).getOperationReference() + } + public fun createObjectDeclarationName(name: String): JetObjectDeclarationName { return createDeclaration("object $name").getNameAsDeclaration()!! } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt index 48fd770cce5..5e1e9d12e63 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt @@ -74,8 +74,16 @@ class RenameReplacement(override val parameter: Parameter): ParameterReplacement [suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")] override fun invoke(e: JetElement): JetElement { - val thisExpr = e.getParent() as? JetThisExpression - return (thisExpr ?: e).replaced(JetPsiFactory(e).createSimpleName(parameter.nameForRef)) + val expressionToReplace = e.getParent() as? JetThisExpression ?: e + val psiFactory = JetPsiFactory(e) + val replacement = + if (expressionToReplace is JetOperationReferenceExpression) { + psiFactory.createOperationName(parameter.nameForRef) + } + else { + psiFactory.createSimpleName(parameter.nameForRef) + } + return expressionToReplace.replaced(replacement) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionData.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionData.kt index e7cf7178198..bbacba30557 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionData.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionData.kt @@ -47,7 +47,8 @@ data class ExtractionOptions( val inferUnitTypeForUnusedValues: Boolean = true, val enableListBoxing: Boolean = false, val extractAsProperty: Boolean = false, - val allowSpecialClassNames: Boolean = false + val allowSpecialClassNames: Boolean = false, + val captureLocalFunctions: Boolean = false ) { companion object { val DEFAULT = ExtractionOptions() diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt index 2fdc8e1432e..d171c3a8a36 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverseFollowingInstructions import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully @@ -66,6 +67,7 @@ import org.jetbrains.kotlin.psi.psiUtil.isInsideOf import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement import org.jetbrains.kotlin.resolve.calls.CallTransformer import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny @@ -83,8 +85,8 @@ import org.jetbrains.kotlin.utils.DFS.VisitedWithSet import java.util.* import kotlin.properties.Delegates -private val DEFAULT_RETURN_TYPE = KotlinBuiltIns.getInstance().getUnitType() -private val DEFAULT_PARAMETER_TYPE = KotlinBuiltIns.getInstance().getNullableAnyType() +private val DEFAULT_RETURN_TYPE = KotlinBuiltIns.getInstance().getUnitType()!! +private val DEFAULT_PARAMETER_TYPE = KotlinBuiltIns.getInstance().getNullableAnyType()!! private fun DeclarationDescriptor.renderForMessage(): String = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(this) @@ -640,9 +642,16 @@ private fun ExtractionData.inferParametersInfo( (originalDeclaration is JetProperty && originalDeclaration.isLocal()) || originalDeclaration is JetParameter + val extractFunctionRef = + options.captureLocalFunctions + && originalRef.getReferencedName() == originalDescriptor.getName().asString() // to forbid calls by convention + && originalDescriptor is FunctionDescriptor + && DescriptorUtils.isLocal(originalDescriptor) + && (targetScope == null || originalDescriptor !in targetScope.getFunctions(originalDescriptor.getName())) + val descriptorToExtract = (if (extractThis) thisDescriptor else null) ?: originalDescriptor - val extractParameter = extractThis || extractLocalVar + val extractParameter = extractThis || extractLocalVar || extractFunctionRef if (extractParameter) { val parameterExpression = when { receiverToExtract is ExpressionReceiver -> receiverToExtract.getExpression() @@ -651,6 +660,13 @@ private fun ExtractionData.inferParametersInfo( } val parameterType = when { + extractFunctionRef -> { + originalDescriptor as FunctionDescriptor + KotlinBuiltIns.getInstance().getFunctionType(Annotations.EMPTY, + originalDescriptor.getExtensionReceiverParameter()?.getType(), + originalDescriptor.getValueParameters().map { it.getType() }, + originalDescriptor.getReturnType() ?: DEFAULT_RETURN_TYPE) + } parameterExpression != null -> bindingContext[BindingContext.SMARTCAST, parameterExpression] ?: bindingContext[BindingContext.EXPRESSION_TYPE, parameterExpression] ?: if (receiverToExtract.exists()) receiverToExtract.getType() else null @@ -666,13 +682,17 @@ private fun ExtractionData.inferParametersInfo( } ?: DEFAULT_PARAMETER_TYPE val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) { - val argumentText = + var argumentText = if (hasThisReceiver && extractThis) { val label = if (descriptorToExtract is ClassDescriptor) "@${descriptorToExtract.getName().asString()}" else "" "this$label" } else (thisExpr ?: ref).getText() ?: throw AssertionError("'this' reference shouldn't be empty: code fragment = $codeFragmentText") + if (extractFunctionRef) { + val receiverTypeText = (originalDeclaration as JetCallableDeclaration).getReceiverTypeReference()?.getText() ?: "" + argumentText = "$receiverTypeText::$argumentText" + } MutableParameter(argumentText, descriptorToExtract, extractThis, targetScope) } @@ -694,6 +714,9 @@ private fun ExtractionData.inferParametersInfo( parameter.addTypePredicate(getExpectedTypePredicate(receiverValue, bindingContext)) } } + else if (extractFunctionRef) { + parameter.addTypePredicate(SingleType(parameterType)) + } else { pseudocode.getElementValuesRecursively(originalRef).forEach { parameter.addTypePredicate(getExpectedTypePredicate(it, bindingContext)) diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt index 74275140402..80e73a303cd 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt @@ -1,5 +1,5 @@ // WITH_RUNTIME -// OPTIONS: true, true, false, false +// OPTIONS: true, true, false, false, false // PARAM_TYPES: kotlin.Int // PARAM_TYPES: kotlin.Int // PARAM_TYPES: kotlin.Int diff --git a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt.after b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt.after index 87263058cd6..baa7b1393bb 100644 --- a/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt.after +++ b/idea/testData/refactoring/extractFunction/controlFlow/outputValues/tooManyOutputValuesAsList.kt.after @@ -1,5 +1,5 @@ // WITH_RUNTIME -// OPTIONS: true, true, false, false +// OPTIONS: true, true, false, false, false // PARAM_TYPES: kotlin.Int // PARAM_TYPES: kotlin.Int // PARAM_TYPES: kotlin.Int diff --git a/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/deeplyLocalFun.kt b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/deeplyLocalFun.kt new file mode 100644 index 00000000000..250b4915c2e --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/deeplyLocalFun.kt @@ -0,0 +1,16 @@ +// OPTIONS: true, false, false, false, true +// PARAM_DESCRIPTOR: local final fun baz(m: kotlin.Int): Int defined in foo.bar +// PARAM_DESCRIPTOR: value-parameter val n: kotlin.Int defined in foo +// PARAM_TYPES: (kotlin.Int) -> Int +// PARAM_TYPES: kotlin.Int + +// SIBLING: +fun foo(n: Int): Int { + fun bar(): Int { + fun baz(m: Int) = m * n + + return baz(n + 1) + } + + return bar() +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/deeplyLocalFun.kt.after b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/deeplyLocalFun.kt.after new file mode 100644 index 00000000000..8a1028fb3ed --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/deeplyLocalFun.kt.after @@ -0,0 +1,18 @@ +// OPTIONS: true, false, false, false, true +// PARAM_DESCRIPTOR: local final fun baz(m: kotlin.Int): Int defined in foo.bar +// PARAM_DESCRIPTOR: value-parameter val n: kotlin.Int defined in foo +// PARAM_TYPES: (kotlin.Int) -> Int +// PARAM_TYPES: kotlin.Int + +// SIBLING: +fun foo(n: Int): Int { + fun bar(): Int { + fun baz(m: Int) = m * n + + return i(::baz, n) + } + + return bar() +} + +private fun i(baz: (Int) -> Int, n: Int) = baz(n + 1) \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFun.kt b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFun.kt new file mode 100644 index 00000000000..14402a11fe3 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFun.kt @@ -0,0 +1,10 @@ +// OPTIONS: true, false, false, false, true +// PARAM_DESCRIPTOR: local final fun kotlin.Int.bar(m: kotlin.Int): Int defined in foo +// PARAM_DESCRIPTOR: value-parameter val n: kotlin.Int defined in foo +// PARAM_TYPES: kotlin.Int.(kotlin.Int) -> Int +// PARAM_TYPES: kotlin.Int +fun foo(n: Int): Int { + fun Int.bar(m: Int) = this * m * n + + return n.bar(n + 1) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFun.kt.after b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFun.kt.after new file mode 100644 index 00000000000..e047db07fd5 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFun.kt.after @@ -0,0 +1,12 @@ +// OPTIONS: true, false, false, false, true +// PARAM_DESCRIPTOR: local final fun kotlin.Int.bar(m: kotlin.Int): Int defined in foo +// PARAM_DESCRIPTOR: value-parameter val n: kotlin.Int defined in foo +// PARAM_TYPES: kotlin.Int.(kotlin.Int) -> Int +// PARAM_TYPES: kotlin.Int +fun foo(n: Int): Int { + fun Int.bar(m: Int) = this * m * n + + return i(Int::bar, n) +} + +private fun i(bar: Int.(Int) -> Int, n: Int) = n.bar(n + 1) \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunChainedCalls.kt b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunChainedCalls.kt new file mode 100644 index 00000000000..7a38bf52e81 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunChainedCalls.kt @@ -0,0 +1,13 @@ +// OPTIONS: true, false, false, false, true +// PARAM_DESCRIPTOR: local final fun kotlin.Int.bar1(m: kotlin.Int): Int defined in foo +// PARAM_DESCRIPTOR: local final fun kotlin.Int.bar2(m: kotlin.Int): Int defined in foo +// PARAM_DESCRIPTOR: value-parameter val n: kotlin.Int defined in foo +// PARAM_TYPES: kotlin.Int.(kotlin.Int) -> Int +// PARAM_TYPES: kotlin.Int.(kotlin.Int) -> Int +// PARAM_TYPES: kotlin.Int +fun foo(n: Int): Int { + fun Int.bar1(m: Int) = this + m + n + fun Int.bar2(m: Int) = this * m * n + + return n.bar1(n + 1).bar2(n + 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunChainedCalls.kt.after b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunChainedCalls.kt.after new file mode 100644 index 00000000000..bde4d07e4dd --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunChainedCalls.kt.after @@ -0,0 +1,15 @@ +// OPTIONS: true, false, false, false, true +// PARAM_DESCRIPTOR: local final fun kotlin.Int.bar1(m: kotlin.Int): Int defined in foo +// PARAM_DESCRIPTOR: local final fun kotlin.Int.bar2(m: kotlin.Int): Int defined in foo +// PARAM_DESCRIPTOR: value-parameter val n: kotlin.Int defined in foo +// PARAM_TYPES: kotlin.Int.(kotlin.Int) -> Int +// PARAM_TYPES: kotlin.Int.(kotlin.Int) -> Int +// PARAM_TYPES: kotlin.Int +fun foo(n: Int): Int { + fun Int.bar1(m: Int) = this + m + n + fun Int.bar2(m: Int) = this * m * n + + return i(Int::bar1, Int::bar2, n) +} + +private fun i(bar1: Int.(Int) -> Int, bar2: Int.(Int) -> Int, n: Int) = n.bar1(n + 1).bar2(n + 2) \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunInfixCall.kt b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunInfixCall.kt new file mode 100644 index 00000000000..6bd3a175cf6 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunInfixCall.kt @@ -0,0 +1,10 @@ +// OPTIONS: true, false, false, false, true +// PARAM_DESCRIPTOR: local final fun kotlin.Int.bar(m: kotlin.Int): Int defined in foo +// PARAM_DESCRIPTOR: value-parameter val n: kotlin.Int defined in foo +// PARAM_TYPES: kotlin.Int.(kotlin.Int) -> Int +// PARAM_TYPES: kotlin.Int +fun foo(n: Int): Int { + fun Int.bar(m: Int) = this * m * n + + return n bar (n + 1) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunInfixCall.kt.after b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunInfixCall.kt.after new file mode 100644 index 00000000000..e751064215d --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunInfixCall.kt.after @@ -0,0 +1,12 @@ +// OPTIONS: true, false, false, false, true +// PARAM_DESCRIPTOR: local final fun kotlin.Int.bar(m: kotlin.Int): Int defined in foo +// PARAM_DESCRIPTOR: value-parameter val n: kotlin.Int defined in foo +// PARAM_TYPES: kotlin.Int.(kotlin.Int) -> Int +// PARAM_TYPES: kotlin.Int +fun foo(n: Int): Int { + fun Int.bar(m: Int) = this * m * n + + return i(Int::bar, n) +} + +private fun i(bar: Int.(Int) -> Int, n: Int) = n bar (n + 1) \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localFun.kt b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localFun.kt new file mode 100644 index 00000000000..e3995dfa9dc --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localFun.kt @@ -0,0 +1,10 @@ +// OPTIONS: true, false, false, false, true +// PARAM_DESCRIPTOR: local final fun bar(m: kotlin.Int): Int defined in foo +// PARAM_DESCRIPTOR: value-parameter val n: kotlin.Int defined in foo +// PARAM_TYPES: (kotlin.Int) -> Int +// PARAM_TYPES: kotlin.Int +fun foo(n: Int): Int { + fun bar(m: Int) = m * n + + return bar(n + 1) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localFun.kt.after b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localFun.kt.after new file mode 100644 index 00000000000..e579ab5c006 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localFun.kt.after @@ -0,0 +1,12 @@ +// OPTIONS: true, false, false, false, true +// PARAM_DESCRIPTOR: local final fun bar(m: kotlin.Int): Int defined in foo +// PARAM_DESCRIPTOR: value-parameter val n: kotlin.Int defined in foo +// PARAM_TYPES: (kotlin.Int) -> Int +// PARAM_TYPES: kotlin.Int +fun foo(n: Int): Int { + fun bar(m: Int) = m * n + + return i(::bar, n) +} + +private fun i(bar: (Int) -> Int, n: Int) = bar(n + 1) \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java index d81ab796f5a..4925256fca4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java @@ -1584,6 +1584,45 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { } } + @TestMetadata("idea/testData/refactoring/extractFunction/parameters/capturedFunctions") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class CapturedFunctions extends AbstractJetExtractionTest { + public void testAllFilesPresentInCapturedFunctions() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/extractFunction/parameters/capturedFunctions"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("deeplyLocalFun.kt") + public void testDeeplyLocalFun() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/capturedFunctions/deeplyLocalFun.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("localExtensionFun.kt") + public void testLocalExtensionFun() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFun.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("localExtensionFunChainedCalls.kt") + public void testLocalExtensionFunChainedCalls() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunChainedCalls.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("localExtensionFunInfixCall.kt") + public void testLocalExtensionFunInfixCall() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localExtensionFunInfixCall.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("localFun.kt") + public void testLocalFun() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/capturedFunctions/localFun.kt"); + doExtractFunctionTest(fileName); + } + } + @TestMetadata("idea/testData/refactoring/extractFunction/parameters/extractSuper") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)