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`.
This commit is contained in:
committed by
Ilya Kirillov
parent
87f3ca3f36
commit
17617ffd3f
+28
-6
@@ -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<FirTypeRef>() {
|
||||
override fun <E : FirElement> transformElement(element: E, data: FirTypeRef): CompositeTransformResult<E> {
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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<FirQualifierPart>,
|
||||
override val annotations: MutableList<FirAnnotationCall>
|
||||
@@ -43,5 +43,6 @@ class FirUserTypeRefImpl(
|
||||
}
|
||||
|
||||
override fun replaceSource(newSource: FirSourceElement?) {
|
||||
source = newSource
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+15
@@ -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");
|
||||
|
||||
+7
-5
@@ -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,
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package test
|
||||
|
||||
class A
|
||||
|
||||
class Test {
|
||||
fun some(vararg a: <caret>A) = 12
|
||||
}
|
||||
|
||||
// REF: (test).A
|
||||
@@ -0,0 +1,9 @@
|
||||
package test
|
||||
|
||||
class A
|
||||
|
||||
class Test {
|
||||
fun some(vararg a: A) = <caret>a
|
||||
}
|
||||
|
||||
// REF: a
|
||||
@@ -0,0 +1,10 @@
|
||||
package test
|
||||
|
||||
class A
|
||||
|
||||
class Test {
|
||||
fun some(vararg a: A) {}
|
||||
fun call() = some(<caret>a = arrayOf(A()))
|
||||
}
|
||||
|
||||
// REF: a
|
||||
+15
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user