From 17617ffd3ffcc06d1596dae0c4b4797b4c90e7cc Mon Sep 17 00:00:00 2001 From: Tianyu Geng Date: Tue, 23 Feb 2021 14:42:07 -0800 Subject: [PATCH] IDE FIR: fix resolving vararg parameter type For a vararg parameter type, there corresponding FIR element has a fake source of kind ArrayTypeFromVarargParameter. As a result, `getOrBuildFir` returns the whole `FirValueParameter` for the parameter type reference. Therefore, we need some special handling for this case in order to resolve the proper `KtSymbol`. --- .../resolve/transformers/TransformUtils.kt | 34 +++++++++++++++---- .../fir/types/impl/FirUserTypeRefImpl.kt | 5 +-- .../FirReferenceResolveTestGenerated.java | 15 ++++++++ .../references/FirReferenceResolveHelper.kt | 12 ++++--- .../references/InMethodVarargParameter.kt | 9 +++++ .../InVaragReferenceInFunctionBody.kt | 9 +++++ .../InVaragReferenceInNamedParameter.kt | 10 ++++++ .../ReferenceResolveTestGenerated.java | 15 ++++++++ 8 files changed, 96 insertions(+), 13 deletions(-) create mode 100644 idea/testData/resolve/references/InMethodVarargParameter.kt create mode 100644 idea/testData/resolve/references/InVaragReferenceInFunctionBody.kt create mode 100644 idea/testData/resolve/references/InVaragReferenceInNamedParameter.kt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt index ce127ba5881..6abad5b3163 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/TransformUtils.kt @@ -9,10 +9,15 @@ import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.declarations.FirTypedDeclaration import org.jetbrains.kotlin.fir.declarations.FirValueParameter -import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.fakeElement import org.jetbrains.kotlin.fir.references.* import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.fir.visitors.* +import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef +import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult +import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer +import org.jetbrains.kotlin.fir.visitors.FirTransformer +import org.jetbrains.kotlin.fir.visitors.compose internal object StoreType : FirDefaultTransformer() { override fun transformElement(element: E, data: FirTypeRef): CompositeTransformResult { @@ -96,13 +101,30 @@ internal fun FirValueParameter.transformVarargTypeToArrayType() { } internal fun FirTypedDeclaration.transformTypeToArrayType() { + val returnTypeRef = this.returnTypeRef + require(returnTypeRef is FirResolvedTypeRef) + // If the delegated type is already resolved, it means we have already created a resolved array type for this vararg type declaration. + // This is because in the buildResolvedTypeRef call below, we set the delegated type ref to the previous (non-vararg) resolved type ref. + if (returnTypeRef.delegatedTypeRef is FirResolvedTypeRef && + returnTypeRef.delegatedTypeRef?.source?.kind == FirFakeSourceElementKind.ArrayTypeFromVarargParameter + ) return val returnType = returnTypeRef.coneType + transformReturnTypeRef( StoreType, - returnTypeRef.withReplacedConeType( - ConeKotlinTypeProjectionOut(returnType).createArrayType(), - FirFakeSourceElementKind.ArrayTypeFromVarargParameter - ) + buildResolvedTypeRef { + source = returnTypeRef.source + type = ConeKotlinTypeProjectionOut(returnType).createArrayType() + annotations += returnTypeRef.annotations + delegatedTypeRef = returnTypeRef.apply { + // Here we replace the source of the immediate delegate and nested delegate with a fake source. Normally the immediate + // delegate is the original resolved type ref before this array augmentation. That is, this is the array element type. + // The nested delegate is the raw type ref created when constructing the FIR. Usually it's a `FirUserTypeRef` for value + // parameters. + replaceSource(source?.fakeElement(FirFakeSourceElementKind.ArrayTypeFromVarargParameter)) + delegatedTypeRef?.replaceSource(source?.fakeElement(FirFakeSourceElementKind.ArrayTypeFromVarargParameter)) + } + } ) } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/impl/FirUserTypeRefImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/impl/FirUserTypeRefImpl.kt index 96c4dc39c80..219e553abcf 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/impl/FirUserTypeRefImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/impl/FirUserTypeRefImpl.kt @@ -16,7 +16,7 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitor import org.jetbrains.kotlin.fir.visitors.transformInplace class FirUserTypeRefImpl( - override val source: FirSourceElement?, + override var source: FirSourceElement?, override val isMarkedNullable: Boolean, override val qualifier: MutableList, override val annotations: MutableList @@ -43,5 +43,6 @@ class FirUserTypeRefImpl( } override fun replaceSource(newSource: FirSourceElement?) { + source = newSource } -} \ No newline at end of file +} diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/resolve/FirReferenceResolveTestGenerated.java b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/resolve/FirReferenceResolveTestGenerated.java index edd6cd6a635..eecb78db278 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/resolve/FirReferenceResolveTestGenerated.java +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/resolve/FirReferenceResolveTestGenerated.java @@ -219,6 +219,11 @@ public class FirReferenceResolveTestGenerated extends AbstractFirReferenceResolv runTest("idea/testData/resolve/references/InMethodParameter.kt"); } + @TestMetadata("InMethodVarargParameter.kt") + public void testInMethodVarargParameter() throws Exception { + runTest("idea/testData/resolve/references/InMethodVarargParameter.kt"); + } + @TestMetadata("InObjectClassObject.kt") public void testInObjectClassObject() throws Exception { runTest("idea/testData/resolve/references/InObjectClassObject.kt"); @@ -229,6 +234,16 @@ public class FirReferenceResolveTestGenerated extends AbstractFirReferenceResolv runTest("idea/testData/resolve/references/InSecondClassObject.kt"); } + @TestMetadata("InVaragReferenceInFunctionBody.kt") + public void testInVaragReferenceInFunctionBody() throws Exception { + runTest("idea/testData/resolve/references/InVaragReferenceInFunctionBody.kt"); + } + + @TestMetadata("InVaragReferenceInNamedParameter.kt") + public void testInVaragReferenceInNamedParameter() throws Exception { + runTest("idea/testData/resolve/references/InVaragReferenceInNamedParameter.kt"); + } + @TestMetadata("JavaAnnotationParameter.kt") public void testJavaAnnotationParameter() throws Exception { runTest("idea/testData/resolve/references/JavaAnnotationParameter.kt"); diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/FirReferenceResolveHelper.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/FirReferenceResolveHelper.kt index 1887b75d494..4b1176dcb3c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/FirReferenceResolveHelper.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/FirReferenceResolveHelper.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.idea.references import com.intellij.psi.tree.TokenSet +import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE import org.jetbrains.kotlin.fir.declarations.* @@ -22,10 +23,7 @@ import org.jetbrains.kotlin.fir.resolve.symbolProvider import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl -import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType -import org.jetbrains.kotlin.fir.types.FirErrorTypeRef -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef -import org.jetbrains.kotlin.fir.types.classId +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.idea.fir.getCandidateSymbols import org.jetbrains.kotlin.idea.fir.isImplicitFunctionCall import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFir @@ -47,7 +45,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult internal object FirReferenceResolveHelper { fun FirResolvedTypeRef.toTargetSymbol(session: FirSession, symbolBuilder: KtSymbolByFirBuilder): KtSymbol? { - val type = type as? ConeLookupTagBasedType + val type = getDeclaredType() as? ConeLookupTagBasedType val resolvedSymbol = type?.lookupTag?.toSymbol(session) as? AbstractFirBasedSymbol<*> val symbol = resolvedSymbol ?: run { @@ -58,6 +56,10 @@ internal object FirReferenceResolveHelper { return symbol?.fir?.buildSymbol(symbolBuilder) } + private fun FirResolvedTypeRef.getDeclaredType() = + if (this.delegatedTypeRef?.source?.kind == FirFakeSourceElementKind.ArrayTypeFromVarargParameter) type.arrayElementType() + else type + private fun ClassId.toTargetPsi( session: FirSession, symbolBuilder: KtSymbolByFirBuilder, diff --git a/idea/testData/resolve/references/InMethodVarargParameter.kt b/idea/testData/resolve/references/InMethodVarargParameter.kt new file mode 100644 index 00000000000..8f61bacb703 --- /dev/null +++ b/idea/testData/resolve/references/InMethodVarargParameter.kt @@ -0,0 +1,9 @@ +package test + +class A + +class Test { + fun some(vararg a: A) = 12 +} + +// REF: (test).A diff --git a/idea/testData/resolve/references/InVaragReferenceInFunctionBody.kt b/idea/testData/resolve/references/InVaragReferenceInFunctionBody.kt new file mode 100644 index 00000000000..c4b14eacb78 --- /dev/null +++ b/idea/testData/resolve/references/InVaragReferenceInFunctionBody.kt @@ -0,0 +1,9 @@ +package test + +class A + +class Test { + fun some(vararg a: A) = a +} + +// REF: a diff --git a/idea/testData/resolve/references/InVaragReferenceInNamedParameter.kt b/idea/testData/resolve/references/InVaragReferenceInNamedParameter.kt new file mode 100644 index 00000000000..0c4e83ad8ae --- /dev/null +++ b/idea/testData/resolve/references/InVaragReferenceInNamedParameter.kt @@ -0,0 +1,10 @@ +package test + +class A + +class Test { + fun some(vararg a: A) {} + fun call() = some(a = arrayOf(A())) +} + +// REF: a diff --git a/idea/tests/org/jetbrains/kotlin/idea/resolve/ReferenceResolveTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/resolve/ReferenceResolveTestGenerated.java index 134d3da6298..de0b2bf499d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/resolve/ReferenceResolveTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/resolve/ReferenceResolveTestGenerated.java @@ -219,6 +219,11 @@ public class ReferenceResolveTestGenerated extends AbstractReferenceResolveTest runTest("idea/testData/resolve/references/InMethodParameter.kt"); } + @TestMetadata("InMethodVarargParameter.kt") + public void testInMethodVarargParameter() throws Exception { + runTest("idea/testData/resolve/references/InMethodVarargParameter.kt"); + } + @TestMetadata("InObjectClassObject.kt") public void testInObjectClassObject() throws Exception { runTest("idea/testData/resolve/references/InObjectClassObject.kt"); @@ -229,6 +234,16 @@ public class ReferenceResolveTestGenerated extends AbstractReferenceResolveTest runTest("idea/testData/resolve/references/InSecondClassObject.kt"); } + @TestMetadata("InVaragReferenceInFunctionBody.kt") + public void testInVaragReferenceInFunctionBody() throws Exception { + runTest("idea/testData/resolve/references/InVaragReferenceInFunctionBody.kt"); + } + + @TestMetadata("InVaragReferenceInNamedParameter.kt") + public void testInVaragReferenceInNamedParameter() throws Exception { + runTest("idea/testData/resolve/references/InVaragReferenceInNamedParameter.kt"); + } + @TestMetadata("JavaAnnotationParameter.kt") public void testJavaAnnotationParameter() throws Exception { runTest("idea/testData/resolve/references/JavaAnnotationParameter.kt");