Skip to content

Commit

Permalink
FIR IDE: introduce KtFirCollectionLiteralReference
Browse files Browse the repository at this point in the history
  • Loading branch information
darthorimar committed Nov 23, 2020
1 parent bac5ebc commit 7b1eef1
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class KotlinFirReferenceContributor : KotlinReferenceProviderContributor {
registerProvider(factory = ::KtFirDestructuringDeclarationReference)
registerProvider(factory = ::KtFirArrayAccessReference)
registerProvider(factory = ::KtFirConstructorDelegationReference)
registerProvider(factory = ::KtFirCollectionLiteralReference)
}
}
}
Original file line number Diff line number Diff line change
@@ -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")

}
}
2 changes: 0 additions & 2 deletions idea/testData/resolve/references/CollectionLiteralLeft.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// IGNORE_FIR

val abc = <caret>[1, 2, 3]

// REF: (kotlin).arrayOf(vararg T)
2 changes: 0 additions & 2 deletions idea/testData/resolve/references/CollectionLiteralRight.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// IGNORE_FIR

val abc: IntArray = [1, 2, 3<caret>]

// REF: (kotlin).intArrayOf(vararg kotlin.Int)

0 comments on commit 7b1eef1

Please sign in to comment.