FIR IDE: introduce KtFirCollectionLiteralReference

This commit is contained in:
Ilya Kirillov
2020-11-06 11:14:31 +03:00
parent bac5ebcb12
commit 7b1eef136e
5 changed files with 77 additions and 5 deletions
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtTypeReference
@@ -89,12 +90,27 @@ object KtDeclarationAndFirDeclarationEqualityChecker {
else -> error("Invalid type reference $this")
}
return if (isVararg) {
"kotlin.Array<out $rendered>"
rendered.asArrayType()
} else {
rendered
}
}
private fun String.asArrayType(): String {
classIdToName[this]?.let { return it }
return "kotlin.Array<out $this>"
}
@OptIn(ExperimentalStdlibApi::class)
private val classIdToName: Map<String, String> = buildList {
StandardClassIds.primitiveArrayTypeByElementType.mapTo(this) { (classId, arrayClassId) ->
classId.asString().replace('/', '.') to arrayClassId.asString().replace('/', '.')
}
StandardClassIds.unsignedArrayTypeByElementType.mapTo(this) { (classId, arrayClassId) ->
classId.asString().replace('/', '.') to arrayClassId.asString().replace('/', '.')
}
}.toMap()
private fun FirTypeProjection.renderTypeAsKotlinType() = when (this) {
is FirStarProjection -> "*"
is FirTypeProjectionWithVariance -> buildString {
@@ -15,6 +15,7 @@ class KotlinFirReferenceContributor : KotlinReferenceProviderContributor {
registerProvider(factory = ::KtFirDestructuringDeclarationReference)
registerProvider(factory = ::KtFirArrayAccessReference)
registerProvider(factory = ::KtFirConstructorDelegationReference)
registerProvider(factory = ::KtFirCollectionLiteralReference)
}
}
}
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.references
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirSafe
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression
class KtFirCollectionLiteralReference(
expression: KtCollectionLiteralExpression
) : KtCollectionLiteralReference(expression), KtFirReference {
override fun KtAnalysisSession.resolveToSymbols(): Collection<KtSymbol> {
check(this is KtFirAnalysisSession)
val fir = element.getOrBuildFirSafe<FirArrayOfCall>(firResolveState) ?: return emptyList()
val type = fir.typeRef.coneTypeSafe<ConeClassLikeType>() ?: return listOfNotNull(arrayOfSymbol(arrayOf))
val call = arrayTypeToArrayOfCall[type.lookupTag.classId] ?: arrayOf
return listOfNotNull(arrayOfSymbol(call))
}
private fun KtFirAnalysisSession.arrayOfSymbol(identifier: Name): KtSymbol? {
val fir = firResolveState.rootModuleSession.firSymbolProvider.getTopLevelCallableSymbols(kotlinPackage, identifier).firstOrNull {
/* choose (for byte array)
* public fun byteArrayOf(vararg elements: kotlin.Byte): kotlin.ByteArray
*/
(it as? FirFunctionSymbol<*>)?.fir?.valueParameters?.singleOrNull()?.isVararg == true
}?.fir as? FirSimpleFunction ?: return null
return firSymbolBuilder.buildFunctionSymbol(fir)
}
companion object {
private val kotlinPackage = FqName("kotlin")
private val arrayOf = Name.identifier("arrayOf")
private val arrayTypeToArrayOfCall = run {
StandardClassIds.primitiveArrayTypeByElementType.values + StandardClassIds.unsignedArrayTypeByElementType.values
}.associateWith { it.correspondingArrayOfCallFqName() }
private fun ClassId.correspondingArrayOfCallFqName(): Name =
Name.identifier("${shortClassName.identifier.decapitalize()}Of")
}
}
@@ -1,5 +1,3 @@
// IGNORE_FIR
val abc = <caret>[1, 2, 3]
// REF: (kotlin).arrayOf(vararg T)
@@ -1,5 +1,3 @@
// IGNORE_FIR
val abc: IntArray = [1, 2, 3<caret>]
// REF: (kotlin).intArrayOf(vararg kotlin.Int)