FIR/Analysis API: Get parameter name from function type notation or

`@ParameterName` annotation, which is also now added during type
resolution.
This commit is contained in:
Mark Punzalan
2021-10-12 07:51:30 +00:00
committed by Dmitriy Novozhilov
parent afb68d15d6
commit 167dc81d3b
27 changed files with 282 additions and 86 deletions
@@ -67,12 +67,13 @@ public sealed class KtDeclaredFunctionCall : KtCall() {
* fun Int.invoke() {}
*/
public class KtVariableWithInvokeFunctionCall(
public val target: KtVariableLikeSymbol,
private val _target: KtVariableLikeSymbol,
private val _argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>,
private val _targetFunction: KtCallTarget,
private val _substitutor: KtSubstitutor,
override val token: ValidityToken
) : KtDeclaredFunctionCall() {
public val target: KtVariableLikeSymbol get() = withValidityAssertion { _target }
override val argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>
get() = withValidityAssertion { _argumentMapping }
override val targetFunction: KtCallTarget
@@ -138,4 +138,15 @@ public abstract class KtValueParameterSymbol : KtVariableLikeSymbol(), KtSymbolW
public abstract val isVararg: Boolean
abstract override fun createPointer(): KtSymbolPointer<KtValueParameterSymbol>
/**
* The name of the value parameter. For a parameter of `FunctionN.invoke()` functions, the name is taken from the function type
* notation, if a name is present. For example:
* ```
* fun foo(x: (item: Int, String) -> Unit) =
* x(1, "") // or `x.invoke(1, "")`
* ```
* The names of the value parameters for `invoke()` are "item" and "p2" (its default parameter name).
*/
abstract override val name: Name
}
@@ -0,0 +1,3 @@
fun call(x: (a: Int, b: String) -> Unit) {
<expr>x(1, "")</expr>
}
@@ -0,0 +1,5 @@
KtFunctionalTypeVariableCall:
target = x: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, @R|kotlin.ParameterName|(name = String(b)) kotlin.String, kotlin.Unit>
argumentMapping = { 1 -> (a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int), "" -> (b: @R|kotlin.ParameterName|(name = String(b)) kotlin.String) }
targetFunction = kotlin/Function2.invoke(<dispatch receiver>: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, @R|kotlin.ParameterName|(name = String(b)) kotlin.String, kotlin.Unit>, a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int, b: @R|kotlin.ParameterName|(name = String(b)) kotlin.String): kotlin.Unit
substitutor = <empty substitutor>
@@ -0,0 +1,3 @@
fun call(x: Function2<@ParameterName("a") Int, @ParameterName("b") String, Unit>) {
<expr>x(1, "")</expr>
}
@@ -0,0 +1,5 @@
KtFunctionalTypeVariableCall:
target = x: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, @R|kotlin.ParameterName|(name = String(b)) kotlin.String, kotlin.Unit>
argumentMapping = { 1 -> (a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int), "" -> (b: @R|kotlin.ParameterName|(name = String(b)) kotlin.String) }
targetFunction = kotlin/Function2.invoke(<dispatch receiver>: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, @R|kotlin.ParameterName|(name = String(b)) kotlin.String, kotlin.Unit>, a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int, b: @R|kotlin.ParameterName|(name = String(b)) kotlin.String): kotlin.Unit
substitutor = <empty substitutor>
@@ -0,0 +1,4 @@
// @ParameterName annotation takes precedence over name in function type parameter
fun call(x: (notMe: @ParameterName("a") Int, meNeither: @ParameterName("b") String) -> Unit) {
<expr>x(1, "")</expr>
}
@@ -0,0 +1,5 @@
KtFunctionalTypeVariableCall:
target = x: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, @R|kotlin.ParameterName|(name = String(b)) kotlin.String, kotlin.Unit>
argumentMapping = { 1 -> (a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int), "" -> (b: @R|kotlin.ParameterName|(name = String(b)) kotlin.String) }
targetFunction = kotlin/Function2.invoke(<dispatch receiver>: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, @R|kotlin.ParameterName|(name = String(b)) kotlin.String, kotlin.Unit>, a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int, b: @R|kotlin.ParameterName|(name = String(b)) kotlin.String): kotlin.Unit
substitutor = <empty substitutor>
@@ -0,0 +1,6 @@
fun <T> T.foo(): (a: T) -> Unit = TODO()
fun call() {
val x = 123.foo()
<expr>x(1)</expr>
}
@@ -0,0 +1,5 @@
KtFunctionalTypeVariableCall:
target = val x: kotlin.Function1<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, kotlin.Unit>
argumentMapping = { 1 -> (a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int) }
targetFunction = kotlin/Function1.invoke(<dispatch receiver>: kotlin.Function1<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, kotlin.Unit>, a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int): kotlin.Unit
substitutor = <empty substitutor>
@@ -0,0 +1,4 @@
// @ParameterName annotation is ignored when not used in function type
fun call(a: @ParameterName("notMe") Int, b: @ParameterName("meNeither") String) {
<expr>call(1, "")</expr>
}
@@ -0,0 +1,4 @@
KtFunctionCall:
argumentMapping = { 1 -> (a: @R|kotlin.ParameterName|(name = String(notMe)) kotlin.Int), "" -> (b: @R|kotlin.ParameterName|(name = String(meNeither)) kotlin.String) }
targetFunction = /call(a: @R|kotlin.ParameterName|(name = String(notMe)) kotlin.Int, b: @R|kotlin.ParameterName|(name = String(meNeither)) kotlin.String): kotlin.Unit
substitutor = <empty substitutor>
@@ -0,0 +1,3 @@
fun call(x: (a: Int, String) -> Unit) {
<expr>x(1, "")</expr>
}
@@ -0,0 +1,5 @@
KtFunctionalTypeVariableCall:
target = x: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, kotlin.String, kotlin.Unit>
argumentMapping = { 1 -> (a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int), "" -> (p2: kotlin.String) }
targetFunction = kotlin/Function2.invoke(<dispatch receiver>: kotlin.Function2<@R|kotlin.ParameterName|(name = String(a)) kotlin.Int, kotlin.String, kotlin.Unit>, a: @R|kotlin.ParameterName|(name = String(a)) kotlin.Int, p2: kotlin.String): kotlin.Unit
substitutor = <empty substitutor>