KT-50862 Add name property to KtSignature

See the KDoc of the property for the reasons why
it was created
This commit is contained in:
Roman Golyshev
2022-01-26 16:09:19 +03:00
committed by Space
parent e2c7290214
commit 564e408434
123 changed files with 585 additions and 128 deletions
@@ -734,10 +734,14 @@ internal class KtFirCallResolver(
private fun Iterable<MutableMap.MutableEntry<FirExpression, FirValueParameter>>?.createArgumentMapping(
signatureOfCallee: KtFunctionLikeSignature<*>
): LinkedHashMap<KtExpression, KtVariableLikeSignature<KtValueParameterSymbol>> {
val paramSignatureByName = signatureOfCallee.valueParameters.associateBy { it.symbol.name }
val paramSignatureByName = signatureOfCallee.valueParameters.associateBy {
// We intentionally use `symbol.name` instead of `name` here, since
// `FirValueParameter.name` is not affected by the `@ParameterName`
it.symbol.name
}
val ktArgumentMapping = LinkedHashMap<KtExpression, KtVariableLikeSignature<KtValueParameterSymbol>>()
this?.forEach { (firExpression, firValueParameter) ->
val parameterSymbol = paramSignatureByName[firValueParameter.symbol.name] ?: return@forEach
val parameterSymbol = paramSignatureByName[firValueParameter.name] ?: return@forEach
mapArgumentExpressionToParameter(firExpression, parameterSymbol, ktArgumentMapping)
}
return ktArgumentMapping
@@ -44,7 +44,7 @@ internal class KtFirValueParameterSymbol(
) : KtValueParameterSymbol(), KtFirSymbol<FirValueParameterSymbol> {
override val psi: PsiElement? by cached { firSymbol.findPsi() }
override val name: Name by cached { firSymbol.getNameByAnnotation(resolveState) }
override val name: Name get() = withValidityAssertion { firSymbol.name }
override val isVararg: Boolean get() = withValidityAssertion { firSymbol.isVararg }
@@ -72,36 +72,3 @@ internal class KtFirValueParameterSymbol(
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
private fun FirValueParameterSymbol.getNameByAnnotation(resolveState: FirModuleResolveState): Name {
val defaultName = fir.name
if (fir.psi != null) return defaultName
// The case where PSI is null is when calling `invoke()` on a variable with functional type, e.g. `x(1)` below:
//
// fun foo(x: (item: Int) -> Unit) { x(1) }
// fun bar(x: Function1<@ParameterName("item") Int, Unit>) { x(1) }
//
// The function being called is `invoke(p1: Int)` on `Function1<Int, Unit>` which is from the stdlib, and therefore no source
// PSI for the function or its parameters. In that case, we use the `@ParameterName` annotation on the parameter type if present
// and fall back to the parameter names from the `invoke()` function (`p1`, `p2`, etc.).
//
// Note: During type resolution, `@ParameterName` type annotations are added based on the names (which are optional) in the
// function type notation. Therefore the `x` parameter in both example functions above have the same type and type annotations.
val parameterNameAnnotation =
resolvedReturnType.attributes.customAnnotations
.getAnnotationsByClassId(StandardNames.FqNames.parameterNameClassId)
.singleOrNull()?.safeAs<FirAnnotation>() ?: return defaultName
// The parent KtDeclaration is where the variable with functional type and `@ParameterName` annotation is declared.
val parentKtDeclaration =
parameterNameAnnotation.psi?.getNonStrictParentOfType<KtDeclaration>() ?: return defaultName
val parentFirDeclaration = parentKtDeclaration.getOrBuildFirOfType<FirDeclaration>(resolveState)
// Resolve to ARGUMENTS_OF_ANNOTATIONS phase to get `name` argument from mapping.
parentFirDeclaration.ensureResolved(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS)
val nameArgument = parameterNameAnnotation.argumentMapping.mapping[StandardClassIds.Annotations.ParameterNames.parameterNameName]
val parameterNameFromAnnotation = nameArgument?.unwrapArgument()?.safeAs<FirConstExpression<*>>()?.value as? String
return parameterNameFromAnnotation?.let { Name.identifier(it) } ?: defaultName
}
@@ -736,6 +736,12 @@ public class FirResolveCallTestGenerated extends AbstractResolveCallTest {
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/variableAsFunctionWithParameterNameAnnotationConflict.kt");
}
@Test
@TestMetadata("variableAsFunctionWithParameterNameAnnotationConflict2.kt")
public void testVariableAsFunctionWithParameterNameAnnotationConflict2() throws Exception {
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/variableAsFunctionWithParameterNameAnnotationConflict2.kt");
}
@Test
@TestMetadata("variableAsFunctionWithParameterNameGeneric.kt")
public void testVariableAsFunctionWithParameterNameGeneric() throws Exception {