Intentions: Convert function type receiver to parameter

#KT-14246 Fixed
This commit is contained in:
Alexey Sedunov
2016-12-07 14:39:19 +03:00
parent d4ed2d2022
commit 215d8b1e1a
25 changed files with 623 additions and 17 deletions
+1
View File
@@ -338,6 +338,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
- [`KT-14044`](https://youtrack.jetbrains.com/issue/KT-14044) Fix exception on deleting unused declaration in IDEA 2016.3
- [`KT-14019`](https://youtrack.jetbrains.com/issue/KT-14019) Create from Usage: Support generation of abstract members for superclasses
- [`KT-14246`](https://youtrack.jetbrains.com/issue/KT-14246) Intentions: Convert function type parameter to receiver
- [`KT-14246`](https://youtrack.jetbrains.com/issue/KT-14246) Intentions: Convert function type receiver to parameter
##### New features
@@ -32,7 +32,7 @@ object EditCommaSeparatedListHelper {
fun <TItem: KtElement> addItemAfter(list: KtElement, allItems: List<TItem>, item: TItem, anchor: TItem?, prefix: KtToken = KtTokens.LPAR): TItem {
assert(anchor == null || anchor.parent == list)
if (allItems.isEmpty()) {
if (list.firstChild.node.elementType == prefix) {
if (list.firstChild?.node?.elementType == prefix) {
return list.addAfter(item, list.firstChild) as TItem
}
else {
@@ -112,6 +112,10 @@ class KtPsiFactory(private val project: Project) {
return (createType("A.() -> B").typeElement as KtFunctionType).receiver!!.apply { this.typeReference.replace(typeReference) }
}
fun createFunctionTypeParameter(typeReference: KtTypeReference): KtParameter {
return (createType("(A) -> B").typeElement as KtFunctionType).parameters.first().apply { this.typeReference!!.replace(typeReference) }
}
fun createTypeAlias(name: String, typeParameters: List<String>, typeElement: KtTypeElement): KtTypeAlias {
return createTypeAlias(name, typeParameters, "X").apply { getTypeReference()!!.replace(createType(typeElement)) }
}
@@ -475,4 +475,25 @@ fun isTypeConstructorReference(e: PsiElement): Boolean {
fun KtParameter.isPropertyParameter() = ownerFunction is KtPrimaryConstructor && hasValOrVar()
fun isDoubleColonReceiver(expression: KtExpression) = expression.getParentOfTypeAndBranch<KtDoubleColonExpression> { this.receiverExpression } != null
fun isDoubleColonReceiver(expression: KtExpression) = expression.getParentOfTypeAndBranch<KtDoubleColonExpression> { this.receiverExpression } != null
fun KtFunctionLiteral.getOrCreateParameterList(): KtParameterList {
valueParameterList?.let { return it }
val psiFactory = KtPsiFactory(this)
val anchor = lBrace
val newParameterList = addAfter(psiFactory.createLambdaParameterList("x"), anchor) as KtParameterList
newParameterList.removeParameter(0)
if (arrow == null) {
val whitespaceAndArrow = psiFactory.createWhitespaceAndArrow()
addRangeAfter(whitespaceAndArrow.first, whitespaceAndArrow.second, newParameterList)
}
return newParameterList
}
fun KtCallExpression.getOrCreateValueArgumentList(): KtValueArgumentList {
valueArgumentList?.let { return it }
return addAfter(KtPsiFactory(this).createCallArguments("()"),
typeArgumentList ?: calleeExpression) as KtValueArgumentList
}
@@ -0,0 +1,3 @@
fun foo(f: (i: <spot>Int</spot>, s: String) -> Boolean) = f(1, "2")
fun bar = foo { i, s -> s.length() > n }
@@ -0,0 +1,3 @@
fun foo(f: <spot>Int</spot>.(s: String) -> Boolean) = 1.f("2")
fun bar = foo { s -> s.length() > this }
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts receiver of a function type used in a function parameter to its first parameter
</body>
</html>
+5
View File
@@ -1461,6 +1461,11 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertFunctionTypeReceiverToParameterIntention</className>
<category>Kotlin</category>
</intentionAction>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
displayName="Object literal can be converted to lambda"
groupName="Kotlin"
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2016 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.kotlin.idea.intentions
import com.intellij.psi.PsiElement
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.psi.KtElement
abstract class AbstractProcessableUsageInfo<out T : PsiElement, in D: Any>(element: T) : UsageInfo(element) {
@Suppress("UNCHECKED_CAST")
override fun getElement() = super.getElement() as T?
abstract fun process(data: D, elementsToShorten: MutableList<KtElement>)
}
@@ -26,7 +26,6 @@ import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.util.RefactoringUIUtil
import com.intellij.usageView.UsageInfo
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.descriptors.CallableDescriptor
@@ -60,14 +59,7 @@ class ConvertFunctionTypeParameterToReceiverIntention : SelfTargetingRangeIntent
KtTypeReference::class.java,
"Convert function type parameter to receiver"
) {
abstract class AbstractUsageInfo<out T : PsiElement>(element: T) : UsageInfo(element) {
@Suppress("UNCHECKED_CAST")
override fun getElement() = super.getElement() as T?
abstract fun process(data: ConversionData, elementsToShorten: MutableList<KtElement>)
}
class FunctionDefinitionInfo(element: KtFunction) : AbstractUsageInfo<KtFunction>(element) {
class FunctionDefinitionInfo(element: KtFunction) : AbstractProcessableUsageInfo<KtFunction, ConversionData>(element) {
override fun process(data: ConversionData, elementsToShorten: MutableList<KtElement>) {
val function = element ?: return
val functionParameter = function.valueParameters.getOrNull(data.functionParameterIndex) ?: return
@@ -80,7 +72,7 @@ class ConvertFunctionTypeParameterToReceiverIntention : SelfTargetingRangeIntent
}
}
class ParameterCallInfo(element: KtCallExpression) : AbstractUsageInfo<KtCallExpression>(element) {
class ParameterCallInfo(element: KtCallExpression) : AbstractProcessableUsageInfo<KtCallExpression, ConversionData>(element) {
override fun process(data: ConversionData, elementsToShorten: MutableList<KtElement>) {
val callExpression = element ?: return
val argumentList = callExpression.valueArgumentList ?: return
@@ -91,7 +83,7 @@ class ConvertFunctionTypeParameterToReceiverIntention : SelfTargetingRangeIntent
}
}
class InternalReferencePassInfo(element: KtSimpleNameExpression) : AbstractUsageInfo<KtSimpleNameExpression>(element) {
class InternalReferencePassInfo(element: KtSimpleNameExpression) : AbstractProcessableUsageInfo<KtSimpleNameExpression, ConversionData>(element) {
override fun process(data: ConversionData, elementsToShorten: MutableList<KtElement>) {
val expression = element ?: return
val lambdaType = data.lambdaType
@@ -111,7 +103,7 @@ class ConvertFunctionTypeParameterToReceiverIntention : SelfTargetingRangeIntent
}
}
class LambdaInfo(element: KtExpression) : AbstractUsageInfo<KtExpression>(element) {
class LambdaInfo(element: KtExpression) : AbstractProcessableUsageInfo<KtExpression, ConversionData>(element) {
override fun process(data: ConversionData, elementsToShorten: MutableList<KtElement>) {
val expression = element ?: return
val context = expression.analyze(BodyResolveMode.PARTIAL)
@@ -185,7 +177,7 @@ class ConvertFunctionTypeParameterToReceiverIntention : SelfTargetingRangeIntent
val conflicts = MultiMap<PsiElement, String>()
val usages = ArrayList<AbstractUsageInfo<*>>()
val usages = ArrayList<AbstractProcessableUsageInfo<*, ConversionData>>()
project.runSynchronouslyWithProgress("Looking for usages and conflicts...", true) {
runReadAction {
@@ -233,7 +225,11 @@ class ConvertFunctionTypeParameterToReceiverIntention : SelfTargetingRangeIntent
}
}
private fun processExternalUsage(conflicts: MultiMap<PsiElement, String>, refElement: PsiElement, usages: java.util.ArrayList<AbstractUsageInfo<*>>) {
private fun processExternalUsage(
conflicts: MultiMap<PsiElement, String>,
refElement: PsiElement,
usages: ArrayList<AbstractProcessableUsageInfo<*, ConversionData>>
) {
val callElement = refElement.getParentOfTypeAndBranch<KtCallElement> { calleeExpression }
if (callElement != null) {
val context = callElement.analyze(BodyResolveMode.PARTIAL)
@@ -294,7 +290,7 @@ class ConvertFunctionTypeParameterToReceiverIntention : SelfTargetingRangeIntent
return true
}
private fun processInternalUsages(callable: KtFunction, usages: ArrayList<AbstractUsageInfo<*>>) {
private fun processInternalUsages(callable: KtFunction, usages: ArrayList<AbstractProcessableUsageInfo<*, ConversionData>>) {
val body = when (callable) {
is KtConstructor<*> -> callable.containingClassOrObject?.getBody()
else -> callable.bodyExpression
@@ -0,0 +1,224 @@
/*
* Copyright 2010-2016 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.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.util.RefactoringUIUtil
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.idea.refactoring.CallableRefactoring
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
import org.jetbrains.kotlin.idea.refactoring.getAffectedCallables
import org.jetbrains.kotlin.idea.references.KtSimpleReference
import org.jetbrains.kotlin.idea.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.psi.typeRefHelpers.setReceiverTypeReference
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getAbbreviatedTypeOrType
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getArgumentByParameterIndex
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType
class ConvertFunctionTypeReceiverToParameterIntention : SelfTargetingRangeIntention<KtTypeReference>(
KtTypeReference::class.java,
"Convert function type receiver to parameter"
) {
class ConversionData(
val functionParameterIndex: Int,
val lambdaReceiverType: KotlinType,
val function: KtFunction
) {
val functionDescriptor by lazy { function.resolveToDescriptor() as FunctionDescriptor }
}
class FunctionDefinitionInfo(element: KtFunction) : AbstractProcessableUsageInfo<KtFunction, ConversionData>(element) {
override fun process(data: ConversionData, elementsToShorten: MutableList<KtElement>) {
val function = element as? KtFunction ?: return
val functionParameter = function.valueParameters.getOrNull(data.functionParameterIndex) ?: return
val functionType = functionParameter.typeReference?.typeElement as? KtFunctionType ?: return
val functionTypeParameterList = functionType.parameterList ?: return
val functionTypeReceiver = functionType.receiverTypeReference ?: return
val parameterToAdd = KtPsiFactory(project).createFunctionTypeParameter(functionTypeReceiver)
functionTypeParameterList.addParameterBefore(parameterToAdd, functionTypeParameterList.parameters.firstOrNull())
functionType.setReceiverTypeReference(null)
}
}
class ParameterCallInfo(element: KtCallExpression) : AbstractProcessableUsageInfo<KtCallExpression, ConversionData>(element) {
override fun process(data: ConversionData, elementsToShorten: MutableList<KtElement>) {
val callExpression = element ?: return
val qualifiedExpression = callExpression.getQualifiedExpressionForSelector() ?: return
val receiverExpression = qualifiedExpression.receiverExpression
val argumentList = callExpression.getOrCreateValueArgumentList()
argumentList.addArgumentBefore(KtPsiFactory(project).createArgument(receiverExpression), argumentList.arguments.firstOrNull())
qualifiedExpression.replace(callExpression)
}
}
class LambdaInfo(element: KtLambdaExpression) : AbstractProcessableUsageInfo<KtLambdaExpression, ConversionData>(element) {
override fun process(data: ConversionData, elementsToShorten: MutableList<KtElement>) {
val lambda = element?.functionLiteral ?: return
val context = lambda.analyze(BodyResolveMode.PARTIAL)
val psiFactory = KtPsiFactory(project)
val validator = CollectingNameValidator(
lambda.valueParameters.mapNotNull { it.name },
NewDeclarationNameValidator(lambda.bodyExpression!!, null, NewDeclarationNameValidator.Target.VARIABLES)
)
val newParameterName = KotlinNameSuggester.suggestNamesByType(data.lambdaReceiverType, validator, "p").first()
val newParameterRefExpression = psiFactory.createExpression(newParameterName)
lambda.forEachDescendantOfType<KtThisExpression> {
val thisTarget = context[BindingContext.REFERENCE_TARGET, it.instanceReference] ?: return@forEachDescendantOfType
if (DescriptorToSourceUtilsIde.getAnyDeclaration(project, thisTarget) == lambda) {
it.replace(newParameterRefExpression)
}
}
val lambdaParameterList = lambda.getOrCreateParameterList()
val parameterToAdd = psiFactory.createLambdaParameterList(newParameterName).parameters.first()
lambdaParameterList.addParameterBefore(parameterToAdd, lambdaParameterList.parameters.firstOrNull())
}
}
private inner class Converter(
private val data: ConversionData
) : CallableRefactoring<CallableDescriptor>(data.function.project, data.functionDescriptor, text) {
override fun performRefactoring(descriptorsForChange: Collection<CallableDescriptor>) {
val callables = getAffectedCallables(project, descriptorsForChange)
val conflicts = MultiMap<PsiElement, String>()
val usages = ArrayList<AbstractProcessableUsageInfo<*, ConversionData>>()
project.runSynchronouslyWithProgress("Looking for usages and conflicts...", true) {
runReadAction {
val progressStep = 1.0/callables.size
for ((i, callable) in callables.withIndex()) {
ProgressManager.getInstance().progressIndicator.fraction = (i + 1) * progressStep
if (callable !is KtFunction) continue
if (!checkModifiable(callable)) {
val renderedCallable = RefactoringUIUtil.getDescription(callable, true).capitalize()
conflicts.putValue(callable, "Can't modify $renderedCallable")
}
val references = callable.toLightMethods().flatMapTo(LinkedHashSet()) { MethodReferencesSearch.search(it) }
for (ref in references) {
if (ref !is KtSimpleReference<*>) continue
processExternalUsage(ref, usages)
}
usages += FunctionDefinitionInfo(callable)
processInternalUsages(callable, usages)
}
}
}
project.checkConflictsInteractively(conflicts) {
project.executeWriteCommand(text) {
val elementsToShorten = ArrayList<KtElement>()
usages.forEach { it.process(data, elementsToShorten) }
ShortenReferences.DEFAULT.process(elementsToShorten)
}
}
}
private fun processExternalUsage(ref: KtSimpleReference<*>, usages: java.util.ArrayList<AbstractProcessableUsageInfo<*, ConversionData>>) {
val callElement = ref.element.getParentOfTypeAndBranch<KtCallElement> { calleeExpression } ?: return
val context = callElement.analyze(BodyResolveMode.PARTIAL)
val expressionToProcess = callElement
.getArgumentByParameterIndex(data.functionParameterIndex, context)
.singleOrNull()
?.getArgumentExpression()
?.let { KtPsiUtil.safeDeparenthesize(it) }
?: return
if (expressionToProcess is KtLambdaExpression) {
usages += LambdaInfo(expressionToProcess)
}
}
private fun processInternalUsages(callable: KtFunction, usages: java.util.ArrayList<AbstractProcessableUsageInfo<*, ConversionData>>) {
val body = when (callable) {
is KtConstructor<*> -> callable.containingClassOrObject?.getBody()
else -> callable.bodyExpression
}
if (body != null) {
val functionParameter = callable.valueParameters.getOrNull(data.functionParameterIndex) ?: return
for (ref in ReferencesSearch.search(functionParameter, LocalSearchScope(body))) {
val element = ref.element as? KtSimpleNameExpression ?: continue
val callExpression = element.getParentOfTypeAndBranch<KtCallExpression> { calleeExpression } ?: continue
usages += ParameterCallInfo(callExpression)
}
}
}
}
private fun KtTypeReference.getConversionData(): ConversionData? {
val functionTypeReceiver = parent as? KtFunctionTypeReceiver ?: return null
val functionType = functionTypeReceiver.parent as? KtFunctionType ?: return null
val lambdaReceiverType = functionType
.getAbbreviatedTypeOrType(functionType.analyze(BodyResolveMode.PARTIAL))
?.getReceiverTypeFromFunctionType()
?: return null
val containingParameter = (functionType.parent as? KtTypeReference)?.parent as? KtParameter ?: return null
val ownerFunction = containingParameter.ownerFunction ?: return null
val functionParameterIndex = ownerFunction.valueParameters.indexOf(containingParameter)
return ConversionData(functionParameterIndex, lambdaReceiverType, ownerFunction)
}
override fun startInWriteAction(): Boolean = false
override fun applicabilityRange(element: KtTypeReference): TextRange? {
val data = element.getConversionData() ?: return null
val elementBefore = data.function.valueParameters[data.functionParameterIndex].typeReference!!.typeElement as KtFunctionType
val elementAfter = elementBefore.copied().apply {
parameterList!!.addParameterBefore(
KtPsiFactory(element).createFunctionTypeParameter(element),
parameterList!!.parameters.firstOrNull()
)
setReceiverTypeReference(null)
}
text = "Convert '${elementBefore.text}' to '${elementAfter.text}'"
return element.textRange
}
override fun applyTo(element: KtTypeReference, editor: Editor?) {
element.getConversionData()?.let { Converter(it).run() }
}
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.intentions.ConvertFunctionTypeReceiverToParameterIntention
@@ -0,0 +1,22 @@
fun foo(f: <caret>Int.(Boolean) -> String) {
1.f(false)
bar(f)
}
fun bar(f: (Int, Boolean) -> String) {
}
fun lambda(): (Int, Boolean) -> String = { i, b -> "$i $b"}
fun baz(f: (Int, Boolean) -> String) {
fun g(i: Int, b: Boolean) = ""
foo(f)
foo(::g)
foo(lambda())
foo { b -> "${this + 1} $b" }
}
@@ -0,0 +1,22 @@
fun foo(f: <caret>(Int, Boolean) -> String) {
f(1, false)
bar(f)
}
fun bar(f: (Int, Boolean) -> String) {
}
fun lambda(): (Int, Boolean) -> String = { i, b -> "$i $b"}
fun baz(f: (Int, Boolean) -> String) {
fun g(i: Int, b: Boolean) = ""
foo(f)
foo(::g)
foo(lambda())
foo { i, b -> "${i + 1} $b" }
}
@@ -0,0 +1,2 @@
// IS_APPLICABLE: false
fun foo(f: Int.(Boolean) -> String): Int.(<caret>Boolean) -> String = f
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
fun foo(f: Int.(<caret>Boolean) -> String) {
}
@@ -0,0 +1,3 @@
fun foo(f: <caret>Int.(() -> Unit) -> String) {
1.f {}
}
@@ -0,0 +1,3 @@
fun foo(f: <caret>(Int, () -> Unit) -> String) {
f(1) {}
}
@@ -0,0 +1,22 @@
fun foo(f: <caret>Int.() -> String) {
1.f()
bar(f)
}
fun bar(f: (Int) -> String) {
}
fun lambda(): (Int) -> String = { i -> "$i"}
fun baz(f: (Int) -> String) {
fun g(i: Int) = ""
foo(f)
foo(::g)
foo(lambda())
foo { "${this + 1}" }
}
@@ -0,0 +1,22 @@
fun foo(f: <caret>(Int) -> String) {
f(1)
bar(f)
}
fun bar(f: (Int) -> String) {
}
fun lambda(): (Int) -> String = { i -> "$i"}
fun baz(f: (Int) -> String) {
fun g(i: Int) = ""
foo(f)
foo(::g)
foo(lambda())
foo { i -> "${i + 1}" }
}
@@ -0,0 +1,41 @@
open class Foo(f: <caret>Int.(Boolean) -> String) {
constructor(a: Int, f: (Int, Boolean) -> String) : this(f)
constructor(a: Int) : this(::g)
constructor(a: Int, b: Int) : this(lambda())
constructor(a: Int, b: Int, c: Int) : this({ b -> "${this + 1} $b" })
init {
1.f(false)
bar(f)
}
}
fun bar(f: (Int, Boolean) -> String) {
}
fun lambda(): (Int, Boolean) -> String = { i, b -> "$i $b"}
fun g(i: Int, b: Boolean) = ""
fun baz(f: (Int, Boolean) -> String) {
Foo(f)
Foo(::g)
Foo(lambda())
Foo { b -> "${this + 1} $b" }
}
class Baz1(f: (Int, Boolean) -> String) : Foo(f)
class Baz2 : Foo(::g)
class Baz3 : Foo(lambda())
class Baz4 : Foo({ b -> "${this + 1} $b" })
class Baz5 : Foo {
constructor(f: (Int, Boolean) -> String) : super(f)
constructor(a: Int) : super(::g)
constructor(a: Int, b: Int) : super(lambda())
constructor(a: Int, b: Int, c: Int) : super({ b -> "${this + 1} $b" })
}
@@ -0,0 +1,41 @@
open class Foo(f: <caret>(Int, Boolean) -> String) {
constructor(a: Int, f: (Int, Boolean) -> String) : this(f)
constructor(a: Int) : this(::g)
constructor(a: Int, b: Int) : this(lambda())
constructor(a: Int, b: Int, c: Int) : this({ i, b -> "${i + 1} $b" })
init {
f(1, false)
bar(f)
}
}
fun bar(f: (Int, Boolean) -> String) {
}
fun lambda(): (Int, Boolean) -> String = { i, b -> "$i $b"}
fun g(i: Int, b: Boolean) = ""
fun baz(f: (Int, Boolean) -> String) {
Foo(f)
Foo(::g)
Foo(lambda())
Foo { i, b -> "${i + 1} $b" }
}
class Baz1(f: (Int, Boolean) -> String) : Foo(f)
class Baz2 : Foo(::g)
class Baz3 : Foo(lambda())
class Baz4 : Foo({ i, b -> "${i + 1} $b" })
class Baz5 : Foo {
constructor(f: (Int, Boolean) -> String) : super(f)
constructor(a: Int) : super(::g)
constructor(a: Int, b: Int) : super(lambda())
constructor(a: Int, b: Int, c: Int) : super({ i, b -> "${i + 1} $b" })
}
@@ -0,0 +1,41 @@
open class Foo {
constructor(f: <caret>Int.(Boolean) -> String) {
1.f(false)
bar(f)
}
constructor(a: Int, f: (Int, Boolean) -> String) : this(f)
constructor(a: Int) : this(::g)
constructor(a: Int, b: Int) : this(lambda())
constructor(a: Int, b: Int, c: Int) : this({ b -> "${this + 1} $b" })
}
fun bar(f: (Int, Boolean) -> String) {
}
fun lambda(): (Int, Boolean) -> String = { i, b -> "$i $b"}
fun g(i: Int, b: Boolean) = ""
fun baz(f: (Int, Boolean) -> String) {
Foo(f)
Foo(::g)
Foo(lambda())
Foo { b -> "${this + 1} $b" }
}
class Baz1(f: (Int, Boolean) -> String) : Foo(f)
class Baz2 : Foo(::g)
class Baz3 : Foo(lambda())
class Baz4 : Foo({ b -> "${this + 1} $b" })
class Baz5 : Foo {
constructor(f: (Int, Boolean) -> String) : super(f)
constructor(a: Int) : super(::g)
constructor(a: Int, b: Int) : super(lambda())
constructor(a: Int, b: Int, c: Int) : super({ b -> "${this + 1} $b" })
}
@@ -0,0 +1,41 @@
open class Foo {
constructor(f: <caret>(Int, Boolean) -> String) {
f(1, false)
bar(f)
}
constructor(a: Int, f: (Int, Boolean) -> String) : this(f)
constructor(a: Int) : this(::g)
constructor(a: Int, b: Int) : this(lambda())
constructor(a: Int, b: Int, c: Int) : this({ i, b -> "${i + 1} $b" })
}
fun bar(f: (Int, Boolean) -> String) {
}
fun lambda(): (Int, Boolean) -> String = { i, b -> "$i $b"}
fun g(i: Int, b: Boolean) = ""
fun baz(f: (Int, Boolean) -> String) {
Foo(f)
Foo(::g)
Foo(lambda())
Foo { i, b -> "${i + 1} $b" }
}
class Baz1(f: (Int, Boolean) -> String) : Foo(f)
class Baz2 : Foo(::g)
class Baz3 : Foo(lambda())
class Baz4 : Foo({ i, b -> "${i + 1} $b" })
class Baz5 : Foo {
constructor(f: (Int, Boolean) -> String) : super(f)
constructor(a: Int) : super(::g)
constructor(a: Int, b: Int) : super(lambda())
constructor(a: Int, b: Int, c: Int) : super({ i, b -> "${i + 1} $b" })
}
@@ -4101,6 +4101,57 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
@TestMetadata("idea/testData/intentions/convertFunctionTypeReceiverToParameter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ConvertFunctionTypeReceiverToParameter extends AbstractIntentionTest {
public void testAllFilesPresentInConvertFunctionTypeReceiverToParameter() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertFunctionTypeReceiverToParameter"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("function.kt")
public void testFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionTypeReceiverToParameter/function.kt");
doTest(fileName);
}
@TestMetadata("notInFunctionParameter.kt")
public void testNotInFunctionParameter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionTypeReceiverToParameter/notInFunctionParameter.kt");
doTest(fileName);
}
@TestMetadata("notOnReceiver.kt")
public void testNotOnReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionTypeReceiverToParameter/notOnReceiver.kt");
doTest(fileName);
}
@TestMetadata("onlyLambdaArgument.kt")
public void testOnlyLambdaArgument() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionTypeReceiverToParameter/onlyLambdaArgument.kt");
doTest(fileName);
}
@TestMetadata("parameterlessFunction.kt")
public void testParameterlessFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionTypeReceiverToParameter/parameterlessFunction.kt");
doTest(fileName);
}
@TestMetadata("primaryConstructor.kt")
public void testPrimaryConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionTypeReceiverToParameter/primaryConstructor.kt");
doTest(fileName);
}
@TestMetadata("secondaryConstructor.kt")
public void testSecondaryConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertFunctionTypeReceiverToParameter/secondaryConstructor.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/intentions/convertIfWithThrowToAssert")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)