FIR IDE: move analysis api fir main sources to the analysis directory

This commit is contained in:
Ilya Kirillov
2021-09-14 17:19:34 +02:00
parent 989f3248e4
commit 5e9f807c78
117 changed files with 969 additions and 964 deletions
@@ -0,0 +1,99 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compile(project(":compiler:psi"))
compile(project(":compiler:fir:fir2ir"))
compile(project(":compiler:ir.tree"))
compile(project(":compiler:fir:resolve"))
compile(project(":compiler:fir:checkers"))
compile(project(":compiler:fir:checkers:checkers.jvm"))
compile(project(":compiler:fir:java"))
compile(project(":analysis:low-level-api-fir"))
compile(project(":analysis:analysis-api"))
compile(project(":compiler:light-classes"))
compile(intellijCoreDep())
implementation(project(":analysis:analysis-api-providers"))
testCompile(projectTests(":analysis:low-level-api-fir"))
testCompile(projectTests(":compiler:tests-common"))
testCompile(projectTests(":compiler:test-infrastructure-utils"))
testCompile(projectTests(":compiler:test-infrastructure"))
testCompile(projectTests(":compiler:tests-common-new"))
testCompile(projectTests(":compiler:fir:analysis-tests:legacy-fir-tests"))
testCompile(project(":kotlin-test:kotlin-test-junit"))
testCompile(toolsJar())
testApiJUnit5()
testRuntime(project(":analysis:symbol-light-classes"))
testRuntimeOnly(intellijDep()) {
includeJars(
"jps-model",
"extensions",
"util",
"platform-api",
"platform-impl",
"idea",
"guava",
"trove4j",
"asm-all",
"log4j",
"jdom",
"streamex",
"bootstrap",
"jna",
rootProject = rootProject
)
}
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
}
projectTest(jUnit5Enabled = true) {
dependsOn(":dist")
workingDir = rootDir
useJUnitPlatform()
}
testsJar()
allprojects {
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
kotlinOptions {
freeCompilerArgs += "-opt-in=org.jetbrains.kotlin.fir.symbols.SymbolInternals"
}
}
}
val generatorClasspath by configurations.creating
dependencies {
generatorClasspath(project(":analysis:analysis-api-fir:analysis-api-fir-generator"))
}
val generateCode by tasks.registering(NoDebugJavaExec::class) {
val generatorRoot = "$projectDir/analysis/analysis-api-fir/analysis-api-fir-generator/src/"
val generatorConfigurationFiles = fileTree(generatorRoot) {
include("**/*.kt")
}
inputs.files(generatorConfigurationFiles)
workingDir = rootDir
classpath = generatorClasspath
main = "org.jetbrains.kotlin.analysis.api.fir.generator.MainKt"
systemProperties["line.separator"] = "\n"
}
val compileKotlin by tasks
compileKotlin.dependsOn(generateCode)
@@ -0,0 +1,153 @@
/*
* 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.analysis.api.fir
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.KtDeclarationAndFirDeclarationEqualityChecker
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSession
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtNamedFunction
//todo introduce LibraryModificationTracker based cache?
object FirIdeDeserializedDeclarationSourceProvider {
fun findPsi(fir: FirElement, project: Project): PsiElement? {
return when (fir) {
is FirSimpleFunction -> provideSourceForFunction(fir, project)
is FirProperty -> provideSourceForProperty(fir, project)
is FirClass -> provideSourceForClass(fir, project)
is FirTypeAlias -> provideSourceForTypeAlias(fir, project)
is FirConstructor -> provideSourceForConstructor(fir, project)
else -> null
}
}
private fun provideSourceForFunction(
function: FirSimpleFunction,
project: Project
): PsiElement? {
val candidates = if (function.isTopLevel) {
project.createDeclarationProvider(function.scope(project)).getTopLevelFunctions(function.symbol.callableId)
.filter(KtNamedFunction::isCompiled)
} else {
function.containingKtClass(project)?.body?.functions
?.filter { it.name == function.name.asString() && it.isCompiled() }
.orEmpty()
}
return function.unwrapFakeOverrides().chooseCorrespondingPsi(candidates)
}
private fun provideSourceForProperty(property: FirProperty, project: Project): PsiElement? {
val candidates = if (property.isTopLevel) {
project.createDeclarationProvider(property.scope(project)).getTopLevelFunctions(property.symbol.callableId)
} else {
property.containingKtClass(project)?.declarations
?.filter { it.name == property.name.asString() }
.orEmpty()
}
return candidates.firstOrNull(KtElement::isCompiled)
}
private fun provideSourceForClass(klass: FirClass, project: Project): PsiElement? =
classByClassId(klass.symbol.classId, klass.scope(project), project)
private fun provideSourceForTypeAlias(alias: FirTypeAlias, project: Project): PsiElement? {
val candidates = project.createDeclarationProvider(alias.scope(project)).getTypeAliasesByClassId(alias.symbol.classId)
return candidates.firstOrNull(KtElement::isCompiled)
}
private fun provideSourceForConstructor(
constructor: FirConstructor,
project: Project
): PsiElement? {
val containingKtClass = constructor.containingKtClass(project) ?: return null
if (constructor.isPrimary) return containingKtClass.primaryConstructor
return constructor.unwrapFakeOverrides().chooseCorrespondingPsi(containingKtClass.secondaryConstructors)
}
private fun FirFunction.chooseCorrespondingPsi(
candidates: Collection<KtFunction>
): KtFunction? {
if (candidates.isEmpty()) return null
for (candidate in candidates) {
assert(candidate.isCompiled()) {
"Candidate should be decompiled from metadata because it should have fqName types as we don't use resolve here"
}
if (KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(candidate, this)) {
return candidate
}
}
return null
}
private fun FirDeclaration.scope(project: Project): GlobalSearchScope {
return GlobalSearchScope.allScope(project)
/* TODO:
val session = session as? FirLibrarySession
return session?.scope ?: GlobalSearchScope.allScope(project)*/
}
private fun FirCallableDeclaration.containingKtClass(project: Project): KtClassOrObject? =
unwrapFakeOverrides().containingClass()?.classId?.let { classByClassId(it, scope(project), project) }
private fun classByClassId(classId: ClassId, scope: GlobalSearchScope, project: Project): KtClassOrObject? {
val correctedClassId = classIdMapping[classId] ?: classId
return project.createDeclarationProvider(scope)
.getClassesByClassId(correctedClassId)
.firstOrNull(KtElement::isCompiled)
}
private val FirCallableDeclaration.isTopLevel
get() = symbol.callableId.className == null
private val classIdMapping = (0..23).associate { i ->
StandardClassIds.FunctionN(i) to ClassId(FqName("kotlin.jvm.functions"), Name.identifier("Function$i"))
}
}
private fun KtElement.isCompiled(): Boolean = containingKtFile.isCompiled
private val allowedFakeElementKinds = setOf(
FirFakeSourceElementKind.PropertyFromParameter,
FirFakeSourceElementKind.ItLambdaParameter,
FirFakeSourceElementKind.DataClassGeneratedMembers,
FirFakeSourceElementKind.ImplicitConstructor,
)
private fun FirElement.getAllowedPsi() = when (val source = source) {
null -> null
is FirRealPsiSourceElement -> source.psi
is FirFakeSourceElement -> if (source.kind in allowedFakeElementKinds) psi else null
else -> null
}
fun FirElement.findPsi(project: Project): PsiElement? =
getAllowedPsi() ?: FirIdeDeserializedDeclarationSourceProvider.findPsi(this, project)
fun FirElement.findPsi(session: FirSession): PsiElement? =
findPsi((session as FirIdeSession).project)
/**
* Finds [PsiElement] which will be used as go-to referenced element for [KtPsiReference]
* For data classes & enums generated members like `copy` `componentN`, `values` it will return corresponding enum/data class
* Otherwise, behaves the same way as [findPsi] returns exact PSI declaration corresponding to passed [FirDeclaration]
*/
fun FirDeclaration.findReferencePsi(): PsiElement? =
psi ?: FirIdeDeserializedDeclarationSourceProvider.findPsi(this, (moduleData.session as FirIdeSession).project)
@@ -0,0 +1,52 @@
/*
* 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.analysis.api.fir
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.util.OperatorNameConventions
fun FirFunctionCall.isImplicitFunctionCall(): Boolean {
if (dispatchReceiver !is FirQualifiedAccessExpression) return false
return calleeReference.getCandidateSymbols().any(FirBasedSymbol<*>::isInvokeFunction)
}
private fun FirBasedSymbol<*>.isInvokeFunction() =
(this as? FirNamedFunctionSymbol)?.fir?.name == OperatorNameConventions.INVOKE
fun FirFunctionCall.getCalleeSymbol(): FirBasedSymbol<*>? =
calleeReference.getResolvedSymbolOfNameReference()
fun FirReference.getResolvedSymbolOfNameReference(): FirBasedSymbol<*>? =
(this as? FirResolvedNamedReference)?.resolvedSymbol
internal fun FirReference.getResolvedKtSymbolOfNameReference(builder: KtSymbolByFirBuilder): KtSymbol? =
getResolvedSymbolOfNameReference()?.fir?.let(builder::buildSymbol)
internal fun FirErrorNamedReference.getCandidateSymbols(): Collection<FirBasedSymbol<*>> =
diagnostic.getCandidateSymbols()
internal fun FirNamedReference.getCandidateSymbols(): Collection<FirBasedSymbol<*>> = when (this) {
is FirResolvedNamedReference -> listOf(resolvedSymbol)
is FirErrorNamedReference -> getCandidateSymbols()
else -> emptyList()
}
internal fun ConeDiagnostic.getCandidateSymbols(): Collection<FirBasedSymbol<*>> =
when (this) {
is ConeDiagnosticWithCandidates -> candidateSymbols
else -> emptyList()
}
@@ -0,0 +1,147 @@
/*
* 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.analysis.api.fir
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir
import org.jetbrains.kotlin.analysis.api.InvalidWayOfUsingAnalysisSession
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.components.*
import org.jetbrains.kotlin.analysis.api.fir.components.*
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirOverrideInfoProvider
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbolProvider
import org.jetbrains.kotlin.analysis.api.fir.utils.threadLocal
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
internal class KtFirAnalysisSession
private constructor(
private val project: Project,
val firResolveState: FirModuleResolveState,
internal val firSymbolBuilder: KtSymbolByFirBuilder,
token: ValidityToken,
element: KtElement,
private val mode: AnalysisSessionMode,
) : KtAnalysisSession(token) {
private enum class AnalysisSessionMode {
REGULAR,
DEPENDENT_COPY
}
override val smartCastProviderImpl = KtFirSmartcastProvider(this, token)
override val expressionTypeProviderImpl = KtFirExpressionTypeProvider(this, token)
override val diagnosticProviderImpl = KtFirDiagnosticProvider(this, token)
override val containingDeclarationProviderImpl = KtFirSymbolContainingDeclarationProvider(this, token)
override val callResolverImpl = KtFirCallResolver(this, token)
override val samResolverImpl = KtFirSamResolver(this, token)
override val scopeProviderImpl by threadLocal { KtFirScopeProvider(this, firSymbolBuilder, project, firResolveState, token) }
override val symbolProviderImpl =
KtFirSymbolProvider(this, firResolveState.rootModuleSession.symbolProvider, firResolveState, firSymbolBuilder, token)
override val completionCandidateCheckerImpl = KtFirCompletionCandidateChecker(this, token)
override val symbolDeclarationOverridesProviderImpl =
KtFirSymbolDeclarationOverridesProvider(this, token)
override val referenceShortenerImpl = KtFirReferenceShortener(this, token, firResolveState)
override val importOptimizerImpl: KtImportOptimizer = KtFirImportOptimizer(token, firResolveState)
override val symbolDeclarationRendererProviderImpl: KtSymbolDeclarationRendererProvider =
KtFirSymbolDeclarationRendererProvider(this, token)
override val expressionInfoProviderImpl = KtFirExpressionInfoProvider(this, token)
override val compileTimeConstantProviderImpl: KtCompileTimeConstantProvider = KtFirCompileTimeConstantProvider(this, token)
override val overrideInfoProviderImpl = KtFirOverrideInfoProvider(this, token)
override val visibilityCheckerImpl: KtVisibilityChecker = KtFirVisibilityChecker(this, token)
override val psiTypeProviderImpl = KtFirPsiTypeProvider(this, token)
override val jvmTypeMapperImpl = KtFirJvmTypeMapper(this, token)
override val typeProviderImpl = KtFirTypeProvider(this, token)
override val typeInfoProviderImpl = KtFirTypeInfoProvider(this, token)
override val subtypingComponentImpl = KtFirSubtypingComponent(this, token)
override val inheritorsProviderImpl: KtInheritorsProvider = KtFirInheritorsProvider(this, token)
override val symbolInfoProviderImpl: KtSymbolInfoProvider = KtFirSymbolInfoProvider(this, token)
override val typesCreatorImpl: KtTypeCreator = KtFirTypeCreator(this, token)
override fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession {
check(mode == AnalysisSessionMode.REGULAR) {
"Cannot create context-dependent copy of KtAnalysis session from a context dependent one"
}
require(!elementToReanalyze.isPhysical) { "Depended context should be build only for non-physical elements" }
val contextResolveState = LowLevelFirApiFacadeForResolveOnAir.getResolveStateForDependentCopy(
originalState = firResolveState,
originalKtFile = originalKtFile,
elementToAnalyze = elementToReanalyze
)
return KtFirAnalysisSession(
project,
contextResolveState,
firSymbolBuilder.createReadOnlyCopy(contextResolveState),
token,
originalKtFile,
AnalysisSessionMode.DEPENDENT_COPY
)
}
val rootModuleSession: FirSession get() = firResolveState.rootModuleSession
val firSymbolProvider: FirSymbolProvider get() = rootModuleSession.symbolProvider
val targetPlatform: TargetPlatform get() = rootModuleSession.moduleData.platform
val searchScope: GlobalSearchScope = element.resolveScope//todo
companion object {
@InvalidWayOfUsingAnalysisSession
@Deprecated("Please use org.jetbrains.kotlin.analysis.api.KtAnalysisSessionProviderKt.analyze")
internal fun createAnalysisSessionByResolveState(
firResolveState: FirModuleResolveState,
token: ValidityToken,
element: KtElement,
): KtFirAnalysisSession {
val project = firResolveState.project
val firSymbolBuilder = KtSymbolByFirBuilder(
firResolveState,
project,
token
)
return KtFirAnalysisSession(
project,
firResolveState,
firSymbolBuilder,
token,
element,
AnalysisSessionMode.REGULAR,
)
}
}
}
@@ -0,0 +1,78 @@
/*
* 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.analysis.api.fir
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getResolveState
import org.jetbrains.kotlin.analysis.api.*
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.tokens.ValidityTokenFactory
import org.jetbrains.kotlin.psi.KtElement
import java.util.concurrent.ConcurrentHashMap
import kotlin.reflect.KClass
@OptIn(InvalidWayOfUsingAnalysisSession::class)
class KtFirAnalysisSessionProvider(private val project: Project) : KtAnalysisSessionProvider() {
private val cache = KtAnalysisSessionCache<Pair<FirModuleResolveState, KClass<out ValidityToken>>>(project)
@InvalidWayOfUsingAnalysisSession
override fun getAnalysisSession(contextElement: KtElement, factory: ValidityTokenFactory): KtAnalysisSession {
val resolveState = contextElement.getResolveState()
return cache.getAnalysisSession(resolveState to factory.identifier) {
val validityToken = factory.create(project)
@Suppress("DEPRECATION")
KtFirAnalysisSession.createAnalysisSessionByResolveState(resolveState, validityToken, contextElement)
}
}
override fun getAnalysisSessionBySymbol(contextSymbol: KtSymbol): KtAnalysisSession {
require(contextSymbol is KtFirSymbol<*>)
val resolveState = contextSymbol.firRef.resolveState
val token = contextSymbol.token
return getCachedAnalysisSession(resolveState, token)
?: error("analysis session was not found for ${contextSymbol::class}, symbol.isValid=${contextSymbol.isValid()}")
}
private fun getCachedAnalysisSession(resolveState: FirModuleResolveState, token: ValidityToken): KtAnalysisSession? {
return cache.getCachedAnalysisSession(resolveState to token::class)
}
@TestOnly
override fun clearCaches() {
cache.clear()
}
}
private class KtAnalysisSessionCache<KEY : Any>(project: Project) {
private val cache = CachedValuesManager.getManager(project).createCachedValue {
CachedValueProvider.Result(
ConcurrentHashMap<KEY, KtAnalysisSession>(),
PsiModificationTracker.MODIFICATION_COUNT,
ProjectRootModificationTracker.getInstance(project),
project.createProjectWideOutOfBlockModificationTracker()
)
}
@TestOnly
fun clear() {
cache.value.clear()
}
inline fun getAnalysisSession(key: KEY, create: () -> KtAnalysisSession): KtAnalysisSession =
cache.value.getOrPut(key) { create() }
fun getCachedAnalysisSession(key: KEY): KtAnalysisSession? =
cache.value[key]
}
@@ -0,0 +1,433 @@
/*
* 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.analysis.api.fir
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.providers.createPackageProvider
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirFieldImpl
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
import org.jetbrains.kotlin.fir.resolve.calls.originalConstructorIfTypeAlias
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.KtStarProjectionTypeArgument
import org.jetbrains.kotlin.analysis.api.KtTypeArgument
import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.fir.symbols.*
import org.jetbrains.kotlin.analysis.api.fir.types.*
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.Variance
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
/**
* Maps FirElement to KtSymbol & ConeType to KtType, thread safe
*/
internal class KtSymbolByFirBuilder private constructor(
private val project: Project,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
val withReadOnlyCaching: Boolean,
private val symbolsCache: BuilderCache<FirDeclaration, KtSymbol>,
private val filesCache: BuilderCache<FirFile, KtFileSymbol>,
private val backingFieldCache: BuilderCache<FirBackingField, KtBackingFieldSymbol>,
private val typesCache: BuilderCache<ConeKotlinType, KtType>,
) : ValidityTokenOwner {
private val resolveState by weakRef(resolveState)
private val firProvider get() = resolveState.rootModuleSession.symbolProvider
val rootSession: FirSession = resolveState.rootModuleSession
val classifierBuilder = ClassifierSymbolBuilder()
val functionLikeBuilder = FunctionLikeSymbolBuilder()
val variableLikeBuilder = VariableLikeSymbolBuilder()
val callableBuilder = CallableSymbolBuilder()
val typeBuilder = TypeBuilder()
constructor(
resolveState: FirModuleResolveState,
project: Project,
token: ValidityToken
) : this(
project = project,
token = token,
resolveState = resolveState,
withReadOnlyCaching = false,
symbolsCache = BuilderCache(),
typesCache = BuilderCache(),
backingFieldCache = BuilderCache(),
filesCache = BuilderCache(),
)
fun createReadOnlyCopy(newResolveState: FirModuleResolveState): KtSymbolByFirBuilder {
check(!withReadOnlyCaching) { "Cannot create readOnly KtSymbolByFirBuilder from a readonly one" }
return KtSymbolByFirBuilder(
project,
token = token,
resolveState = newResolveState,
withReadOnlyCaching = true,
symbolsCache = symbolsCache.createReadOnlyCopy(),
typesCache = typesCache.createReadOnlyCopy(),
filesCache = filesCache.createReadOnlyCopy(),
backingFieldCache = backingFieldCache.createReadOnlyCopy(),
)
}
fun buildSymbol(fir: FirDeclaration): KtSymbol {
return when (fir) {
is FirClassLikeDeclaration -> classifierBuilder.buildClassLikeSymbol(fir)
is FirTypeParameter -> classifierBuilder.buildTypeParameterSymbol(fir)
is FirCallableDeclaration -> callableBuilder.buildCallableSymbol(fir)
else -> throwUnexpectedElementError(fir)
}
}
fun buildEnumEntrySymbol(fir: FirEnumEntry) = symbolsCache.cache(fir) { KtFirEnumEntrySymbol(fir, resolveState, token, this) }
fun buildFileSymbol(fir: FirFile) = filesCache.cache(fir) { KtFirFileSymbol(fir, resolveState, token) }
private val packageProvider = project.createPackageProvider(GlobalSearchScope.allScope(project))//todo scope
fun createPackageSymbolIfOneExists(packageFqName: FqName): KtFirPackageSymbol? {
val exists =
packageProvider.isPackageExists(packageFqName)
|| JavaPsiFacade.getInstance(project).findPackage(packageFqName.asString()) != null
if (!exists) {
return null
}
return createPackageSymbol(packageFqName)
}
fun createPackageSymbol(packageFqName: FqName): KtFirPackageSymbol {
return KtFirPackageSymbol(packageFqName, project, token)
}
inner class ClassifierSymbolBuilder {
fun buildClassifierSymbol(firSymbol: FirClassifierSymbol<*>): KtClassifierSymbol {
return when (val fir = firSymbol.fir) {
is FirClassLikeDeclaration -> classifierBuilder.buildClassLikeSymbol(fir)
is FirTypeParameter -> buildTypeParameterSymbol(fir)
else -> throwUnexpectedElementError(fir)
}
}
fun buildClassLikeSymbol(fir: FirClassLikeDeclaration): KtClassLikeSymbol {
return when (fir) {
is FirClass -> buildClassOrObjectSymbol(fir)
is FirTypeAlias -> buildTypeAliasSymbol(fir)
else -> throwUnexpectedElementError(fir)
}
}
fun buildClassOrObjectSymbol(fir: FirClass): KtClassOrObjectSymbol {
return when (fir) {
is FirAnonymousObject -> buildAnonymousObjectSymbol(fir)
is FirRegularClass -> buildNamedClassOrObjectSymbol(fir)
else -> throwUnexpectedElementError(fir)
}
}
fun buildNamedClassOrObjectSymbol(fir: FirRegularClass): KtFirNamedClassOrObjectSymbol {
return symbolsCache.cache(fir) { KtFirNamedClassOrObjectSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder) }
}
fun buildAnonymousObjectSymbol(fir: FirAnonymousObject): KtAnonymousObjectSymbol {
return symbolsCache.cache(fir) { KtFirAnonymousObjectSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder) }
}
fun buildTypeAliasSymbol(fir: FirTypeAlias): KtFirTypeAliasSymbol {
return symbolsCache.cache(fir) { KtFirTypeAliasSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder) }
}
fun buildTypeParameterSymbol(fir: FirTypeParameter): KtFirTypeParameterSymbol {
return symbolsCache.cache(fir) { KtFirTypeParameterSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder) }
}
fun buildTypeParameterSymbolByLookupTag(lookupTag: ConeTypeParameterLookupTag): KtTypeParameterSymbol? {
val firTypeParameterSymbol = firProvider.getSymbolByLookupTag(lookupTag) as? FirTypeParameterSymbol ?: return null
return buildTypeParameterSymbol(firTypeParameterSymbol.fir)
}
fun buildClassLikeSymbolByClassId(classId: ClassId): KtClassLikeSymbol? {
val firClassLikeSymbol = firProvider.getClassLikeSymbolByClassId(classId) ?: return null
return buildClassLikeSymbol(firClassLikeSymbol.fir)
}
fun buildClassLikeSymbolByLookupTag(lookupTag: ConeClassLikeLookupTag): KtClassLikeSymbol? {
val firClassLikeSymbol = firProvider.getSymbolByLookupTag(lookupTag) ?: return null
return buildClassLikeSymbol(firClassLikeSymbol.fir)
}
}
inner class FunctionLikeSymbolBuilder {
fun buildFunctionLikeSymbol(fir: FirFunction): KtFunctionLikeSymbol {
return when (fir) {
is FirSimpleFunction -> {
if (fir.origin == FirDeclarationOrigin.SamConstructor) {
buildSamConstructorSymbol(fir)
} else {
buildFunctionSymbol(fir)
}
}
is FirConstructor -> buildConstructorSymbol(fir)
is FirAnonymousFunction -> buildAnonymousFunctionSymbol(fir)
is FirPropertyAccessor -> buildPropertyAccessorSymbol(fir)
else -> throwUnexpectedElementError(fir)
}
}
fun buildFunctionSymbol(fir: FirSimpleFunction): KtFirFunctionSymbol {
check(fir.origin != FirDeclarationOrigin.SamConstructor)
return symbolsCache.cache(fir) { KtFirFunctionSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder) }
}
fun buildAnonymousFunctionSymbol(fir: FirAnonymousFunction): KtFirAnonymousFunctionSymbol {
return symbolsCache.cache(fir) { KtFirAnonymousFunctionSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder) }
}
fun buildConstructorSymbol(fir: FirConstructor): KtFirConstructorSymbol {
val originalFir = fir.originalConstructorIfTypeAlias ?: fir
return symbolsCache.cache(originalFir) {
KtFirConstructorSymbol(originalFir, resolveState, token, this@KtSymbolByFirBuilder)
}
}
fun buildSamConstructorSymbol(fir: FirSimpleFunction): KtFirSamConstructorSymbol {
check(fir.origin == FirDeclarationOrigin.SamConstructor)
return symbolsCache.cache(fir) { KtFirSamConstructorSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder) }
}
fun buildPropertyAccessorSymbol(fir: FirPropertyAccessor): KtFunctionLikeSymbol {
return symbolsCache.cache(fir) {
if (fir.isGetter) {
KtFirPropertyGetterSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder)
} else {
KtFirPropertySetterSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder)
}
}
}
}
inner class VariableLikeSymbolBuilder {
fun buildVariableLikeSymbol(fir: FirVariable): KtVariableLikeSymbol {
return when (fir) {
is FirProperty -> buildVariableSymbol(fir)
is FirValueParameter -> buildValueParameterSymbol(fir)
is FirField -> buildFieldSymbol(fir)
is FirEnumEntry -> buildEnumEntrySymbol(fir) // TODO enum entry should not be callable
is FirBackingField -> buildBackingFieldSymbol(fir)
is FirErrorProperty -> throwUnexpectedElementError(fir)
}
}
fun buildVariableSymbol(fir: FirProperty): KtVariableSymbol {
return when {
fir.isLocal -> buildLocalVariableSymbol(fir)
fir is FirSyntheticProperty -> buildSyntheticJavaPropertySymbol(fir)
else -> buildPropertySymbol(fir)
}
}
fun buildPropertySymbol(fir: FirProperty): KtKotlinPropertySymbol {
checkRequirementForBuildingSymbol<KtKotlinPropertySymbol>(fir, !fir.isLocal)
checkRequirementForBuildingSymbol<KtKotlinPropertySymbol>(fir, fir !is FirSyntheticProperty)
return symbolsCache.cache(fir) {
KtFirKotlinPropertySymbol(fir, resolveState, token, this@KtSymbolByFirBuilder)
}
}
fun buildLocalVariableSymbol(fir: FirProperty): KtFirLocalVariableSymbol {
checkRequirementForBuildingSymbol<KtFirLocalVariableSymbol>(fir, fir.isLocal)
return symbolsCache.cache(fir) {
KtFirLocalVariableSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder)
}
}
fun buildSyntheticJavaPropertySymbol(fir: FirSyntheticProperty): KtFirSyntheticJavaPropertySymbol {
return symbolsCache.cache(fir) {
KtFirSyntheticJavaPropertySymbol(fir, resolveState, token, this@KtSymbolByFirBuilder)
}
}
fun buildValueParameterSymbol(fir: FirValueParameter): KtValueParameterSymbol {
return symbolsCache.cache(fir) {
KtFirValueParameterSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder)
}
}
fun buildFieldSymbol(fir: FirField): KtFirJavaFieldSymbol {
checkRequirementForBuildingSymbol<KtFirJavaFieldSymbol>(fir, fir.isJavaFieldOrSubstitutionOverrideOfJavaField())
return symbolsCache.cache(fir) { KtFirJavaFieldSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder) }
}
fun buildBackingFieldSymbol(fir: FirBackingField): KtFirBackingFieldSymbol {
return backingFieldCache.cache(fir) {
KtFirBackingFieldSymbol(fir.propertySymbol.fir, resolveState, token, this@KtSymbolByFirBuilder)
}
}
fun buildBackingFieldSymbolByProperty(fir: FirProperty): KtFirBackingFieldSymbol {
val backingFieldSymbol = fir.backingField
?: error("FirProperty backingField is null")
return buildBackingFieldSymbol(backingFieldSymbol)
}
private fun FirField.isJavaFieldOrSubstitutionOverrideOfJavaField(): Boolean = when (this) {
is FirJavaField -> true
is FirFieldImpl -> (this as FirField).originalForSubstitutionOverride?.isJavaFieldOrSubstitutionOverrideOfJavaField() == true
else -> throwUnexpectedElementError(this)
}
}
inner class CallableSymbolBuilder {
fun buildCallableSymbol(fir: FirCallableDeclaration): KtCallableSymbol {
return when (fir) {
is FirPropertyAccessor -> buildPropertyAccessorSymbol(fir)
is FirFunction -> functionLikeBuilder.buildFunctionLikeSymbol(fir)
is FirVariable -> variableLikeBuilder.buildVariableLikeSymbol(fir)
else -> throwUnexpectedElementError(fir)
}
}
fun buildPropertyAccessorSymbol(fir: FirPropertyAccessor): KtPropertyAccessorSymbol {
return when {
fir.isGetter -> buildGetterSymbol(fir)
else -> buildSetterSymbol(fir)
}
}
fun buildGetterSymbol(fir: FirPropertyAccessor): KtFirPropertyGetterSymbol {
checkRequirementForBuildingSymbol<KtFirPropertyGetterSymbol>(fir, fir.isGetter)
return symbolsCache.cache(fir) { KtFirPropertyGetterSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder) }
}
fun buildSetterSymbol(fir: FirPropertyAccessor): KtFirPropertySetterSymbol {
checkRequirementForBuildingSymbol<KtFirPropertySetterSymbol>(fir, fir.isSetter)
return symbolsCache.cache(fir) { KtFirPropertySetterSymbol(fir, resolveState, token, this@KtSymbolByFirBuilder) }
}
}
inner class TypeBuilder {
fun buildKtType(coneType: ConeKotlinType): KtType {
return typesCache.cache(coneType) {
when (coneType) {
is ConeClassLikeTypeImpl -> {
if (hasFunctionalClassId(coneType)) KtFirFunctionalType(coneType, token, this@KtSymbolByFirBuilder)
else KtFirUsualClassType(coneType, token, this@KtSymbolByFirBuilder)
}
is ConeTypeParameterType -> KtFirTypeParameterType(coneType, token, this@KtSymbolByFirBuilder)
is ConeClassErrorType -> KtFirClassErrorType(coneType, token, this@KtSymbolByFirBuilder)
is ConeFlexibleType -> KtFirFlexibleType(coneType, token, this@KtSymbolByFirBuilder)
is ConeIntersectionType -> KtFirIntersectionType(coneType, token, this@KtSymbolByFirBuilder)
is ConeDefinitelyNotNullType -> KtFirDefinitelyNotNullType(coneType, token, this@KtSymbolByFirBuilder)
is ConeCapturedType -> KtFirCapturedType(coneType, token)
else -> throwUnexpectedElementError(coneType)
}
}
}
private fun hasFunctionalClassId(coneType: ConeClassLikeTypeImpl): Boolean {
val classId = coneType.classId ?: return false
return FunctionClassKind.byClassNamePrefix(classId.packageFqName, classId.relativeClassName.asString()) != null
}
fun buildKtType(coneType: FirTypeRef): KtType {
return buildKtType(coneType.coneType)
}
fun buildTypeArgument(coneType: ConeTypeProjection): KtTypeArgument = when (coneType) {
is ConeStarProjection -> KtStarProjectionTypeArgument(token)
is ConeKotlinTypeProjection -> KtTypeArgumentWithVariance(
buildKtType(coneType.type),
coneType.kind.toVariance(),
token,
)
}
private fun ProjectionKind.toVariance(): Variance = when (this) {
ProjectionKind.OUT -> Variance.OUT_VARIANCE
ProjectionKind.IN -> Variance.IN_VARIANCE
ProjectionKind.INVARIANT -> Variance.INVARIANT
ProjectionKind.STAR -> error("KtStarProjectionTypeArgument should not be directly created")
}
}
companion object {
private fun throwUnexpectedElementError(element: Any): Nothing {
error("Unexpected ${element::class.simpleName}")
}
@OptIn(ExperimentalContracts::class)
private inline fun <reified S : KtSymbol> checkRequirementForBuildingSymbol(
fir: FirElement,
requirement: Boolean,
) {
contract {
returns() implies requirement
}
require(requirement) {
"Cannot build ${S::class.simpleName} for ${fir.renderWithType(FirRenderer.RenderMode.WithResolvePhases)}"
}
}
}
}
private class BuilderCache<From, To: Any> private constructor(
private val cache: ConcurrentMap<From, To>,
private val isReadOnly: Boolean
) {
constructor() : this(ConcurrentHashMap<From, To>(), isReadOnly = false)
fun createReadOnlyCopy(): BuilderCache<From, To> {
check(!isReadOnly) { "Cannot create readOnly BuilderCache from a readonly one" }
return BuilderCache(cache, isReadOnly = true)
}
inline fun <reified S : To> cache(key: From, calculation: () -> S): S {
val value = if (isReadOnly) {
cache[key] ?: calculation()
} else cache.getOrPut(key, calculation)
return value as? S
?: error("Cannot cast ${value::class} to ${S::class}\n${DebugSymbolRenderer.render(value as KtSymbol)}")
}
}
internal fun FirElement.buildSymbol(builder: KtSymbolByFirBuilder) =
(this as? FirDeclaration)?.let(builder::buildSymbol)
internal fun FirDeclaration.buildSymbol(builder: KtSymbolByFirBuilder) =
builder.buildSymbol(this)
@@ -0,0 +1,72 @@
/*
* 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic
import org.jetbrains.kotlin.fir.analysis.diagnostics.toFirDiagnostics
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.ConeInferenceContext
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeStarProjection
import org.jetbrains.kotlin.fir.types.ConeTypeProjection
import org.jetbrains.kotlin.analysis.api.KtStarProjectionTypeArgument
import org.jetbrains.kotlin.analysis.api.KtTypeArgument
import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance
import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnosticWithPsi
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KT_DIAGNOSTIC_CONVERTER
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.types.TypeCheckerState
import org.jetbrains.kotlin.types.model.convertVariance
internal interface KtFirAnalysisSessionComponent {
val analysisSession: KtFirAnalysisSession
val rootModuleSession: FirSession get() = analysisSession.firResolveState.rootModuleSession
val typeContext: ConeInferenceContext get() = rootModuleSession.typeContext
val firSymbolBuilder get() = analysisSession.firSymbolBuilder
val firResolveState get() = analysisSession.firResolveState
fun ConeKotlinType.asKtType() = analysisSession.firSymbolBuilder.typeBuilder.buildKtType(this)
fun FirPsiDiagnostic.asKtDiagnostic(): KtDiagnosticWithPsi<*> =
KT_DIAGNOSTIC_CONVERTER.convert(analysisSession, this as FirDiagnostic)
fun ConeDiagnostic.asKtDiagnostic(
source: FirSourceElement,
qualifiedAccessSource: FirSourceElement?,
diagnosticCache: MutableList<FirDiagnostic>
): KtDiagnosticWithPsi<*>? {
val firDiagnostic = toFirDiagnostics(source, qualifiedAccessSource).firstOrNull() ?: return null
diagnosticCache += firDiagnostic
check(firDiagnostic is FirPsiDiagnostic)
return firDiagnostic.asKtDiagnostic()
}
val KtType.coneType: ConeKotlinType
get() {
require(this is KtFirType)
return coneType
}
val KtTypeArgument.coneTypeProjection: ConeTypeProjection
get() = when (this) {
is KtStarProjectionTypeArgument -> ConeStarProjection
is KtTypeArgumentWithVariance -> {
typeContext.createTypeArgument(type.coneType, variance.convertVariance()) as ConeTypeProjection
}
}
fun createTypeCheckerContext(): TypeCheckerState {
// TODO use correct session here,
return analysisSession.firResolveState.rootModuleSession.typeContext.newTypeCheckerState(errorTypesEqualToAnything = true, stubTypesEqualToAnything = true)
}
}
@@ -0,0 +1,46 @@
/*
* 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.components.KtBuiltinTypes
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirUsualClassType
import org.jetbrains.kotlin.analysis.api.fir.utils.ValidityAwareCachedValue
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.types.KtType
internal class KtFirBuiltInTypes(builtinTypes: BuiltinTypes, builder: KtSymbolByFirBuilder, override val token: ValidityToken) : KtBuiltinTypes() {
private val builder by weakRef(builder)
override val INT: KtType by cachedBuiltin(builtinTypes.intType)
override val LONG: KtType by cachedBuiltin(builtinTypes.longType)
override val SHORT: KtType by cachedBuiltin(builtinTypes.shortType)
override val BYTE: KtType by cachedBuiltin(builtinTypes.byteType)
override val FLOAT: KtType by cachedBuiltin(builtinTypes.floatType)
override val DOUBLE: KtType by cachedBuiltin(builtinTypes.doubleType)
override val CHAR: KtType by cachedBuiltin(builtinTypes.charType)
override val BOOLEAN: KtType by cachedBuiltin(builtinTypes.booleanType)
override val STRING: KtType by cachedBuiltin(builtinTypes.stringType)
override val UNIT: KtType by cachedBuiltin(builtinTypes.unitType)
override val NOTHING: KtType by cachedBuiltin(builtinTypes.nothingType)
override val ANY: KtType by cachedBuiltin(builtinTypes.anyType)
override val NULLABLE_ANY: KtType by cachedBuiltin(builtinTypes.nullableAnyType)
override val NULLABLE_NOTHING: KtType by cachedBuiltin(builtinTypes.nullableNothingType)
private fun cachedBuiltin(builtinTypeRef: FirImplicitBuiltinTypeRef): ValidityAwareCachedValue<KtFirUsualClassType> = cached {
KtFirUsualClassType(builtinTypeRef.type as ConeClassLikeTypeImpl, token, builder) // TODO builder leaking
}
}
@@ -0,0 +1,290 @@
/*
* 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.analysis.api.fir.components
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.realPsi
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.resolve.calls.FirErrorReferenceWithCandidate
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols
import org.jetbrains.kotlin.analysis.api.fir.isImplicitFunctionCall
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.calls.*
import org.jetbrains.kotlin.analysis.api.components.KtCallResolver
import org.jetbrains.kotlin.analysis.api.diagnostics.KtNonBoundToPsiErrorDiagnostic
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.buildSymbol
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.idea.references.FirReferenceResolveHelper
import org.jetbrains.kotlin.idea.references.readWriteAccess
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.findAssignment
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal class KtFirCallResolver(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtCallResolver(), KtFirAnalysisSessionComponent {
private val diagnosticCache = mutableListOf<FirDiagnostic>()
override fun resolveAccessorCall(call: KtSimpleNameExpression): KtCall? = withValidityAssertion {
when (val fir = call.getOrBuildFir(firResolveState)) {
is FirResolvedNamedReference -> {
val propertySymbol = fir.resolvedSymbol as? FirPropertySymbol ?: return null
val access = call.readWriteAccess(useResolveForReadWrite = false)
val setterValue = findAssignment(call)?.right
val accessor = when {
access.isWrite -> propertySymbol.setterSymbol?.fir
access.isRead -> propertySymbol.getterSymbol?.fir
else -> null
} ?: return null
val accessorSymbol = analysisSession.firSymbolBuilder.functionLikeBuilder.buildFunctionLikeSymbol(accessor)
val target =
if (!access.isWrite || setterValue != null)
KtSuccessCallTarget(accessorSymbol)
else // access.isWrite && setterValue == null
KtErrorCallTarget(
listOf(accessorSymbol),
KtNonBoundToPsiErrorDiagnostic(factoryName = null, "Setter value is missing", token)
)
val ktArgumentMapping = LinkedHashMap<KtExpression, KtValueParameterSymbol>()
if (access.isWrite && setterValue != null) {
val setterParameterSymbol = accessor.valueParameters.single().buildSymbol(firSymbolBuilder) as KtValueParameterSymbol
ktArgumentMapping[setterValue] = setterParameterSymbol
}
return KtFunctionCall(ktArgumentMapping, target)
}
else -> return null
}
}
override fun resolveCall(call: KtBinaryExpression): KtCall? = withValidityAssertion {
when (val fir = call.getOrBuildFir(firResolveState)) {
is FirFunctionCall -> resolveCall(fir)
is FirComparisonExpression -> resolveCall(fir.compareToCall)
is FirEqualityOperatorCall -> null // TODO
else -> null
}
}
override fun resolveCall(call: KtUnaryExpression): KtCall? = withValidityAssertion {
when (val fir = call.getOrBuildFir(firResolveState)) {
is FirFunctionCall -> resolveCall(fir)
is FirBlock -> {
// Desugared increment or decrement block. See [BaseFirBuilder#generateIncrementOrDecrementBlock]
// There would be corresponding inc()/dec() call that is assigned back to a temp variable.
val prefix = fir.statements.filterIsInstance<FirVariableAssignment>().find { it.rValue is FirFunctionCall }
(prefix?.rValue as? FirFunctionCall)?.let { resolveCall(it) }
}
is FirCheckNotNullCall -> null // TODO
else -> null
}
}
override fun resolveCall(call: KtCallElement): KtCall? = withValidityAssertion {
return when (val fir = call.getOrBuildFir(firResolveState)) {
is FirFunctionCall -> resolveCall(fir)
is FirAnnotationCall -> fir.asAnnotationCall()
is FirDelegatedConstructorCall -> fir.asDelegatedConstructorCall()
is FirConstructor -> fir.asDelegatedConstructorCall()
is FirSafeCallExpression -> fir.regularQualifiedAccess.safeAs<FirFunctionCall>()?.let { resolveCall(it) }
else -> null
}
}
override fun resolveCall(call: KtArrayAccessExpression): KtCall? = withValidityAssertion {
return when (val fir = call.getOrBuildFir(firResolveState)) {
is FirFunctionCall -> resolveCall(fir)
else -> null
}
}
private fun resolveCall(firCall: FirFunctionCall): KtCall? {
val session = firResolveState.rootModuleSession
return when {
firCall.isImplicitFunctionCall() -> {
val target = with(FirReferenceResolveHelper) {
val calleeReference = (firCall.dispatchReceiver as FirQualifiedAccessExpression).calleeReference
calleeReference.toTargetSymbol(session, firSymbolBuilder).singleOrNull()
}
when (target) {
is KtVariableLikeSymbol -> firCall.createCallByVariableLikeSymbolCall(target)
null -> null
else -> firCall.asSimpleFunctionCall()
}
}
else -> firCall.asSimpleFunctionCall()
}
}
private fun FirFunctionCall.createCallByVariableLikeSymbolCall(variableLikeSymbol: KtVariableLikeSymbol): KtCall? {
val (functionSymbol, target) = when (val callReference = calleeReference) {
is FirResolvedNamedReference -> {
val functionSymbol = callReference.resolvedSymbol as? FirNamedFunctionSymbol
(functionSymbol?.fir?.buildSymbol(firSymbolBuilder) as? KtFunctionSymbol)?.let {
functionSymbol to KtSuccessCallTarget(it)
} ?: return null
}
is FirErrorNamedReference -> {
val functionSymbol = callReference.candidateSymbol as? FirNamedFunctionSymbol
functionSymbol to callReference.createErrorCallTarget(source)
}
else -> error("Unexpected call reference ${callReference::class.simpleName}")
}
val callableId = functionSymbol?.callableId ?: return null
return if (callableId in kotlinFunctionInvokeCallableIds) {
KtFunctionalTypeVariableCall(variableLikeSymbol, createArgumentMapping(), target)
} else {
KtVariableWithInvokeFunctionCall(variableLikeSymbol, createArgumentMapping(), target)
}
}
private fun FirFunctionCall.asSimpleFunctionCall(): KtFunctionCall? {
val target = calleeReference.createCallTarget() ?: return null
return KtFunctionCall(createArgumentMapping(), target)
}
private fun FirAnnotationCall.asAnnotationCall(): KtAnnotationCall? {
val target = calleeReference.createCallTarget() ?: return null
return KtAnnotationCall(createArgumentMapping(), target)
}
private fun FirDelegatedConstructorCall.asDelegatedConstructorCall(): KtDelegatedConstructorCall? {
val target = calleeReference.createCallTarget() ?: return null
val kind = if (isSuper) KtDelegatedConstructorCallKind.SUPER_CALL else KtDelegatedConstructorCallKind.THIS_CALL
return KtDelegatedConstructorCall(createArgumentMapping(), target, kind)
}
private fun FirConstructor.asDelegatedConstructorCall(): KtDelegatedConstructorCall? {
// A delegation call may not be present in the source code:
//
// class A {
// constructor(i: Int) // <--- implicit constructor delegation call (empty element after RPAR)
// }
//
// and FIR built/found from that implicit `KtConstructorDelegationCall` is `FirConstructor`,
// which may have a pointer to the delegated constructor.
return delegatedConstructor?.asDelegatedConstructorCall()
}
private fun FirReference.createCallTarget(): KtCallTarget? {
return when (this) {
is FirSuperReference -> createCallTarget(source)
is FirResolvedNamedReference -> getKtFunctionOrConstructorSymbol()?.let { KtSuccessCallTarget(it) }
is FirErrorNamedReference -> createErrorCallTarget(source)
is FirErrorReferenceWithCandidate -> createErrorCallTarget(source)
is FirSimpleNamedReference ->
null
/* error(
"""
Looks like ${this::class.simpleName} && it calle reference ${calleeReference::class.simpleName} were not resolved to BODY_RESOLVE phase,
consider resolving it containing declaration before starting resolve calls
${this.render()}
${(this.psi as? KtElement)?.getElementTextInContext()}
""".trimIndent()
)*/
else -> error("Unexpected call reference ${this::class.simpleName}")
}
}
private fun FirCall.createArgumentMapping(): LinkedHashMap<KtExpression, KtValueParameterSymbol> {
val ktArgumentMapping = LinkedHashMap<KtExpression, KtValueParameterSymbol>()
argumentMapping?.let {
fun FirExpression.findKtExpression(): KtExpression? {
// For spread, named, and lambda arguments, the source is the KtValueArgument.
// For other arguments (including array indices), the source is the KtExpression.
return when (this) {
is FirNamedArgumentExpression, is FirSpreadArgumentExpression, is FirLambdaArgumentExpression ->
realPsi.safeAs<KtValueArgument>()?.getArgumentExpression()
else -> realPsi as? KtExpression
}
}
for ((firExpression, firValueParameter) in it.entries) {
val parameterSymbol = firValueParameter.buildSymbol(firSymbolBuilder) as KtValueParameterSymbol
if (firExpression is FirVarargArgumentsExpression) {
for (varargArgument in firExpression.arguments) {
val valueArgument = varargArgument.findKtExpression() ?: continue
ktArgumentMapping[valueArgument] = parameterSymbol
}
} else {
val valueArgument = firExpression.findKtExpression() ?: continue
ktArgumentMapping[valueArgument] = parameterSymbol
}
}
}
return ktArgumentMapping
}
private fun FirErrorNamedReference.createErrorCallTarget(qualifiedAccessSource: FirSourceElement?): KtErrorCallTarget =
KtErrorCallTarget(
getCandidateSymbols().mapNotNull { it.fir.buildSymbol(firSymbolBuilder) as? KtFunctionLikeSymbol },
source?.let { diagnostic.asKtDiagnostic(it, qualifiedAccessSource, diagnosticCache) }
?: KtNonBoundToPsiErrorDiagnostic(factoryName = null, diagnostic.reason, token)
)
private fun FirErrorReferenceWithCandidate.createErrorCallTarget(qualifiedAccessSource: FirSourceElement?): KtErrorCallTarget =
KtErrorCallTarget(
getCandidateSymbols().mapNotNull { it.fir.buildSymbol(firSymbolBuilder) as? KtFunctionLikeSymbol },
source?.let { diagnostic.asKtDiagnostic(it, qualifiedAccessSource, diagnosticCache) }
?: KtNonBoundToPsiErrorDiagnostic(factoryName = null, diagnostic.reason, token)
)
private fun FirResolvedNamedReference.getKtFunctionOrConstructorSymbol(): KtFunctionLikeSymbol? =
resolvedSymbol.fir.buildSymbol(firSymbolBuilder) as? KtFunctionLikeSymbol
private fun FirSuperReference.createCallTarget(qualifiedAccessSource: FirSourceElement?): KtCallTarget? =
when (val type = superTypeRef.coneType) {
is ConeKotlinErrorType ->
KtErrorCallTarget(
(firSymbolBuilder.classifierBuilder.buildClassLikeSymbolByLookupTag(type.lookupTag) as? KtSymbolWithMembers)?.let {
analysisSession.getPrimaryConstructor(it)?.let { ctor -> listOf(ctor) }
} ?: emptyList(),
source?.let { type.diagnostic.asKtDiagnostic(it, qualifiedAccessSource, diagnosticCache) }
?: KtNonBoundToPsiErrorDiagnostic(factoryName = null, type.diagnostic.reason, token)
)
is ConeClassLikeType ->
type.classId?.let { classId ->
(firSymbolBuilder.classifierBuilder.buildClassLikeSymbolByClassId(classId) as? KtSymbolWithMembers)?.let {
analysisSession.getPrimaryConstructor(it)?.let { ctor -> KtSuccessCallTarget(ctor) }
}
}
else ->
error("Unexpected type in super reference: ${type::class}")
}
private fun KtAnalysisSession.getPrimaryConstructor(symbolWithMembers: KtSymbolWithMembers): KtConstructorSymbol? =
symbolWithMembers.getDeclaredMemberScope().getConstructors().firstOrNull { it.isPrimary }
companion object {
private val kotlinFunctionInvokeCallableIds = (0..23).flatMapTo(hashSetOf()) { arity ->
listOf(
CallableId(StandardNames.getFunctionClassId(arity), OperatorNameConventions.INVOKE),
CallableId(StandardNames.getSuspendFunctionClassId(arity), OperatorNameConventions.INVOKE)
)
}
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirCompileTimeConstantEvaluator
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.analysis.api.components.KtCompileTimeConstantProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.utils.convertConstantExpression
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSimpleConstantValue
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.psi.KtExpression
internal class KtFirCompileTimeConstantProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtCompileTimeConstantProvider(), KtFirAnalysisSessionComponent {
override fun evaluate(expression: KtExpression): KtSimpleConstantValue<*>? = withValidityAssertion {
when (val fir = expression.getOrBuildFir(firResolveState)) {
is FirExpression -> FirCompileTimeConstantEvaluator().evaluate(fir)?.convertConstantExpression()
else -> throwUnexpectedFirElementError(fir, expression)
}
}
}
@@ -0,0 +1,96 @@
/*
* 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue
import org.jetbrains.kotlin.fir.resolve.inference.receiverType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir.getTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.ResolutionParameters
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.SingleCandidateResolutionMode
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.SingleCandidateResolver
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext
import org.jetbrains.kotlin.analysis.api.components.KtCompletionCandidateChecker
import org.jetbrains.kotlin.analysis.api.components.KtExtensionApplicabilityResult
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
internal class KtFirCompletionCandidateChecker(
analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtCompletionCandidateChecker(), KtFirAnalysisSessionComponent {
override val analysisSession: KtFirAnalysisSession by weakRef(analysisSession)
override fun checkExtensionFitsCandidate(
firSymbolForCandidate: KtCallableSymbol,
originalFile: KtFile,
nameExpression: KtSimpleNameExpression,
possibleExplicitReceiver: KtExpression?,
): KtExtensionApplicabilityResult = withValidityAssertion {
require(firSymbolForCandidate is KtFirSymbol<*>)
return firSymbolForCandidate.firRef.withFir(
phase = FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE
) { declaration ->
check(declaration is FirCallableDeclaration)
checkExtension(declaration, originalFile, nameExpression, possibleExplicitReceiver)
}
}
private fun checkExtension(
candidateSymbol: FirCallableDeclaration,
originalFile: KtFile,
nameExpression: KtSimpleNameExpression,
possibleExplicitReceiver: KtExpression?,
): KtExtensionApplicabilityResult {
val file = originalFile.getOrBuildFirFile(firResolveState)
val explicitReceiverExpression = possibleExplicitReceiver?.getOrBuildFirOfType<FirExpression>(firResolveState)
val resolver = SingleCandidateResolver(firResolveState.rootModuleSession, file)
val implicitReceivers = getImplicitReceivers(nameExpression)
for (implicitReceiverValue in implicitReceivers) {
val resolutionParameters = ResolutionParameters(
singleCandidateResolutionMode = SingleCandidateResolutionMode.CHECK_EXTENSION_FOR_COMPLETION,
callableSymbol = candidateSymbol.symbol,
implicitReceiver = implicitReceiverValue,
explicitReceiver = explicitReceiverExpression
)
resolver.resolveSingleCandidate(resolutionParameters)?.let {
return when {
candidateSymbol is FirVariable && candidateSymbol.returnTypeRef.coneType.receiverType(rootModuleSession) != null -> {
KtExtensionApplicabilityResult.ApplicableAsFunctionalVariableCall
}
else -> {
KtExtensionApplicabilityResult.ApplicableAsExtensionCallable
}
}
}
}
return KtExtensionApplicabilityResult.NonApplicable
}
private fun getImplicitReceivers(fakeNameExpression: KtSimpleNameExpression): Sequence<ImplicitReceiverValue<*>?> {
val towerDataContext = analysisSession.firResolveState.getTowerContextProvider()
.getClosestAvailableParentContext(fakeNameExpression)
?: error("Cannot find enclosing declaration for ${fakeNameExpression.getElementTextInContext()}")
return sequence {
yield(null) // otherwise explicit receiver won't be checked when there are no implicit receivers in completion position
yieldAll(towerDataContext.implicitReceiverStack)
}
}
}
@@ -0,0 +1,42 @@
/*
* 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDiagnosticsForFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getDiagnostics
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.components.KtDiagnosticCheckerFilter
import org.jetbrains.kotlin.analysis.api.components.KtDiagnosticProvider
import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnosticWithPsi
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
internal class KtFirDiagnosticProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtDiagnosticProvider(), KtFirAnalysisSessionComponent {
override fun getDiagnosticsForElement(
element: KtElement,
filter: KtDiagnosticCheckerFilter
): Collection<KtDiagnosticWithPsi<*>> = withValidityAssertion {
element.getDiagnostics(firResolveState, filter.asLLFilter()).map { it.asKtDiagnostic() }
}
override fun collectDiagnosticsForFile(ktFile: KtFile, filter: KtDiagnosticCheckerFilter): Collection<KtDiagnosticWithPsi<*>> =
ktFile.collectDiagnosticsForFile(firResolveState, filter.asLLFilter()).map { it.asKtDiagnostic() }
private fun KtDiagnosticCheckerFilter.asLLFilter() = when (this) {
KtDiagnosticCheckerFilter.ONLY_COMMON_CHECKERS -> DiagnosticCheckerFilter.ONLY_COMMON_CHECKERS
KtDiagnosticCheckerFilter.ONLY_EXTENDED_CHECKERS -> DiagnosticCheckerFilter.ONLY_EXTENDED_CHECKERS
KtDiagnosticCheckerFilter.EXTENDED_AND_COMMON_CHECKERS -> DiagnosticCheckerFilter.EXTENDED_AND_COMMON_CHECKERS
}
}
@@ -0,0 +1,34 @@
/*
* 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.analysis.api.fir.components
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
import org.jetbrains.kotlin.fir.resolve.transformers.FirWhenExhaustivenessTransformer
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.api.components.KtExpressionInfoProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.KtWhenExpression
internal class KtFirExpressionInfoProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtExpressionInfoProvider(), KtFirAnalysisSessionComponent {
override fun getReturnExpressionTargetSymbol(returnExpression: KtReturnExpression): KtCallableSymbol? {
val fir = returnExpression.getOrBuildFirSafe<FirReturnExpression>(firResolveState) ?: return null
val firTargetSymbol = fir.target.labeledElement
return firSymbolBuilder.callableBuilder.buildCallableSymbol(firTargetSymbol)
}
override fun getWhenMissingCases(whenExpression: KtWhenExpression): List<WhenMissingCase> {
val firWhenExpression = whenExpression.getOrBuildFirSafe<FirWhenExpression>(analysisSession.firResolveState) ?: return emptyList()
return FirWhenExhaustivenessTransformer.computeAllMissingCases(analysisSession.firResolveState.rootModuleSession, firWhenExpression)
}
}
@@ -0,0 +1,224 @@
/*
* 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.analysis.api.fir.components
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirLabel
import org.jetbrains.kotlin.fir.FirPackageDirective
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.constructFunctionalType
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.api.components.KtExpressionTypeProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.utils.getReferencedElementType
import org.jetbrains.kotlin.analysis.api.fir.utils.unwrap
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtClassErrorType
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
internal class KtFirExpressionTypeProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtExpressionTypeProvider(), KtFirAnalysisSessionComponent {
override fun getKtExpressionType(expression: KtExpression): KtType? = withValidityAssertion {
when (val fir = expression.unwrap().getOrBuildFir(firResolveState)) {
is FirExpression -> fir.typeRef.coneType.asKtType()
is FirNamedReference -> fir.getReferencedElementType(firResolveState).asKtType()
is FirStatement -> with(analysisSession) { builtinTypes.UNIT }
is FirTypeRef, is FirImport, is FirPackageDirective, is FirLabel -> null
else -> error("Unexpected ${fir?.let { it::class }} for ${expression::class} with text `${expression.text}`")
}
}
override fun getReturnTypeForKtDeclaration(declaration: KtDeclaration): KtType = withValidityAssertion {
val firDeclaration = declaration.getOrBuildFirOfType<FirCallableDeclaration>(firResolveState)
firDeclaration.returnTypeRef.coneType.asKtType()
}
override fun getFunctionalTypeForKtFunction(declaration: KtFunction): KtType = withValidityAssertion {
val firFunction = declaration.getOrBuildFirOfType<FirFunction>(firResolveState)
firFunction.constructFunctionalType(firFunction.isSuspend).asKtType()
}
override fun getExpectedType(expression: PsiElement): KtType? {
val unwrapped = expression.unwrap()
val expectedType = getExpectedTypeByReturnExpression(unwrapped)
?: getExpressionTypeByIfOrBooleanCondition(unwrapped)
?: getExpectedTypeByTypeCast(unwrapped)
?: getExpectedTypeOfFunctionParameter(unwrapped)
?: getExpectedTypeOfInfixFunctionParameter(unwrapped)
?: getExpectedTypeByVariableAssignment(unwrapped)
?: getExpectedTypeByPropertyDeclaration(unwrapped)
?: getExpectedTypeByFunctionExpressionBody(unwrapped)
return expectedType.takeIf { it !is KtClassErrorType }
}
private fun getExpectedTypeByTypeCast(expression: PsiElement): KtType? {
val typeCastExpression =
expression.unwrapQualified<KtBinaryExpressionWithTypeRHS> { castExpr, expr -> castExpr.left == expr } ?: return null
with(analysisSession) {
return typeCastExpression.right?.getKtType()
}
}
private fun getExpectedTypeOfFunctionParameter(expression: PsiElement): KtType? {
val (ktCallExpression, argumentExpression) = expression.getFunctionCallAsWithThisAsParameter() ?: return null
val firCall = ktCallExpression.getOrBuildFirSafe<FirFunctionCall>(firResolveState) ?: return null
val callee = (firCall.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol
if (callee?.fir?.origin == FirDeclarationOrigin.SamConstructor) {
return (callee.fir as FirSimpleFunction).returnTypeRef.coneType.asKtType()
}
val arguments = firCall.argumentMapping ?: return null
val firParameterForExpression =
arguments.entries.firstOrNull { (arg, _) ->
when (arg) {
// TODO: better to utilize. See `createArgumentMapping` in [KtFirCallResolver]
is FirLambdaArgumentExpression, is FirNamedArgumentExpression, is FirSpreadArgumentExpression ->
arg.psi == argumentExpression.parent
else ->
arg.psi == argumentExpression
}
}?.value ?: return null
return firParameterForExpression.returnTypeRef.coneType.asKtType()
}
private fun PsiElement.getFunctionCallAsWithThisAsParameter(): KtCallWithArgument? {
val valueArgument = unwrapQualified<KtValueArgument> { valueArg, expr -> valueArg.getArgumentExpression() == expr } ?: return null
val callExpression =
(valueArgument.parent as? KtValueArgumentList)?.parent as? KtCallExpression
?: valueArgument.parent as? KtCallExpression // KtLambdaArgument
?: return null
val argumentExpression = valueArgument.getArgumentExpression() ?: return null
return KtCallWithArgument(callExpression, argumentExpression)
}
private fun getExpectedTypeOfInfixFunctionParameter(expression: PsiElement): KtType? {
val infixCallExpression =
expression.unwrapQualified<KtBinaryExpression> { binaryExpr, expr -> binaryExpr.right == expr } ?: return null
val firCall = infixCallExpression.getOrBuildFirSafe<FirFunctionCall>(firResolveState) ?: return null
// There is only one parameter for infix functions; get its type
val arguments = firCall.argumentMapping ?: return null
val firParameterForExpression = arguments.values.singleOrNull() ?: return null
return firParameterForExpression.returnTypeRef.coneType.asKtType()
}
private fun getExpectedTypeByReturnExpression(expression: PsiElement): KtType? {
val returnParent = expression.getReturnExpressionWithThisType() ?: return null
val targetSymbol = with(analysisSession) { returnParent.getReturnTargetSymbol() } ?: return null
return targetSymbol.annotatedType.type
}
private fun PsiElement.getReturnExpressionWithThisType(): KtReturnExpression? =
unwrapQualified { returnExpr, target -> returnExpr.returnedExpression == target }
private fun getExpressionTypeByIfOrBooleanCondition(expression: PsiElement): KtType? = when {
expression.isWhileLoopCondition() || expression.isIfCondition() -> with(analysisSession) { builtinTypes.BOOLEAN }
else -> null
}
private fun getExpectedTypeByVariableAssignment(expression: PsiElement): KtType? {
// Given: `x = expression`
// Expected type of `expression` is type of `x`
val assignmentExpression =
expression.unwrapQualified<KtBinaryExpression> { binaryExpr, expr -> binaryExpr.right == expr && binaryExpr.operationToken == KtTokens.EQ }
?: return null
val variableExpression = assignmentExpression.left as? KtNameReferenceExpression ?: return null
return getKtExpressionType(variableExpression)
}
private fun getExpectedTypeByPropertyDeclaration(expression: PsiElement): KtType? {
// Given: `val x: T = expression`
// Expected type of `expression` is `T`
val property = expression.unwrapQualified<KtProperty> { property, expr -> property.initializer == expr } ?: return null
return getReturnTypeForKtDeclaration(property)
}
private fun getExpectedTypeByFunctionExpressionBody(expression: PsiElement): KtType? {
// Given: `fun f(): T = expression`
// Expected type of `expression` is `T`
val function = expression.unwrapQualified<KtFunction> { function, expr -> function.bodyExpression == expr } ?: return null
if (function.bodyBlockExpression != null) {
// Given `fun f(...): R { blockExpression }`, `{ blockExpression }` is mapped to the enclosing anonymous function,
// which may raise an exception if we attempt to retrieve, e.g., callable declaration from it.
return null
}
return getReturnTypeForKtDeclaration(function)
}
private fun PsiElement.isWhileLoopCondition() =
unwrapQualified<KtWhileExpressionBase> { whileExpr, cond -> whileExpr.condition == cond } != null
private fun PsiElement.isIfCondition() =
unwrapQualified<KtIfExpression> { ifExpr, cond -> ifExpr.condition == cond } != null
override fun isDefinitelyNull(expression: KtExpression): Boolean =
getDefiniteNullability(expression) == DefiniteNullability.DEFINITELY_NULL
override fun isDefinitelyNotNull(expression: KtExpression): Boolean =
getDefiniteNullability(expression) == DefiniteNullability.DEFINITELY_NOT_NULL
private fun getDefiniteNullability(expression: KtExpression): DefiniteNullability = withValidityAssertion {
fun FirExpression.isNotNullable() = with(analysisSession.rootModuleSession.typeContext) {
!typeRef.coneType.isNullableType()
}
when (val fir = expression.getOrBuildFir(analysisSession.firResolveState)) {
is FirExpressionWithSmartcastToNull -> if (fir.isStable) {
return DefiniteNullability.DEFINITELY_NULL
}
is FirExpressionWithSmartcast -> if (fir.isStable && fir.isNotNullable()) {
return DefiniteNullability.DEFINITELY_NOT_NULL
}
is FirExpression -> if (fir.isNotNullable()) {
return DefiniteNullability.DEFINITELY_NOT_NULL
}
}
return DefiniteNullability.UNKNOWN
}
}
private data class KtCallWithArgument(val call: KtCallExpression, val argument: KtExpression)
private inline fun <reified R : Any> PsiElement.unwrapQualified(check: (R, PsiElement) -> Boolean): R? {
val parent = nonContainerParent
return when {
parent is R && check(parent, this) -> parent
parent is KtQualifiedExpression && parent.selectorExpression == this -> {
val grandParent = parent.nonContainerParent
when {
grandParent is R && check(grandParent, parent) -> grandParent
else -> null
}
}
else -> null
}
}
private val PsiElement.nonContainerParent: PsiElement?
get() = when (val parent = parent) {
is KtContainerNode -> parent.parent
else -> parent
}
private enum class DefiniteNullability { DEFINITELY_NULL, DEFINITELY_NOT_NULL, UNKNOWN }
@@ -0,0 +1,387 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.realPsi
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.symbols.ensureResolved
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
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.visitors.FirVisitorVoid
import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.api.assertIsValidAndAccessible
import org.jetbrains.kotlin.analysis.api.components.KtImportOptimizer
import org.jetbrains.kotlin.analysis.api.components.KtImportOptimizerResult
import org.jetbrains.kotlin.analysis.api.fir.utils.computeImportableName
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.parentOrNull
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getCallNameExpression
import org.jetbrains.kotlin.psi.psiUtil.getPossiblyQualifiedCallExpression
import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.util.OperatorNameConventions
internal class KtFirImportOptimizer(
override val token: ValidityToken,
private val firResolveState: FirModuleResolveState
) : KtImportOptimizer() {
private val firSession: FirSession
get() = firResolveState.rootModuleSession
override fun analyseImports(file: KtFile): KtImportOptimizerResult {
assertIsValidAndAccessible()
val firFile = file.getOrBuildFirFile(firResolveState).apply { ensureResolved(FirResolvePhase.BODY_RESOLVE) }
val existingImports = file.importDirectives
val explicitlyImportedFqNames = existingImports
.asSequence()
.mapNotNull { it.importPath }
.filter { !it.isAllUnder && !it.hasAlias() }
.map { it.fqName }
.toSet()
val referencesEntities = collectReferencedEntities(firFile)
.filterNot { (fqName, referencedByNames) ->
// when referenced by more than one name, we need to keep the imports with same package
fqName.parentOrNull() == file.packageFqName && referencedByNames.size == 1
}
val requiredStarImports = referencesEntities.keys
.asSequence()
.filterNot { it in explicitlyImportedFqNames }
.mapNotNull { it.parentOrNull() }
.filterNot { it.isRoot }
.toSet()
val unusedImports = mutableSetOf<KtImportDirective>()
val alreadySeenImports = mutableSetOf<ImportPath>()
for (import in existingImports) {
val importPath = import.importPath ?: continue
val isUsed = when {
!alreadySeenImports.add(importPath) -> false
importPath.isAllUnder -> importPath.fqName in requiredStarImports
importPath.fqName in referencesEntities -> importPath.importedName in referencesEntities.getValue(importPath.fqName)
else -> false
}
if (!isUsed) {
unusedImports += import
}
}
return KtImportOptimizerResult(unusedImports)
}
private fun collectReferencedEntities(firFile: FirFile): Map<FqName, Set<Name>> {
val usedImports = mutableMapOf<FqName, MutableSet<Name>>()
firFile.accept(object : FirVisitorVoid() {
override fun visitElement(element: FirElement) {
element.acceptChildren(this)
}
override fun visitFunctionCall(functionCall: FirFunctionCall) {
processFunctionCall(functionCall)
super.visitFunctionCall(functionCall)
}
override fun visitImplicitInvokeCall(implicitInvokeCall: FirImplicitInvokeCall) {
processImplicitFunctionCall(implicitInvokeCall)
super.visitImplicitInvokeCall(implicitInvokeCall)
}
override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression) {
processPropertyAccessExpression(propertyAccessExpression)
super.visitPropertyAccessExpression(propertyAccessExpression)
}
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef) {
processTypeRef(resolvedTypeRef)
super.visitTypeRef(resolvedTypeRef)
}
override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef) {
processTypeRef(errorTypeRef)
super.visitErrorTypeRef(errorTypeRef)
}
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess) {
processCallableReferenceAccess(callableReferenceAccess)
super.visitCallableReferenceAccess(callableReferenceAccess)
}
override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier) {
processResolvedQualifier(resolvedQualifier)
super.visitResolvedQualifier(resolvedQualifier)
}
override fun visitErrorResolvedQualifier(errorResolvedQualifier: FirErrorResolvedQualifier) {
processResolvedQualifier(errorResolvedQualifier)
super.visitErrorResolvedQualifier(errorResolvedQualifier)
}
private fun processFunctionCall(functionCall: FirFunctionCall) {
if (functionCall.isFullyQualified) return
val referencesByName = functionCall.functionReferenceName ?: return
val functionSymbol = functionCall.referencedCallableSymbol ?: return
saveCallable(functionSymbol, referencesByName)
}
private fun processImplicitFunctionCall(implicitInvokeCall: FirImplicitInvokeCall) {
val functionSymbol = implicitInvokeCall.referencedCallableSymbol ?: return
saveCallable(functionSymbol, OperatorNameConventions.INVOKE)
}
private fun processPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression) {
if (propertyAccessExpression.isFullyQualified) return
val referencedByName = propertyAccessExpression.propertyReferenceName ?: return
val propertySymbol = propertyAccessExpression.referencedCallableSymbol ?: return
saveCallable(propertySymbol, referencedByName)
}
private fun processTypeRef(resolvedTypeRef: FirResolvedTypeRef) {
val wholeQualifier = TypeQualifier.createFor(resolvedTypeRef) ?: return
processTypeQualifier(wholeQualifier)
}
private fun processCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess) {
if (callableReferenceAccess.isFullyQualified) return
val referencedByName = callableReferenceAccess.callableReferenceName ?: return
val resolvedSymbol = callableReferenceAccess.referencedCallableSymbol ?: return
saveCallable(resolvedSymbol, referencedByName)
}
private fun processResolvedQualifier(resolvedQualifier: FirResolvedQualifier) {
val wholeQualifier = TypeQualifier.createFor(resolvedQualifier) ?: return
processTypeQualifier(wholeQualifier)
}
private fun processTypeQualifier(qualifier: TypeQualifier) {
val mostOuterTypeQualifier = generateSequence(qualifier) { it.outerTypeQualifier }.last()
if (mostOuterTypeQualifier.isQualified) return
saveType(mostOuterTypeQualifier)
}
private fun saveType(qualifier: TypeQualifier) {
val importableName = qualifier.referencedClassId.asSingleFqName()
val referencedByName = qualifier.referencedByName
saveReferencedItem(importableName, referencedByName)
}
private fun saveCallable(resolvedSymbol: FirCallableSymbol<*>, referencedByName: Name) {
val importableName = resolvedSymbol.computeImportableName(firSession) ?: return
saveReferencedItem(importableName, referencedByName)
}
private fun saveReferencedItem(importableName: FqName, referencedByName: Name) {
usedImports.getOrPut(importableName) { hashSetOf() } += referencedByName
}
})
return usedImports
}
}
/**
* An actual name by which this callable reference were used.
*/
private val FirCallableReferenceAccess.callableReferenceName: Name?
get() {
toResolvedCallableReference()?.let { return it.name }
val wholeCallableReferenceExpression = realPsi as? KtCallableReferenceExpression
return wholeCallableReferenceExpression?.callableReference?.getReferencedNameAsName()
}
/**
* A name by which referenced functions was called.
*/
private val FirFunctionCall.functionReferenceName: Name?
get() {
toResolvedCallableReference()?.let { return it.name }
// unresolved reference has incorrect name, so we have to retrieve it by PSI
val wholeCallExpression = realPsi as? KtExpression
val callExpression = wholeCallExpression?.getPossiblyQualifiedCallExpression()
return callExpression?.getCallNameExpression()?.getReferencedNameAsName()
}
/**
* A name by which referenced property is used.
*/
private val FirPropertyAccessExpression.propertyReferenceName: Name?
get() {
toResolvedCallableReference()?.let { return it.name }
// unresolved reference has incorrect name, so we have to retrieve it by PSI
val wholePropertyAccessExpression = realPsi as? KtExpression
val propertyNameExpression = wholePropertyAccessExpression?.getPossiblyQualifiedSimpleNameExpression()
return propertyNameExpression?.getReferencedNameAsName()
}
/**
* Referenced callable symbol, even if it not completely correctly resolved.
*/
private val FirQualifiedAccessExpression.referencedCallableSymbol: FirCallableSymbol<*>?
get() {
return toResolvedCallableSymbol()
?: (calleeReference as? FirNamedReference)?.candidateSymbol as? FirCallableSymbol<*>
}
/**
* Referenced [ClassId], even if it is not completely correctly resolved.
*/
private val FirResolvedTypeRef.resolvedClassId: ClassId?
get() {
if (this !is FirErrorTypeRef) return type.classId
val candidateSymbols = diagnostic.getCandidateSymbols()
val singleClassSymbol = candidateSymbols.singleOrNull() as? FirClassLikeSymbol
return singleClassSymbol?.classId
}
private val FirQualifiedAccessExpression.isFullyQualified: Boolean
get() = explicitReceiver is FirResolvedQualifier
private fun KtExpression.getPossiblyQualifiedSimpleNameExpression(): KtSimpleNameExpression? {
return ((this as? KtQualifiedExpression)?.selectorExpression ?: this) as? KtSimpleNameExpression?
}
/**
* Helper abstraction to navigate through qualified FIR elements - we have to match [ClassId] and PSI qualifier pair
* to correctly reason about long qualifiers.
*/
private sealed interface TypeQualifier {
val referencedClassId: ClassId
/**
* Type can be imported with alias, and thus can be referenced by the name different from its actual name.
*
* We cannot use [ClassId.getShortClassName] for this, since it is not affected by the alias.
*/
val referencedByName: Name
/**
* Must be `true` if the PSI qualifier is itself qualified with the package or some other type, and `false` otherwise.
*
* ```
* foo.bar.Baz -> true
* Baz.Type -> true
* Baz -> false
* ```
*/
val isQualified: Boolean
val outerTypeQualifier: TypeQualifier?
private class KtDotExpressionTypeQualifier(
override val referencedClassId: ClassId,
qualifier: KtElement,
) : TypeQualifier {
private val dotQualifier: KtDotQualifiedExpression? = qualifier as? KtDotQualifiedExpression
private val typeNameReference: KtNameReferenceExpression = when (qualifier) {
is KtDotQualifiedExpression -> qualifier.selectorExpression as? KtNameReferenceExpression
is KtNameReferenceExpression -> qualifier
else -> null
} ?: error("Cannot get referenced name from '${qualifier.text}'")
override val referencedByName: Name
get() = typeNameReference.getReferencedNameAsName()
override val isQualified: Boolean
get() = dotQualifier != null
override val outerTypeQualifier: TypeQualifier?
get() {
val outerClassId = referencedClassId.outerClassId ?: return null
val outerQualifier = dotQualifier?.receiverExpression ?: return null
return KtDotExpressionTypeQualifier(outerClassId, outerQualifier)
}
}
private class KtUserTypeQualifier(
override val referencedClassId: ClassId,
private val qualifier: KtUserType,
) : TypeQualifier {
override val referencedByName: Name
get() = qualifier.referenceExpression?.getReferencedNameAsName()
?: error("Cannot get referenced name from '${qualifier.text}'")
override val isQualified: Boolean
get() = qualifier.qualifier != null
override val outerTypeQualifier: TypeQualifier?
get() {
val outerClassId = referencedClassId.outerClassId ?: return null
val outerQualifier = qualifier.qualifier ?: return null
return KtUserTypeQualifier(outerClassId, outerQualifier)
}
}
companion object {
fun createFor(qualifier: FirResolvedQualifier): TypeQualifier? {
val wholeClassId = qualifier.classId ?: return null
val psi = qualifier.psi as? KtExpression ?: return null
val wholeQualifier = when (psi) {
is KtDotQualifiedExpression -> psi
is KtNameReferenceExpression -> psi.getDotQualifiedExpressionForSelector() ?: psi
else -> psi
}
return KtDotExpressionTypeQualifier(wholeClassId, wholeQualifier)
}
fun createFor(typeRef: FirResolvedTypeRef): TypeQualifier? {
val wholeClassId = typeRef.resolvedClassId ?: return null
val psi = typeRef.psi as? KtTypeReference ?: return null
val wholeUserType = psi.typeElement?.unwrapNullability() as? KtUserType ?: return null
return KtUserTypeQualifier(wholeClassId, wholeUserType)
}
}
}
@@ -0,0 +1,45 @@
/*
* 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.analysis.api.fir.components
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.declarations.getSealedClassInheritors
import org.jetbrains.kotlin.analysis.api.components.KtInheritorsProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind
import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
internal class KtFirInheritorsProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtInheritorsProvider(), KtFirAnalysisSessionComponent {
override fun getInheritorsOfSealedClass(
classSymbol: KtNamedClassOrObjectSymbol
): List<KtNamedClassOrObjectSymbol> = withValidityAssertion {
require(classSymbol.modality == Modality.SEALED)
require(classSymbol is KtFirNamedClassOrObjectSymbol)
val inheritorClassIds = classSymbol.firRef.withFir { fir ->
fir.getSealedClassInheritors(analysisSession.rootModuleSession)
}
with(analysisSession) {
inheritorClassIds.mapNotNull { it.getCorrespondingToplevelClassOrObjectSymbol() as? KtNamedClassOrObjectSymbol }
}
}
override fun getEnumEntries(classSymbol: KtNamedClassOrObjectSymbol): List<KtEnumEntrySymbol> = withValidityAssertion {
require(classSymbol.classKind == KtClassKind.ENUM_CLASS)
with(analysisSession) {
classSymbol.getDeclaredMemberScope().getCallableSymbols().filterIsInstance<KtEnumEntrySymbol>().toList()
}
}
}
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.backend.jvm.jvmTypeMapper
import org.jetbrains.kotlin.analysis.api.components.KtJvmTypeMapper
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.org.objectweb.asm.Type
internal class KtFirJvmTypeMapper(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtJvmTypeMapper(), KtFirAnalysisSessionComponent {
override fun mapTypeToJvmType(type: KtType, mode: TypeMappingMode): Type {
return analysisSession.rootModuleSession.jvmTypeMapper.mapType(type.coneType, mode)
}
}
@@ -0,0 +1,129 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.components
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiType
import com.intellij.psi.impl.cache.TypeInfo
import com.intellij.psi.impl.compiled.ClsTypeElementImpl
import com.intellij.psi.impl.compiled.SignatureParsing
import com.intellij.psi.impl.compiled.StubBuildingVisitor
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.jvm.jvmTypeMapper
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.withFirDeclaration
import org.jetbrains.kotlin.analysis.api.components.KtPsiTypeProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.types.PublicTypeApproximator
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import java.text.StringCharacterIterator
internal class KtFirPsiTypeProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtPsiTypeProvider(), KtFirAnalysisSessionComponent {
override fun asPsiType(
type: KtType,
context: PsiElement,
mode: TypeMappingMode,
): PsiType? = withValidityAssertion {
type.coneType.asPsiType(rootModuleSession, analysisSession.firResolveState, mode, context)
}
}
private fun ConeKotlinType.simplifyType(session: FirSession, state: FirModuleResolveState): ConeKotlinType {
val substitutor = AnonymousTypesSubstitutor(session, state)
var currentType = this
do {
val oldType = currentType
currentType = currentType.fullyExpandedType(session)
currentType = currentType.upperBoundIfFlexible()
currentType = substitutor.substituteOrSelf(currentType)
currentType = PublicTypeApproximator.approximateTypeToPublicDenotable(currentType, session) ?: currentType
} while (oldType !== currentType)
return currentType
}
internal fun ConeKotlinType.asPsiType(
session: FirSession,
state: FirModuleResolveState,
mode: TypeMappingMode,
psiContext: PsiElement,
): PsiType? {
val correctedType = simplifyType(session, state)
if (correctedType is ConeClassErrorType || correctedType !is SimpleTypeMarker) return null
if (correctedType.typeArguments.any { it is ConeClassErrorType }) return null
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS)
//TODO Check thread safety
session.jvmTypeMapper.mapType(correctedType, mode, signatureWriter)
val canonicalSignature = signatureWriter.toString()
if (canonicalSignature.contains("L<error>")) return null
require(!canonicalSignature.contains(SpecialNames.ANONYMOUS_STRING))
val signature = StringCharacterIterator(canonicalSignature)
val javaType = SignatureParsing.parseTypeString(signature, StubBuildingVisitor.GUESSING_MAPPER)
val typeInfo = TypeInfo.fromString(javaType, false)
val typeText = TypeInfo.createTypeText(typeInfo) ?: return null
val typeElement = ClsTypeElementImpl(psiContext, typeText, '\u0000')
return typeElement.type
}
private class AnonymousTypesSubstitutor(
private val session: FirSession,
private val state: FirModuleResolveState,
) : AbstractConeSubstitutor(session.typeContext) {
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
if (type !is ConeClassLikeType) return null
val isAnonymous = type.classId.let { it?.shortClassName?.asString() == SpecialNames.ANONYMOUS_STRING }
if (!isAnonymous) return null
fun ConeClassLikeType.isNotInterface(): Boolean {
val firClassNode = lookupTag.toSymbol(session)?.fir as? FirClass ?: return false
return firClassNode.withFirDeclaration(state) { firSuperClass ->
firSuperClass.classKind != ClassKind.INTERFACE
}
}
val firClassNode = (type.lookupTag.toSymbol(session) as? FirClassSymbol)?.fir
if (firClassNode != null) {
val superTypesCones = firClassNode.withFirDeclaration(state, FirResolvePhase.SUPER_TYPES) {
(it as? FirClass)?.superConeTypes
}
val superClass = superTypesCones?.firstOrNull { it.isNotInterface() }
if (superClass != null) return superClass
}
return if (type.nullability.isNullable) session.builtinTypes.nullableAnyType.type
else session.builtinTypes.anyType.type
}
}
@@ -0,0 +1,629 @@
/*
* 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.analysis.api.fir.components
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.TextRange
import com.intellij.psi.SmartPsiElementPointer
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvedImport
import org.jetbrains.kotlin.fir.declarations.builder.buildImport
import org.jetbrains.kotlin.fir.declarations.builder.buildResolvedImport
import org.jetbrains.kotlin.fir.expressions.FirErrorResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.resolve.transformers.resolveToPackageOrClass
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.getFunctions
import org.jetbrains.kotlin.fir.scopes.getProperties
import org.jetbrains.kotlin.fir.scopes.impl.*
import org.jetbrains.kotlin.fir.scopes.processClassifiersByName
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.types.lowerBoundIfFlexible
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.parentsOfType
import org.jetbrains.kotlin.analysis.api.components.KtReferenceShortener
import org.jetbrains.kotlin.analysis.api.components.ShortenCommand
import org.jetbrains.kotlin.analysis.api.components.ShortenOption
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.utils.addImportToFile
import org.jetbrains.kotlin.analysis.api.fir.utils.computeImportableName
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability
import org.jetbrains.kotlin.utils.addIfNotNull
internal class KtFirReferenceShortener(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
override val firResolveState: FirModuleResolveState,
) : KtReferenceShortener(), KtFirAnalysisSessionComponent {
private val context = FirShorteningContext(firResolveState)
override fun collectShortenings(
file: KtFile,
selection: TextRange,
classShortenOption: (KtClassLikeSymbol) -> ShortenOption,
callableShortenOption: (KtCallableSymbol) -> ShortenOption
): ShortenCommand {
val declarationToVisit = file.findSmallestDeclarationContainingSelection(selection)
?: file.withDeclarationsResolvedToBodyResolve()
val firDeclaration = declarationToVisit.getOrBuildFirOfType<FirDeclaration>(firResolveState)
val towerContext =
LowLevelFirApiFacadeForResolveOnAir.onAirGetTowerContextProvider(firResolveState, declarationToVisit)
//TODO: collect all usages of available symbols in the file and prevent importing symbols that could introduce name clashes, which
// may alter the meaning of existing code.
val collector = ElementsToShortenCollector(
context,
towerContext,
selection,
classShortenOption = { classShortenOption(analysisSession.firSymbolBuilder.buildSymbol(it.fir) as KtClassLikeSymbol) },
callableShortenOption = { callableShortenOption(analysisSession.firSymbolBuilder.buildSymbol(it.fir) as KtCallableSymbol) })
firDeclaration.accept(collector)
return ShortenCommandImpl(
file,
collector.namesToImport.distinct(),
collector.namesToImportWithStar.distinct(),
collector.typesToShorten.distinct().map { it.createSmartPointer() },
collector.qualifiersToShorten.distinct().map { it.createSmartPointer() }
)
}
private fun KtFile.withDeclarationsResolvedToBodyResolve(): KtFile {
for (declaration in declarations) {
declaration.getOrBuildFir(firResolveState) // temporary hack, resolves declaration to BODY_RESOLVE stage
}
return this
}
}
private fun KtFile.findSmallestDeclarationContainingSelection(selection: TextRange): KtDeclaration? =
findElementAt(selection.startOffset)
?.parentsOfType<KtDeclaration>(withSelf = true)
?.firstOrNull { selection in it.textRange }
/**
* How a symbol is imported. The order of the enum entry represents the priority of imports. If a symbol is available from multiple kinds of
* imports, the symbol from "smaller" kind is used. For example, an explicitly imported symbol can overwrite a star-imported symbol.
*/
private enum class ImportKind {
/** The symbol is available from the local scope and hence cannot be imported or overwritten. */
LOCAL,
/** Explicitly imported by user. */
EXPLICIT,
/** Explicitly imported by Kotlin default. For example, `kotlin.String`. */
DEFAULT_EXPLICIT,
/** Implicitly imported from package. */
PACKAGE,
/** Star imported (star import) by user. */
STAR,
/** Star imported (star import) by Kotlin default. */
DEFAULT_STAR;
infix fun hasHigherPriorityThan(that: ImportKind): Boolean = this < that
val canBeOverwrittenByExplicitImport: Boolean get() = DEFAULT_EXPLICIT hasHigherPriorityThan this
companion object {
fun fromScope(scope: FirScope): ImportKind {
return when (scope) {
is FirDefaultStarImportingScope -> DEFAULT_STAR
is FirAbstractStarImportingScope -> STAR
is FirPackageMemberScope -> PACKAGE
is FirDefaultSimpleImportingScope -> DEFAULT_EXPLICIT
is FirAbstractSimpleImportingScope -> EXPLICIT
else -> LOCAL
}
}
}
}
private data class AvailableSymbol<out T>(
val symbol: T,
val importKind: ImportKind,
)
private class FirShorteningContext(val firResolveState: FirModuleResolveState) {
private val firSession: FirSession
get() = firResolveState.rootModuleSession
fun findFirstClassifierInScopesByName(positionScopes: List<FirScope>, targetClassName: Name): AvailableSymbol<ClassId>? {
for (scope in positionScopes) {
val classifierSymbol = scope.findFirstClassifierByName(targetClassName) ?: continue
val classifierLookupTag = classifierSymbol.toLookupTag() as? ConeClassLikeLookupTag ?: continue
return AvailableSymbol(classifierLookupTag.classId, ImportKind.fromScope(scope))
}
return null
}
fun findFunctionsInScopes(scopes: List<FirScope>, name: Name): List<AvailableSymbol<FirNamedFunctionSymbol>> {
return scopes.flatMap { scope ->
val importKind = ImportKind.fromScope(scope)
scope.getFunctions(name).map {
AvailableSymbol(it, importKind)
}
}
}
fun findPropertiesInScopes(scopes: List<FirScope>, name: Name): List<AvailableSymbol<FirVariableSymbol<*>>> {
return scopes.flatMap { scope ->
val importKind = ImportKind.fromScope(scope)
scope.getProperties(name).map {
AvailableSymbol(it, importKind)
}
}
}
private fun FirScope.findFirstClassifierByName(name: Name): FirClassifierSymbol<*>? {
var element: FirClassifierSymbol<*>? = null
processClassifiersByName(name) {
if (element == null) {
element = it
}
}
return element
}
@OptIn(ExperimentalStdlibApi::class)
fun findScopesAtPosition(
position: KtElement,
newImports: List<FqName>,
towerContextProvider: FirTowerContextProvider
): List<FirScope>? {
val towerDataContext = towerContextProvider.getClosestAvailableParentContext(position) ?: return null
val result = buildList<FirScope> {
addAll(towerDataContext.nonLocalTowerDataElements.mapNotNull { it.scope })
addIfNotNull(createFakeImportingScope(newImports))
addAll(towerDataContext.localScopes)
}
return result.asReversed()
}
private fun createFakeImportingScope(newImports: List<FqName>): FirScope? {
val resolvedNewImports = newImports.mapNotNull { createFakeResolvedImport(it) }
if (resolvedNewImports.isEmpty()) return null
return FirExplicitSimpleImportingScope(resolvedNewImports, firSession, ScopeSession())
}
private fun createFakeResolvedImport(fqNameToImport: FqName): FirResolvedImport? {
val packageOrClass = resolveToPackageOrClass(firSession.symbolProvider, fqNameToImport) ?: return null
val delegateImport = buildImport {
importedFqName = fqNameToImport
isAllUnder = false
}
return buildResolvedImport {
delegate = delegateImport
packageFqName = packageOrClass.packageFqName
}
}
fun getRegularClass(typeRef: FirTypeRef): FirRegularClass? {
return typeRef.toRegularClassSymbol(firSession)?.fir
}
fun toClassSymbol(classId: ClassId) =
firSession.symbolProvider.getClassLikeSymbolByClassId(classId)
fun convertToImportableName(callableSymbol: FirCallableSymbol<*>): FqName? =
callableSymbol.computeImportableName(firSession)
}
private sealed class ElementToShorten {
abstract val nameToImport: FqName?
abstract val importAllInParent: Boolean
}
private class ShortenType(
val element: KtUserType,
override val nameToImport: FqName? = null,
override val importAllInParent: Boolean = false
) : ElementToShorten()
private class ShortenQualifier(
val element: KtDotQualifiedExpression,
override val nameToImport: FqName? = null,
override val importAllInParent: Boolean = false
) : ElementToShorten()
private class ElementsToShortenCollector(
private val shorteningContext: FirShorteningContext,
private val towerContextProvider: FirTowerContextProvider,
private val selection: TextRange,
private val classShortenOption: (FirClassLikeSymbol<*>) -> ShortenOption,
private val callableShortenOption: (FirCallableSymbol<*>) -> ShortenOption,
) :
FirVisitorVoid() {
val namesToImport: MutableList<FqName> = mutableListOf()
val namesToImportWithStar: MutableList<FqName> = mutableListOf()
val typesToShorten: MutableList<KtUserType> = mutableListOf()
val qualifiersToShorten: MutableList<KtDotQualifiedExpression> = mutableListOf()
override fun visitElement(element: FirElement) {
element.acceptChildren(this)
}
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef) {
processTypeRef(resolvedTypeRef)
resolvedTypeRef.acceptChildren(this)
resolvedTypeRef.delegatedTypeRef?.accept(this)
}
override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier) {
super.visitResolvedQualifier(resolvedQualifier)
processTypeQualifier(resolvedQualifier)
}
override fun visitErrorResolvedQualifier(errorResolvedQualifier: FirErrorResolvedQualifier) {
super.visitErrorResolvedQualifier(errorResolvedQualifier)
processTypeQualifier(errorResolvedQualifier)
}
override fun visitResolvedNamedReference(resolvedNamedReference: FirResolvedNamedReference) {
super.visitResolvedNamedReference(resolvedNamedReference)
processPropertyReference(resolvedNamedReference)
}
override fun visitFunctionCall(functionCall: FirFunctionCall) {
super.visitFunctionCall(functionCall)
processFunctionCall(functionCall)
}
private fun processTypeRef(resolvedTypeRef: FirResolvedTypeRef) {
val wholeTypeReference = resolvedTypeRef.psi as? KtTypeReference ?: return
if (!wholeTypeReference.textRange.intersects(selection)) return
val wholeClassifierId = resolvedTypeRef.type.lowerBoundIfFlexible().classId ?: return
val wholeTypeElement = wholeTypeReference.typeElement?.unwrapNullability() as? KtUserType ?: return
if (wholeTypeElement.qualifier == null) return
findTypeToShorten(wholeClassifierId, wholeTypeElement)?.let(::addElementToShorten)
}
private fun findTypeToShorten(wholeClassifierId: ClassId, wholeTypeElement: KtUserType): ElementToShorten? {
val positionScopes = shorteningContext.findScopesAtPosition(wholeTypeElement, namesToImport, towerContextProvider) ?: return null
val allClassIds = wholeClassifierId.outerClassesWithSelf
val allQualifiedTypeElements = wholeTypeElement.qualifiedTypesWithSelf
return findClassifierElementsToShorten(
positionScopes,
allClassIds,
allQualifiedTypeElements,
::ShortenType,
this::findFakePackageToShorten
)
}
private fun findFakePackageToShorten(typeElement: KtUserType): ShortenType? {
val deepestTypeWithQualifier = typeElement.qualifiedTypesWithSelf.last()
return if (deepestTypeWithQualifier.hasFakeRootPrefix()) ShortenType(deepestTypeWithQualifier) else null
}
private fun processTypeQualifier(resolvedQualifier: FirResolvedQualifier) {
val wholeClassQualifier = resolvedQualifier.classId ?: return
val qualifierPsi = resolvedQualifier.psi ?: return
if (!qualifierPsi.textRange.intersects(selection)) return
val wholeQualifierElement = when (qualifierPsi) {
is KtDotQualifiedExpression -> qualifierPsi
is KtNameReferenceExpression -> qualifierPsi.getDotQualifiedExpressionForSelector() ?: return
else -> return
}
findTypeQualifierToShorten(wholeClassQualifier, wholeQualifierElement)?.let(::addElementToShorten)
}
private fun findTypeQualifierToShorten(
wholeClassQualifier: ClassId,
wholeQualifierElement: KtDotQualifiedExpression
): ElementToShorten? {
val positionScopes: List<FirScope> =
shorteningContext.findScopesAtPosition(wholeQualifierElement, namesToImport, towerContextProvider) ?: return null
val allClassIds: Sequence<ClassId> = wholeClassQualifier.outerClassesWithSelf
val allQualifiers: Sequence<KtDotQualifiedExpression> = wholeQualifierElement.qualifiedExpressionsWithSelf
return findClassifierElementsToShorten(
positionScopes,
allClassIds,
allQualifiers,
::ShortenQualifier,
this::findFakePackageToShorten
)
}
private inline fun <E> findClassifierElementsToShorten(
positionScopes: List<FirScope>,
allClassIds: Sequence<ClassId>,
allQualifiedElements: Sequence<E>,
createElementToShorten: (E, nameToImport: FqName?, importAllInParent: Boolean) -> ElementToShorten,
findFakePackageToShortenFn: (E) -> ElementToShorten?,
): ElementToShorten? {
for ((classId, element) in allClassIds.zip(allQualifiedElements)) {
val option = classShortenOption(shorteningContext.toClassSymbol(classId) ?: return null)
if (option == ShortenOption.DO_NOT_SHORTEN) continue
// Find class with the same name that's already available in this file.
val availableClassifier = shorteningContext.findFirstClassifierInScopesByName(positionScopes, classId.shortClassName)
when {
// No class with name `classId.shortClassName` is present in the scope. Hence, we can safely import the name and shorten
// the reference.
availableClassifier == null -> {
// Caller indicates don't shorten if doing that needs importing more names. Hence, we just skip.
if (option == ShortenOption.SHORTEN_IF_ALREADY_IMPORTED) continue
return createElementToShorten(
element,
classId.asSingleFqName(),
option == ShortenOption.SHORTEN_AND_STAR_IMPORT
)
}
// The class with name `classId.shortClassName` happens to be the same class referenced by this qualified access.
availableClassifier.symbol == classId -> {
// Respect caller's request to use star import, if it's not already star-imported.
return when {
availableClassifier.importKind == ImportKind.EXPLICIT && option == ShortenOption.SHORTEN_AND_STAR_IMPORT -> {
createElementToShorten(element, classId.asSingleFqName(), true)
}
// Otherwise, just shorten it and don't alter import statements
else -> createElementToShorten(element, null, false)
}
}
// Allow using star import to overwrite members implicitly imported by default.
availableClassifier.importKind == ImportKind.DEFAULT_STAR && option == ShortenOption.SHORTEN_AND_STAR_IMPORT -> {
return createElementToShorten(element, classId.asSingleFqName(), true)
}
// Allow using explicit import to overwrite members star-imported or in package
availableClassifier.importKind.canBeOverwrittenByExplicitImport && option == ShortenOption.SHORTEN_AND_IMPORT -> {
return createElementToShorten(element, classId.asSingleFqName(), false)
}
}
}
return findFakePackageToShortenFn(allQualifiedElements.last())
}
private fun processPropertyReference(resolvedNamedReference: FirResolvedNamedReference) {
val referenceExpression = resolvedNamedReference.psi as? KtNameReferenceExpression ?: return
if (!referenceExpression.textRange.intersects(selection)) return
val qualifiedProperty = referenceExpression.getDotQualifiedExpressionForSelector() ?: return
val callableSymbol = resolvedNamedReference.resolvedSymbol as? FirCallableSymbol<*> ?: return
processCallableQualifiedAccess(callableSymbol, qualifiedProperty, qualifiedProperty, shorteningContext::findPropertiesInScopes)
}
private fun processFunctionCall(functionCall: FirFunctionCall) {
if (!canBePossibleToDropReceiver(functionCall)) return
val qualifiedCallExpression = functionCall.psi as? KtDotQualifiedExpression ?: return
if (!qualifiedCallExpression.textRange.intersects(selection)) return
val callExpression = qualifiedCallExpression.selectorExpression as? KtCallExpression ?: return
val calleeReference = functionCall.calleeReference
val calledSymbol = findUnambiguousReferencedCallableId(calleeReference) ?: return
processCallableQualifiedAccess(calledSymbol, qualifiedCallExpression, callExpression, shorteningContext::findFunctionsInScopes)
}
private fun processCallableQualifiedAccess(
calledSymbol: FirCallableSymbol<*>,
qualifiedCallExpression: KtDotQualifiedExpression,
expressionToGetScope: KtExpression,
findCallableInScopes: (List<FirScope>, Name) -> List<AvailableSymbol<FirCallableSymbol<*>>>,
) {
val option = callableShortenOption(calledSymbol)
if (option == ShortenOption.DO_NOT_SHORTEN) return
val scopes = shorteningContext.findScopesAtPosition(expressionToGetScope, namesToImport, towerContextProvider) ?: return
val availableCallables = findCallableInScopes(scopes, calledSymbol.name)
val nameToImport = shorteningContext.convertToImportableName(calledSymbol)
val (matchedCallables, otherCallables) = availableCallables.partition { it.symbol.callableId == calledSymbol.callableId }
val callToShorten = when {
// TODO: instead of allowing import only if the other callables are all with kind `DEFAULT_STAR`, we should allow import if
// the requested import kind has higher priority than the available symbols.
otherCallables.all { it.importKind == ImportKind.DEFAULT_STAR } -> {
when {
matchedCallables.isEmpty() -> {
if (nameToImport == null || option == ShortenOption.SHORTEN_IF_ALREADY_IMPORTED) return
ShortenQualifier(
qualifiedCallExpression,
nameToImport,
importAllInParent = option == ShortenOption.SHORTEN_AND_STAR_IMPORT
)
}
// Respect caller's request to star import this symbol.
matchedCallables.any { it.importKind == ImportKind.EXPLICIT } && option == ShortenOption.SHORTEN_AND_STAR_IMPORT ->
ShortenQualifier(qualifiedCallExpression, nameToImport, importAllInParent = true)
else -> ShortenQualifier(qualifiedCallExpression)
}
}
else -> findFakePackageToShorten(qualifiedCallExpression)
}
callToShorten?.let(::addElementToShorten)
}
private fun canBePossibleToDropReceiver(functionCall: FirFunctionCall): Boolean {
// we can remove receiver only if it is a qualifier
val explicitReceiver = functionCall.explicitReceiver as? FirResolvedQualifier ?: return false
// if there is no extension receiver necessary, then it can be removed
if (functionCall.extensionReceiver is FirNoReceiverExpression) return true
val receiverType = shorteningContext.getRegularClass(explicitReceiver.typeRef) ?: return true
return receiverType.classKind != ClassKind.OBJECT
}
private fun findUnambiguousReferencedCallableId(namedReference: FirNamedReference): FirCallableSymbol<*>? {
val unambiguousSymbol = when (namedReference) {
is FirResolvedNamedReference -> namedReference.resolvedSymbol
is FirErrorNamedReference -> {
val candidateSymbol = namedReference.candidateSymbol
if (candidateSymbol !is FirErrorFunctionSymbol) {
candidateSymbol
} else {
getSingleUnambiguousCandidate(namedReference)
}
}
else -> null
}
return (unambiguousSymbol as? FirCallableSymbol<*>)
}
/**
* If [namedReference] is ambiguous and all candidates point to the callables with same callableId,
* returns the first candidate; otherwise returns null.
*/
private fun getSingleUnambiguousCandidate(namedReference: FirErrorNamedReference): FirCallableSymbol<*>? {
val coneAmbiguityError = namedReference.diagnostic as? ConeAmbiguityError ?: return null
val candidates = coneAmbiguityError.candidates.map { it.symbol as FirCallableSymbol<*> }
require(candidates.isNotEmpty()) { "Cannot have zero candidates" }
val distinctCandidates = candidates.distinctBy { it.callableId }
return distinctCandidates.singleOrNull()
?: error("Expected all candidates to have same callableId, but got: ${distinctCandidates.map { it.callableId }}")
}
private fun findFakePackageToShorten(wholeQualifiedExpression: KtDotQualifiedExpression): ShortenQualifier? {
val deepestQualifier = wholeQualifiedExpression.qualifiedExpressionsWithSelf.last()
return if (deepestQualifier.hasFakeRootPrefix()) ShortenQualifier(deepestQualifier) else null
}
private fun addElementToShorten(element: ElementToShorten) {
if (element.importAllInParent && element.nameToImport?.parentOrNull()?.isRoot == false) {
namesToImportWithStar.addIfNotNull(element.nameToImport?.parent())
} else {
namesToImport.addIfNotNull(element.nameToImport)
}
when (element) {
is ShortenType -> {
typesToShorten.add(element.element)
}
is ShortenQualifier -> {
qualifiersToShorten.add(element.element)
}
}
}
private val ClassId.outerClassesWithSelf: Sequence<ClassId>
get() = generateSequence(this) { it.outerClassId }
/**
* Note: The resulting sequence does not contain non-qualified types!
*
* For type `A.B.C.D` it will return sequence of [`A.B.C.D`, `A.B.C`, `A.B`] (**without** `A`).
*/
private val KtUserType.qualifiedTypesWithSelf: Sequence<KtUserType>
get() {
require(qualifier != null) {
"Type element should have at least one qualifier, instead it was $text"
}
return generateSequence(this) { it.qualifier }.takeWhile { it.qualifier != null }
}
private val KtDotQualifiedExpression.qualifiedExpressionsWithSelf: Sequence<KtDotQualifiedExpression>
get() = generateSequence(this) { it.receiverExpression as? KtDotQualifiedExpression }
}
private class ShortenCommandImpl(
val targetFile: KtFile,
val importsToAdd: List<FqName>,
val starImportsToAdd: List<FqName>,
val typesToShorten: List<SmartPsiElementPointer<KtUserType>>,
val qualifiersToShorten: List<SmartPsiElementPointer<KtDotQualifiedExpression>>,
) : ShortenCommand {
override fun invokeShortening() {
ApplicationManager.getApplication().assertWriteAccessAllowed()
for (nameToImport in importsToAdd) {
addImportToFile(targetFile.project, targetFile, nameToImport)
}
for (nameToImport in starImportsToAdd) {
addImportToFile(targetFile.project, targetFile, nameToImport, allUnder = true)
}
//todo
// PostprocessReformattingAspect.getInstance(targetFile.project).disablePostprocessFormattingInside {
for (typePointer in typesToShorten) {
val type = typePointer.element ?: continue
type.deleteQualifier()
}
for (callPointer in qualifiersToShorten) {
val call = callPointer.element ?: continue
call.deleteQualifier()
}
// }
}
override val isEmpty: Boolean get() = typesToShorten.isEmpty() && qualifiersToShorten.isEmpty()
}
private fun KtUserType.hasFakeRootPrefix(): Boolean =
qualifier?.referencedName == ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE
private fun KtDotQualifiedExpression.hasFakeRootPrefix(): Boolean =
(receiverExpression as? KtNameReferenceExpression)?.getReferencedName() == ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE
internal fun KtElement.getDotQualifiedExpressionForSelector(): KtDotQualifiedExpression? =
getQualifiedExpressionForSelector() as? KtDotQualifiedExpression
private fun KtDotQualifiedExpression.deleteQualifier(): KtExpression? {
val selectorExpression = selectorExpression ?: return null
return this.replace(selectorExpression) as KtExpression
}
@@ -0,0 +1,66 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer
import org.jetbrains.kotlin.analysis.api.components.KtSamResolver
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.getClassLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSamConstructorSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
internal class KtFirSamResolver(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtSamResolver(), KtFirAnalysisSessionComponent {
override fun getSamConstructor(ktClassLikeSymbol: KtClassLikeSymbol): KtSamConstructorSymbol? {
val classId = ktClassLikeSymbol.classIdIfNonLocal ?: return null
val owner = analysisSession.getClassLikeSymbol(classId) as? FirRegularClass ?: return null
val resolver = LocalSamResolver(analysisSession.rootModuleSession)
return resolver.getSamConstructor(owner)?.let {
analysisSession.firSymbolBuilder.functionLikeBuilder.buildSamConstructorSymbol(it)
}
}
private class LocalSamResolver(
private val firSession: FirSession,
) {
private val scopeSession = ScopeSession()
// TODO: This transformer is not intended for actual transformations and
// created here only to simplify access to SAM resolver in body resolve components
private val stubBodyResolveTransformer = object : FirBodyResolveTransformer(
session = firSession,
phase = FirResolvePhase.BODY_RESOLVE,
implicitTypeOnly = false,
scopeSession = scopeSession,
) {}
private val bodyResolveComponents =
FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents(
firSession,
scopeSession,
stubBodyResolveTransformer,
stubBodyResolveTransformer.context,
)
// TODO: this doesn't guarantee that the same synthetic function (as a SAM constructor) is created/returned
fun getSamConstructor(firClass: FirRegularClass): FirSimpleFunction? {
val samConstructor = bodyResolveComponents.samResolver.getSamConstructor(firClass) ?: return null
if (samConstructor.origin != FirDeclarationOrigin.SamConstructor) return null
return samConstructor
}
}
}
@@ -0,0 +1,231 @@
/*
* 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.analysis.api.fir.components
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticPropertiesScope
import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir.getTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.components.KtImplicitReceiver
import org.jetbrains.kotlin.analysis.api.components.KtScopeContext
import org.jetbrains.kotlin.analysis.api.components.KtScopeProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.scopes.*
import org.jetbrains.kotlin.analysis.api.fir.symbols.*
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.scopes.*
import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtPackageSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithDeclarations
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import java.util.*
internal class KtFirScopeProvider(
analysisSession: KtFirAnalysisSession,
builder: KtSymbolByFirBuilder,
private val project: Project,
firResolveState: FirModuleResolveState,
override val token: ValidityToken,
) : KtScopeProvider(), ValidityTokenOwner {
override val analysisSession: KtFirAnalysisSession by weakRef(analysisSession)
private val builder by weakRef(builder)
private val firResolveState by weakRef(firResolveState)
private val firScopeStorage = FirScopeRegistry()
private val memberScopeCache = IdentityHashMap<KtSymbolWithMembers, KtMemberScope>()
private val declaredMemberScopeCache = IdentityHashMap<KtSymbolWithMembers, KtDeclaredMemberScope>()
private val fileScopeCache = IdentityHashMap<KtFileSymbol, KtDeclarationScope<KtSymbolWithDeclarations>>()
private val packageMemberScopeCache = IdentityHashMap<KtPackageSymbol, KtPackageScope>()
private inline fun <T> KtSymbolWithMembers.withFirForScope(crossinline body: (FirClass) -> T): T? = when (this) {
is KtFirNamedClassOrObjectSymbol -> firRef.withFir(FirResolvePhase.TYPES, body)
is KtFirAnonymousObjectSymbol -> firRef.withFir(FirResolvePhase.TYPES, body)
is KtFirEnumEntrySymbol -> firRef.withFir(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) {
val initializer = it.initializer
check(initializer is FirAnonymousObjectExpression) { "Unexpected enum entry initializer: ${initializer?.javaClass}" }
body(initializer.anonymousObject)
}
else -> error { "Unknown KtSymbolWithDeclarations implementation ${this::class.qualifiedName}" }
}
override fun getMemberScope(classSymbol: KtSymbolWithMembers): KtMemberScope = withValidityAssertion {
memberScopeCache.getOrPut(classSymbol) {
val firScope = classSymbol.withFirForScope { fir ->
val firSession = analysisSession.rootModuleSession
fir.unsubstitutedScope(
firSession,
ScopeSession(),
withForcedTypeCalculator = false
)
} ?: return@getOrPut KtFirEmptyMemberScope(classSymbol)
firScopeStorage.register(firScope)
KtFirMemberScope(classSymbol, firScope, token, builder)
}
}
override fun getStaticMemberScope(symbol: KtSymbolWithMembers): KtScope {
val firScope = symbol.withFirForScope { fir ->
fir.scopeProvider.getStaticScope(fir, analysisSession.rootModuleSession, ScopeSession())
} ?: return KtFirEmptyMemberScope(symbol)
firScopeStorage.register(firScope)
check(firScope is FirContainingNamesAwareScope)
return KtFirDelegatingScopeImpl(firScope, builder, token)
}
override fun getDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtDeclaredMemberScope = withValidityAssertion {
declaredMemberScopeCache.getOrPut(classSymbol) {
val firScope = classSymbol.withFirForScope {
analysisSession.rootModuleSession.declaredMemberScope(it)
} ?: return@getOrPut KtFirEmptyMemberScope(classSymbol)
firScopeStorage.register(firScope)
KtFirDeclaredMemberScope(classSymbol, firScope, token, builder)
}
}
override fun getFileScope(fileSymbol: KtFileSymbol): KtDeclarationScope<KtSymbolWithDeclarations> = withValidityAssertion {
fileScopeCache.getOrPut(fileSymbol) {
check(fileSymbol is KtFirFileSymbol) { "KtFirScopeProvider can only work with KtFirFileSymbol, but ${fileSymbol::class} was provided" }
KtFirFileScope(fileSymbol, token, builder)
}
}
override fun getPackageScope(packageSymbol: KtPackageSymbol): KtPackageScope = withValidityAssertion {
packageMemberScopeCache.getOrPut(packageSymbol) {
KtFirPackageScope(
packageSymbol.fqName,
project,
builder,
this,
token,
analysisSession.searchScope,
analysisSession.targetPlatform
)
}
}
fun registerScope(scope: FirScope) {
firScopeStorage.register(scope)
}
override fun getCompositeScope(subScopes: List<KtScope>): KtCompositeScope = withValidityAssertion {
KtFirCompositeScope(subScopes, token)
}
override fun getTypeScope(type: KtType): KtScope? {
check(type is KtFirType) { "KtFirScopeProvider can only work with KtFirType, but ${type::class} was provided" }
val firSession = firResolveState.rootModuleSession
val firTypeScope = type.coneType.scope(
firSession,
ScopeSession(),
FakeOverrideTypeCalculator.Forced
) ?: return null
return getCompositeScope(
listOf(
convertToKtScope(firTypeScope),
firTypeScope.getSyntheticPropertiesScope(firSession)
)
)
}
private fun FirTypeScope.getSyntheticPropertiesScope(firSession: FirSession): KtScope =
convertToKtScope(FirSyntheticPropertiesScope(firSession, this))
override fun getScopeContextForPosition(
originalFile: KtFile,
positionInFakeFile: KtElement
): KtScopeContext = withValidityAssertion {
val towerDataContext =
analysisSession.firResolveState.getTowerContextProvider().getClosestAvailableParentContext(positionInFakeFile)
?: error("Cannot find enclosing declaration for ${positionInFakeFile.getElementTextInContext()}")
val implicitReceivers = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.implicitReceiver }.distinct()
val implicitKtReceivers = implicitReceivers.map { receiver ->
KtImplicitReceiver(
token,
builder.typeBuilder.buildKtType(receiver.type),
builder.buildSymbol(receiver.boundSymbol.fir),
)
}
val implicitReceiverScopes = implicitReceivers.mapNotNull { it.implicitScope }
val nonLocalScopes = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.scope }.distinct()
val firLocalScopes = towerDataContext.localScopes
@OptIn(ExperimentalStdlibApi::class)
val allKtScopes = buildList<KtScope> {
implicitReceiverScopes.mapTo(this, ::convertToKtScope)
nonLocalScopes.mapTo(this, ::convertToKtScope)
firLocalScopes.mapTo(this, ::convertToKtScope)
}
KtScopeContext(
getCompositeScope(allKtScopes.asReversed()),
implicitKtReceivers.asReversed()
)
}
private fun convertToKtScope(firScope: FirScope): KtScope {
firScopeStorage.register(firScope)
return when (firScope) {
is FirAbstractSimpleImportingScope -> KtFirNonStarImportingScope(firScope, builder, token)
is FirAbstractStarImportingScope -> KtFirStarImportingScope(firScope, builder, project, token)
is FirPackageMemberScope -> KtFirPackageScope(
firScope.fqName,
project,
builder,
this,
token,
analysisSession.searchScope,
analysisSession.targetPlatform
)
is FirContainingNamesAwareScope -> KtFirDelegatingScopeImpl(firScope, builder, token)
is FirMemberTypeParameterScope -> KtFirDelegatingScopeImpl(firScope, builder, token)
else -> TODO(firScope::class.toString())
}
}
}
private class KtFirDelegatingScopeImpl<S>(
firScope: S, builder: KtSymbolByFirBuilder,
token: ValidityToken
) : KtFirDelegatingScope<S>(builder, token), ValidityTokenOwner where S : FirContainingNamesAwareScope, S : FirScope {
override val firScope: S by weakRef(firScope)
}
/**
* Stores strong references to all instances of [FirScope] used
* Needed as the only entity which may have a strong references to FIR internals is [KtFirAnalysisSession] & [KtAnalysisSessionComponent]
* Entities which needs storing [FirScope] instances will store them as weak references via [org.jetbrains.kotlin.analysis.api.fir.utils.weakRef]
*/
internal class FirScopeRegistry {
private val scopes = mutableListOf<FirScope>()
fun register(scope: FirScope) {
scopes += scope
}
}
@@ -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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.types.isStableSmartcast
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.api.ImplicitReceiverSmartCast
import org.jetbrains.kotlin.analysis.api.ImplicitReceiverSmartcastKind
import org.jetbrains.kotlin.analysis.api.components.KtSmartCastProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.psi.KtExpression
internal class KtFirSmartcastProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtSmartCastProvider(), KtFirAnalysisSessionComponent {
override fun getSmartCastedToType(expression: KtExpression): KtType? = withValidityAssertion {
expression.getOrBuildFirSafe<FirExpressionWithSmartcast>(analysisSession.firResolveState)
?.takeIf { it.isStable }
?.typeRef
?.coneTypeSafe<ConeKotlinType>()
?.asKtType()
}
@OptIn(ExperimentalStdlibApi::class)
override fun getImplicitReceiverSmartCast(expression: KtExpression): Collection<ImplicitReceiverSmartCast> = withValidityAssertion {
val qualifiedExpression =
expression.getOrBuildFirSafe<FirQualifiedAccessExpression>(analysisSession.firResolveState) ?: return emptyList()
val dispatchReceiver = qualifiedExpression.dispatchReceiver
val extensionReceiver = qualifiedExpression.extensionReceiver
if ((dispatchReceiver !is FirExpressionWithSmartcast || !dispatchReceiver.isStable) &&
(extensionReceiver !is FirExpressionWithSmartcast || !extensionReceiver.isStable)
) return emptyList()
buildList {
dispatchReceiver.takeIf { it.isStableSmartcast() }?.let { smartCasted ->
ImplicitReceiverSmartCast(
smartCasted.typeRef.coneTypeSafe<ConeKotlinType>()?.asKtType() ?: return@let null,
ImplicitReceiverSmartcastKind.DISPATCH
)
}?.let(::add)
extensionReceiver.takeIf { it.isStableSmartcast() }?.let { smartCasted ->
ImplicitReceiverSmartCast(
smartCasted.typeRef.coneTypeSafe<ConeKotlinType>()?.asKtType() ?: return@let null,
ImplicitReceiverSmartcastKind.EXTENSION
)
}?.let(::add)
}
}
}
@@ -0,0 +1,42 @@
/*
* 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.analysis.api.fir.components
import org.jetbrains.kotlin.analysis.api.assertIsValidAndAccessible
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.components.KtSubtypingComponent
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.types.AbstractTypeChecker
internal class KtFirSubtypingComponent(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtSubtypingComponent(), KtFirAnalysisSessionComponent {
override fun isEqualTo(first: KtType, second: KtType): Boolean = withValidityAssertion {
second.assertIsValidAndAccessible()
check(first is KtFirType)
check(second is KtFirType)
return AbstractTypeChecker.equalTypes(
createTypeCheckerContext(),
first.coneType,
second.coneType
)
}
override fun isSubTypeOf(subType: KtType, superType: KtType): Boolean = withValidityAssertion {
superType.assertIsValidAndAccessible()
check(subType is KtFirType)
check(superType is KtFirType)
return AbstractTypeChecker.isSubtypeOf(
createTypeCheckerContext(),
subType.coneType,
superType.coneType
)
}
}
@@ -0,0 +1,123 @@
/*
* 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.analysis.api.fir.components
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.parentOfType
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.components.KtSymbolContainingDeclarationProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind
import org.jetbrains.kotlin.psi.*
internal class KtFirSymbolContainingDeclarationProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtSymbolContainingDeclarationProvider(), KtFirAnalysisSessionComponent {
override fun getContainingDeclaration(symbol: KtSymbolWithKind): KtSymbolWithKind? {
if (symbol is KtPackageSymbol) return null
if (symbol.symbolKind == KtSymbolKind.TOP_LEVEL) return null
if (symbol is KtCallableSymbol) {
val classId = symbol.callableIdIfNonLocal?.classId
if (classId != null) {
with(analysisSession) {
return classId.getCorrespondingToplevelClassOrObjectSymbol()
}
}
}
return when (symbol.origin) {
KtSymbolOrigin.SOURCE, KtSymbolOrigin.SOURCE_MEMBER_GENERATED ->
getContainingDeclarationForKotlinInSourceSymbol(symbol)
KtSymbolOrigin.LIBRARY, KtSymbolOrigin.JAVA, KtSymbolOrigin.JAVA_SYNTHETIC_PROPERTY ->
getContainingDeclarationForLibrarySymbol(symbol)
KtSymbolOrigin.PROPERTY_BACKING_FIELD -> getContainingDeclarationForBackingFieldSymbol(symbol)
KtSymbolOrigin.INTERSECTION_OVERRIDE -> TODO()
KtSymbolOrigin.SAM_CONSTRUCTOR -> null
KtSymbolOrigin.DELEGATED -> TODO()
}
}
private fun getContainingDeclarationForBackingFieldSymbol(symbol: KtSymbolWithKind): KtSymbolWithKind {
require(symbol is KtBackingFieldSymbol)
return symbol.owningProperty
}
private fun getContainingDeclarationForKotlinInSourceSymbol(symbol: KtSymbolWithKind): KtSymbolWithKind = with(analysisSession) {
require(symbol.origin == KtSymbolOrigin.SOURCE || symbol.origin == KtSymbolOrigin.SOURCE_MEMBER_GENERATED)
require(symbol is KtFirSymbol<*>)
val containingDeclaration = getContainingPsi(symbol)
return with(analysisSession) {
val containingSymbol = containingDeclaration.getSymbol()
check(containingSymbol is KtSymbolWithKind)
containingSymbol
}
}
private fun getContainingPsi(symbol: KtFirSymbol<*>): KtDeclaration {
val source = symbol.firRef.withFir(action = FirDeclaration::source)
val thisSource = when (source?.kind) {
null -> error("PSI should present for declaration built by Kotlin code")
FirFakeSourceElementKind.ImplicitConstructor ->
return source.psi as KtDeclaration
FirFakeSourceElementKind.PropertyFromParameter -> return source.psi?.parentOfType<KtPrimaryConstructor>()!!
FirRealSourceElementKind -> source.psi!!
else -> error("Unexpected FirSourceElement: kind=${source.kind} element=${source.psi!!::class.simpleName}")
}
return when (symbol.origin) {
KtSymbolOrigin.SOURCE -> thisSource.getContainingKtDeclaration()
?: error("Containing declaration should present for non-toplevel declaration")
KtSymbolOrigin.SOURCE_MEMBER_GENERATED -> thisSource as KtDeclaration
else -> error("Unsupported declaration origin ${symbol.origin}")
}
}
private fun PsiElement.getContainingKtDeclaration(): KtDeclaration? =
when (val container = this.parentOfType<KtDeclaration>()) {
is KtDestructuringDeclaration -> container.parentOfType()
else -> container
}
private fun getContainingDeclarationForLibrarySymbol(symbol: KtSymbolWithKind): KtSymbolWithKind = with(analysisSession) {
require(symbol.origin == KtSymbolOrigin.LIBRARY || symbol.origin == KtSymbolOrigin.JAVA)
check(symbol.symbolKind == KtSymbolKind.MEMBER)
val containingClassId = when (symbol) {
is KtClassLikeSymbol -> {
val classId = symbol.classIdIfNonLocal ?: error("classId should not be null for non-local declaration")
classId.outerClassId
}
is KtFunctionSymbol -> {
val fqName = symbol.callableIdIfNonLocal ?: error("callableIdIfNonLocal should not be null for non-local declaration")
fqName.classId
}
is KtEnumEntrySymbol -> {
val classId = symbol.containingEnumClassIdIfNonLocal ?: error("fqName should not be null for non-local declaration")
classId.outerClassId
}
is KtPropertySymbol -> {
val fqName = symbol.callableIdIfNonLocal ?: error("fqName should not be null for non-local declaration")
fqName.classId
}
is KtConstructorSymbol -> {
symbol.containingClassIdIfNonLocal
?: error("fqName should not be null for non-local declaration")
}
else -> error("We should not have a ${symbol::class} from a library")
} ?: error("outerClassId should not be null for member declaration")
val containingClass = containingClassId.getCorrespondingToplevelClassOrObjectSymbol()
return containingClass ?: error("Class with id $containingClassId should exists")
}
}
@@ -0,0 +1,190 @@
/*
* 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.ensureResolved
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionOverrideFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionOverridePropertySymbol
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveType
import org.jetbrains.kotlin.analysis.api.components.KtSymbolDeclarationOverridesProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
internal class KtFirSymbolDeclarationOverridesProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtSymbolDeclarationOverridesProvider(), KtFirAnalysisSessionComponent {
override fun <T : KtSymbol> getAllOverriddenSymbols(
callableSymbol: T,
): List<KtCallableSymbol> {
val overriddenElement = mutableSetOf<FirCallableSymbol<*>>()
processOverrides(callableSymbol) { firTypeScope, firCallableDeclaration ->
firTypeScope.processAllOverriddenDeclarations(firCallableDeclaration) { overriddenDeclaration ->
overriddenDeclaration.symbol.collectIntersectionOverridesSymbolsTo(overriddenElement)
}
}
return overriddenElement.map { analysisSession.firSymbolBuilder.callableBuilder.buildCallableSymbol(it.fir) }
}
override fun <T : KtSymbol> getDirectlyOverriddenSymbols(callableSymbol: T): List<KtCallableSymbol> {
val overriddenElement = mutableSetOf<FirCallableSymbol<*>>()
processOverrides(callableSymbol) { firTypeScope, firCallableDeclaration ->
firTypeScope.processDirectOverriddenDeclarations(firCallableDeclaration) { overriddenDeclaration ->
overriddenDeclaration.symbol.collectIntersectionOverridesSymbolsTo(overriddenElement)
}
}
return overriddenElement.map { analysisSession.firSymbolBuilder.callableBuilder.buildCallableSymbol(it.fir) }
}
private fun FirTypeScope.processCallableByName(declaration: FirDeclaration) = when (declaration) {
is FirSimpleFunction -> processFunctionsByName(declaration.name) { }
is FirProperty -> processPropertiesByName(declaration.name) { }
else -> error { "Invalid FIR symbol to process: ${declaration::class}" }
}
private fun FirTypeScope.processAllOverriddenDeclarations(
declaration: FirDeclaration,
processor: (FirCallableDeclaration) -> Unit
) = when (declaration) {
is FirSimpleFunction -> processOverriddenFunctions(declaration.symbol) { symbol ->
processor.invoke(symbol.fir)
ProcessorAction.NEXT
}
is FirProperty -> processOverriddenProperties(declaration.symbol) { symbol ->
processor.invoke(symbol.fir)
ProcessorAction.NEXT
}
else -> error { "Invalid FIR symbol to process: ${declaration::class}" }
}
private fun FirTypeScope.processDirectOverriddenDeclarations(
declaration: FirDeclaration,
processor: (FirCallableDeclaration) -> Unit
) = when (declaration) {
is FirSimpleFunction -> processDirectOverriddenFunctionsWithBaseScope(declaration.symbol) { symbol, _ ->
processor.invoke(symbol.fir)
ProcessorAction.NEXT
}
is FirProperty -> processDirectOverriddenPropertiesWithBaseScope(declaration.symbol) { symbol, _ ->
processor.invoke(symbol.fir)
ProcessorAction.NEXT
}
else -> error { "Invalid FIR symbol to process: ${declaration::class}" }
}
private inline fun <T : KtSymbol> processOverrides(
callableSymbol: T,
crossinline process: (FirTypeScope, FirDeclaration) -> Unit
) {
require(callableSymbol is KtFirSymbol<*>)
val containingDeclaration = with(analysisSession) {
(callableSymbol as? KtCallableSymbol)?.originalContainingClassForOverride
} ?: return
check(containingDeclaration is KtFirNamedClassOrObjectSymbol)
processOverrides(containingDeclaration, callableSymbol, process)
}
private inline fun processOverrides(
containingDeclaration: KtFirNamedClassOrObjectSymbol,
callableSymbol: KtFirSymbol<*>,
crossinline process: (FirTypeScope, FirDeclaration) -> Unit
) {
containingDeclaration.firRef.withFir(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) { firContainer ->
callableSymbol.firRef.withFirUnsafe { firCallableDeclaration ->
val firTypeScope = firContainer.unsubstitutedScope(
firContainer.moduleData.session,
ScopeSession(),
withForcedTypeCalculator = false
)
firTypeScope.processCallableByName(firCallableDeclaration)
process(firTypeScope, firCallableDeclaration)
}
}
}
private fun FirCallableSymbol<*>.collectIntersectionOverridesSymbolsTo(to: MutableCollection<FirCallableSymbol<*>>) {
when (this) {
is FirIntersectionOverrideFunctionSymbol -> {
intersections.forEach { it.collectIntersectionOverridesSymbolsTo(to) }
}
is FirIntersectionOverridePropertySymbol -> {
intersections.forEach { it.collectIntersectionOverridesSymbolsTo(to) }
}
else -> {
to += this
}
}
}
override fun isSubClassOf(subClass: KtClassOrObjectSymbol, superClass: KtClassOrObjectSymbol): Boolean {
return isSubClassOf(subClass, superClass, checkDeep = true)
}
override fun isDirectSubClassOf(subClass: KtClassOrObjectSymbol, superClass: KtClassOrObjectSymbol): Boolean {
return isSubClassOf(subClass, superClass, checkDeep = false)
}
private fun isSubClassOf(subClass: KtClassOrObjectSymbol, superClass: KtClassOrObjectSymbol, checkDeep: Boolean): Boolean {
require(subClass is KtFirSymbol<*>)
require(superClass is KtFirSymbol<*>)
if (subClass == superClass) return false
return subClass.firRef.withFirByType(ResolveType.ClassSuperTypes) { subClassFir ->
check(subClassFir is FirRegularClass)
superClass.firRef.withFir { superClassFir ->
check(superClassFir is FirRegularClass)
isSubClassOf(subClassFir, superClassFir, checkDeep)
}
}
}
private fun isSubClassOf(subClass: FirRegularClass, superClass: FirRegularClass, checkDeep: Boolean): Boolean {
if (subClass.superConeTypes.any { it.toRegularClassSymbol(rootModuleSession) == superClass.symbol }) return true
if (!checkDeep) return false
subClass.superConeTypes.forEach { superType ->
val superOfSub = superType.toRegularClassSymbol(rootModuleSession) ?: return@forEach
superOfSub.ensureResolved(FirResolvePhase.SUPER_TYPES)
if (isSubClassOf(superOfSub.fir, superClass, checkDeep = true)) return true
}
return false
}
override fun getIntersectionOverriddenSymbols(symbol: KtCallableSymbol): Collection<KtCallableSymbol> {
require(symbol is KtFirSymbol<*>)
if (symbol.origin != KtSymbolOrigin.INTERSECTION_OVERRIDE) return emptyList()
return symbol.firRef.withFir { fir ->
val firSymbol = fir.symbol
firSymbol.getIntersectionOverriddenSymbols()
.map { analysisSession.firSymbolBuilder.callableBuilder.buildCallableSymbol(it.fir) }
}
}
private fun FirBasedSymbol<*>.getIntersectionOverriddenSymbols(): Collection<FirCallableSymbol<*>> {
require(this is FirCallableSymbol<*>) {
"Required FirCallableSymbol but ${this::class} found"
}
return when (this) {
is FirIntersectionOverrideFunctionSymbol -> intersections
is FirIntersectionOverridePropertySymbol -> intersections
else -> listOf(this)
}
}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions
import org.jetbrains.kotlin.analysis.api.components.KtSymbolDeclarationRendererProvider
import org.jetbrains.kotlin.analysis.api.components.KtTypeRendererOptions
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.renderer.ConeTypeIdeRenderer
import org.jetbrains.kotlin.analysis.api.fir.renderer.FirIdeRenderer
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.*
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
internal class KtFirSymbolDeclarationRendererProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtSymbolDeclarationRendererProvider() {
override fun render(type: KtType, options: KtTypeRendererOptions): String {
require(type is KtFirType)
return ConeTypeIdeRenderer(analysisSession.firResolveState.rootModuleSession, options).renderType(type.coneType)
}
override fun render(symbol: KtSymbol, options: KtDeclarationRendererOptions): String {
return when (symbol) {
is KtPackageSymbol -> {
"package ${symbol.fqName.asString()}"
}
is KtFirSymbol<*> -> {
val containingSymbol = with(analysisSession) {
(symbol as? KtSymbolWithKind)?.getContainingSymbol()
}
check(containingSymbol is KtFirSymbol<*>?)
symbol.firRef.withFir(FirResolvePhase.BODY_RESOLVE) { fir ->
val containingFir = containingSymbol?.firRef?.withFirUnsafe { it }
FirIdeRenderer.render(fir, containingFir, options, fir.moduleData.session)
}
}
else -> {
error("Unexpected Fir Symbol ${symbol::class.simpleName}")
}
}
}
}
@@ -0,0 +1,95 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.components
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.getDeprecationForCallSite
import org.jetbrains.kotlin.fir.declarations.getJvmNameFromAnnotation
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.analysis.api.components.KtSymbolInfoProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirBackingFieldSymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirPackageSymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSyntheticJavaPropertySymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name
internal class KtFirSymbolInfoProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtSymbolInfoProvider(), KtFirAnalysisSessionComponent {
override fun getDeprecation(symbol: KtSymbol): DeprecationInfo? {
if (symbol is KtFirBackingFieldSymbol || symbol is KtFirPackageSymbol) return null
require(symbol is KtFirSymbol<*>)
return symbol.firRef.withFir {
val firSymbol = it.symbol
if (firSymbol is FirPropertySymbol) {
firSymbol.getDeprecationForCallSite(AnnotationUseSiteTarget.PROPERTY)
} else {
firSymbol.getDeprecationForCallSite()
}
}
}
override fun getDeprecation(symbol: KtSymbol, annotationUseSiteTarget: AnnotationUseSiteTarget?): DeprecationInfo? {
require(symbol is KtFirSymbol<*>)
return symbol.firRef.withFir { firDeclaration ->
if (annotationUseSiteTarget != null) {
firDeclaration.symbol.getDeprecationForCallSite(annotationUseSiteTarget)
} else {
firDeclaration.symbol.getDeprecationForCallSite()
}
}
}
override fun getGetterDeprecation(symbol: KtPropertySymbol): DeprecationInfo? {
require(symbol is KtFirSymbol<*>)
return symbol.firRef.withFir {
it.symbol.getDeprecationForCallSite(AnnotationUseSiteTarget.PROPERTY_GETTER, AnnotationUseSiteTarget.PROPERTY)
}
}
override fun getSetterDeprecation(symbol: KtPropertySymbol): DeprecationInfo? {
require(symbol is KtFirSymbol<*>)
return symbol.firRef.withFir {
it.symbol.getDeprecationForCallSite(AnnotationUseSiteTarget.PROPERTY_SETTER, AnnotationUseSiteTarget.PROPERTY)
}
}
override fun getJavaGetterName(symbol: KtPropertySymbol): Name {
require(symbol is KtFirSymbol<*>)
if (symbol is KtFirSyntheticJavaPropertySymbol) {
return symbol.firRef.withFir { it.getter.delegate.name }
}
val jvmName = symbol.firRef.withFir {
val firProperty = it as? FirProperty ?: return@withFir null
firProperty.getJvmNameFromAnnotation(AnnotationUseSiteTarget.PROPERTY_GETTER) ?: firProperty.getter?.getJvmNameFromAnnotation()
}
return Name.identifier(jvmName ?: JvmAbi.getterName(symbol.name.identifier))
}
override fun getJavaSetterName(symbol: KtPropertySymbol): Name? {
require(symbol is KtFirSymbol<*>)
if (symbol is KtFirSyntheticJavaPropertySymbol) {
symbol.firRef.withFir { it.setter?.delegate?.name }
}
return if (symbol.isVal) null
else {
val jvmName = symbol.firRef.withFir {
val firProperty = it as? FirProperty ?: return@withFir null
firProperty.getJvmNameFromAnnotation(AnnotationUseSiteTarget.PROPERTY_SETTER)
?: firProperty.setter?.getJvmNameFromAnnotation()
}
Name.identifier(jvmName ?: JvmAbi.setterName(symbol.name.identifier))
}
}
}
@@ -0,0 +1,50 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedSymbolError
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.analysis.api.components.KtClassTypeBuilder
import org.jetbrains.kotlin.analysis.api.components.KtTypeCreator
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtClassType
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
internal class KtFirTypeCreator(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken
) : KtTypeCreator(), KtFirAnalysisSessionComponent {
override fun buildClassType(builder: KtClassTypeBuilder): KtClassType = withValidityAssertion {
val lookupTag = when (builder) {
is KtClassTypeBuilder.ByClassId -> {
val classSymbol = rootModuleSession.symbolProvider.getClassLikeSymbolByClassId(builder.classId)
?: return ConeClassErrorType(ConeUnresolvedSymbolError(builder.classId)).asKtType() as KtClassType
classSymbol.toLookupTag()
}
is KtClassTypeBuilder.BySymbol -> {
val symbol = builder.symbol
check(symbol is KtFirSymbol<*>)
symbol.firRef.withFir { (it as FirClassLikeDeclaration).symbol.toLookupTag() }
}
}
val typeContext = rootModuleSession.typeContext
val coneType = typeContext.createSimpleType(
lookupTag,
builder.arguments.map { it.coneTypeProjection },
builder.nullability.isNullable
) as ConeClassLikeType
return coneType.asKtType() as KtClassType
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.resolve.FirSamResolverImpl
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.types.canBeNull
import org.jetbrains.kotlin.analysis.api.components.KtTypeInfoProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
internal class KtFirTypeInfoProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtTypeInfoProvider(), KtFirAnalysisSessionComponent {
override fun isFunctionalInterfaceType(type: KtType): Boolean {
val coneType = (type as KtFirType).coneType
val samResolver = FirSamResolverImpl(analysisSession.rootModuleSession, ScopeSession())
return samResolver.getFunctionTypeForPossibleSamType(coneType) != null
}
override fun canBeNull(type: KtType): Boolean = (type as KtFirType).coneType.canBeNull
}
@@ -0,0 +1,98 @@
/*
* 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.analysis.api.fir.components
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.analysis.api.components.KtBuiltinTypes
import org.jetbrains.kotlin.analysis.api.components.KtTypeProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType
import org.jetbrains.kotlin.analysis.api.fir.types.PublicTypeApproximator
import org.jetbrains.kotlin.analysis.api.fir.utils.toConeNullability
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.psi.KtDoubleColonExpression
import org.jetbrains.kotlin.psi.KtTypeReference
internal class KtFirTypeProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtTypeProvider(), KtFirAnalysisSessionComponent {
override val builtinTypes: KtBuiltinTypes = KtFirBuiltInTypes(rootModuleSession.builtinTypes, firSymbolBuilder, token)
override fun approximateToSuperPublicDenotableType(type: KtType): KtType? {
require(type is KtFirType)
val coneType = type.coneType
val approximatedConeType = PublicTypeApproximator.approximateTypeToPublicDenotable(
coneType,
rootModuleSession
)
return approximatedConeType?.asKtType()
}
override fun buildSelfClassType(symbol: KtNamedClassOrObjectSymbol): KtType {
require(symbol is KtFirNamedClassOrObjectSymbol)
val type = symbol.firRef.withFir(FirResolvePhase.SUPER_TYPES) { firClass ->
ConeClassLikeTypeImpl(
firClass.symbol.toLookupTag(),
firClass.typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), isNullable = false) }.toTypedArray(),
isNullable = false
)
}
return type.asKtType()
}
override fun commonSuperType(types: Collection<KtType>): KtType? {
return analysisSession.rootModuleSession.typeContext
.commonSuperTypeOrNull(types.map { it.coneType })
?.asKtType()
}
override fun getKtType(ktTypeReference: KtTypeReference): KtType = withValidityAssertion {
when (val fir = ktTypeReference.getOrBuildFir(firResolveState)) {
is FirResolvedTypeRef -> fir.coneType.asKtType()
is FirDelegatedConstructorCall -> fir.constructedTypeRef.coneType.asKtType()
else -> throwUnexpectedFirElementError(fir, ktTypeReference)
}
}
override fun getReceiverTypeForDoubleColonExpression(expression: KtDoubleColonExpression): KtType? = withValidityAssertion {
when (val fir = expression.getOrBuildFir(firResolveState)) {
is FirGetClassCall ->
fir.typeRef.coneType.getReceiverOfReflectionType()?.asKtType()
is FirCallableReferenceAccess ->
fir.typeRef.coneType.getReceiverOfReflectionType()?.asKtType()
else -> throwUnexpectedFirElementError(fir, expression)
}
}
private fun ConeKotlinType.getReceiverOfReflectionType(): ConeKotlinType? {
if (this !is ConeClassLikeType) return null
if (lookupTag.classId.packageFqName != StandardClassIds.BASE_REFLECT_PACKAGE) return null
return typeArguments.firstOrNull()?.type
}
override fun withNullability(type: KtType, newNullability: KtTypeNullability): KtType {
require(type is KtFirType)
return type.coneType.withNullability(newNullability.toConeNullability(), rootModuleSession.typeContext).asKtType()
}
}
@@ -0,0 +1,82 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.components
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue
import org.jetbrains.kotlin.fir.visibilityChecker
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignation
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.parentsOfType
import org.jetbrains.kotlin.analysis.api.components.KtVisibilityChecker
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirFileSymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
internal class KtFirVisibilityChecker(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken
) : KtVisibilityChecker(), KtFirAnalysisSessionComponent {
override fun isVisible(
candidateSymbol: KtSymbolWithVisibility,
useSiteFile: KtFileSymbol,
position: PsiElement,
receiverExpression: KtExpression?
): Boolean {
require(candidateSymbol is KtFirSymbol<*>)
require(useSiteFile is KtFirFileSymbol)
val nonLocalContainingDeclaration = findContainingNonLocalDeclaration(position)
return useSiteFile.firRef.withFir { useSiteFirFile ->
val containers = nonLocalContainingDeclaration
?.getOrBuildFirSafe<FirCallableDeclaration>(analysisSession.firResolveState)
?.collectDesignation()
?.path
.orEmpty()
val explicitDispatchReceiver = receiverExpression
?.getOrBuildFirSafe<FirExpression>(analysisSession.firResolveState)
?.let { ExpressionReceiverValue(it) }
candidateSymbol.firRef.withFir { candidateFirSymbol ->
require(candidateFirSymbol is FirMemberDeclaration) {
"$candidateFirSymbol must be a FirStatusOwner and FirSymbolOwner; it were ${candidateFirSymbol::class} instead"
}
rootModuleSession.visibilityChecker.isVisible(
candidateFirSymbol,
rootModuleSession,
useSiteFirFile,
containers,
explicitDispatchReceiver
)
}
}
}
private fun findContainingNonLocalDeclaration(element: PsiElement): KtCallableDeclaration? {
return element
.parentsOfType<KtCallableDeclaration>()
.firstOrNull { it.isNotFromLocalClass }
}
private val KtCallableDeclaration.isNotFromLocalClass
get() = this is KtNamedFunction && (isTopLevel || containingClassOrObject?.isLocal == false) ||
this is KtProperty && (isTopLevel || containingClassOrObject?.isLocal == false)
}
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.diagnostics
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDefaultErrorMessages
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic
import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnosticWithPsi
internal interface KtAbstractFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
val firDiagnostic: FirPsiDiagnostic
override val factoryName: String
get() = firDiagnostic.factory.name
override val defaultMessage: String
get() {
val diagnostic = firDiagnostic as FirDiagnostic
val firDiagnosticRenderer = FirDefaultErrorMessages.getRendererForDiagnostic(diagnostic)
return firDiagnosticRenderer.render(diagnostic)
}
override val textRanges: Collection<TextRange>
get() = firDiagnostic.textRanges
@Suppress("UNCHECKED_CAST")
override val psi: PSI
get() = firDiagnostic.psiElement as PSI
override val severity: Severity
get() = firDiagnostic.severity
}
@@ -0,0 +1,91 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.diagnostics
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
internal interface KtFirDiagnosticCreator
internal fun interface KtFirDiagnostic0Creator : KtFirDiagnosticCreator {
fun KtFirAnalysisSession.create(diagnostic: FirSimpleDiagnostic): KtFirDiagnostic<*>
}
internal fun interface KtFirDiagnostic1Creator<A> : KtFirDiagnosticCreator {
fun KtFirAnalysisSession.create(diagnostic: FirDiagnosticWithParameters1<A>): KtFirDiagnostic<*>
}
internal fun interface KtFirDiagnostic2Creator<A, B> : KtFirDiagnosticCreator {
fun KtFirAnalysisSession.create(diagnostic: FirDiagnosticWithParameters2<A, B>): KtFirDiagnostic<*>
}
internal fun interface KtFirDiagnostic3Creator<A, B, C> : KtFirDiagnosticCreator {
fun KtFirAnalysisSession.create(diagnostic: FirDiagnosticWithParameters3<A, B, C>): KtFirDiagnostic<*>
}
internal fun interface KtFirDiagnostic4Creator<A, B, C, D> : KtFirDiagnosticCreator {
fun KtFirAnalysisSession.create(diagnostic: FirDiagnosticWithParameters4<A, B, C, D>): KtFirDiagnostic<*>
}
internal class KtDiagnosticConverter(private val conversions: Map<AbstractFirDiagnosticFactory, KtFirDiagnosticCreator>) {
fun convert(analysisSession: KtFirAnalysisSession, diagnostic: FirDiagnostic): KtFirDiagnostic<*> {
val creator = conversions[diagnostic.factory]
?: error("No conversion was found for ${diagnostic.factory}")
@Suppress("UNCHECKED_CAST")
return with(analysisSession) {
when (creator) {
is KtFirDiagnostic0Creator -> with(creator) {
create(diagnostic as FirSimpleDiagnostic)
}
is KtFirDiagnostic1Creator<*> -> with(creator as KtFirDiagnostic1Creator<Any?>) {
create(diagnostic as FirDiagnosticWithParameters1<Any?>)
}
is KtFirDiagnostic2Creator<*, *> -> with(creator as KtFirDiagnostic2Creator<Any?, Any?>) {
create(diagnostic as FirDiagnosticWithParameters2<Any?, Any?>)
}
is KtFirDiagnostic3Creator<*, *, *> -> with(creator as KtFirDiagnostic3Creator<Any?, Any?, Any?>) {
create(diagnostic as FirDiagnosticWithParameters3<Any?, Any?, Any?>)
}
is KtFirDiagnostic4Creator<*, *, *, *> -> with(creator as KtFirDiagnostic4Creator<Any?, Any?, Any?, Any?>) {
create(diagnostic as FirDiagnosticWithParameters4<Any?, Any?, Any?, Any?>)
}
else -> error("Invalid KtFirDiagnosticCreator ${creator::class.simpleName}")
}
}
}
}
internal class KtDiagnosticConverterBuilder private constructor() {
private val conversions = mutableMapOf<AbstractFirDiagnosticFactory, KtFirDiagnosticCreator>()
fun add(diagnostic: FirDiagnosticFactory0, creator: KtFirDiagnostic0Creator) {
conversions[diagnostic] = creator
}
fun <A> add(diagnostic: FirDiagnosticFactory1<A>, creator: KtFirDiagnostic1Creator<A>) {
conversions[diagnostic] = creator
}
fun <A, B> add(diagnostic: FirDiagnosticFactory2<A, B>, creator: KtFirDiagnostic2Creator<A, B>) {
conversions[diagnostic] = creator
}
fun <A, B, C> add(diagnostic: FirDiagnosticFactory3<A, B, C>, creator: KtFirDiagnostic3Creator<A, B, C>) {
conversions[diagnostic] = creator
}
fun <A, B, C, D> add(diagnostic: FirDiagnosticFactory4<A, B, C, D>, creator: KtFirDiagnostic4Creator<A, B, C, D>) {
conversions[diagnostic] = creator
}
private fun build() = KtDiagnosticConverter(conversions)
companion object {
inline fun buildConverter(init: KtDiagnosticConverterBuilder.() -> Unit) =
KtDiagnosticConverterBuilder().apply(init).build()
}
}
@@ -0,0 +1,216 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.evaluate
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.argument
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.*
import org.jetbrains.kotlin.resolve.constants.evaluate.CompileTimeType
import org.jetbrains.kotlin.resolve.constants.evaluate.evalBinaryOp
import org.jetbrains.kotlin.resolve.constants.evaluate.evalUnaryOp
import org.jetbrains.kotlin.types.ConstantValueKind
/**
* An evaluator that transform numeric operation, such as div, into compile-time constant iff involved operands, such as explicit receiver
* and the argument, are compile-time constant as well.
*/
internal class FirCompileTimeConstantEvaluator {
// TODO: Handle boolean operators, const property loading, class reference, array, annotation values, etc.
fun evaluate(expression: FirExpression): FirConstExpression<*>? =
when (expression) {
is FirConstExpression<*> -> expression
is FirFunctionCall -> evaluate(expression)
else -> null
}
// TODO: Rework to handle nested expressions
// This is no longer used during FIR2IR where an inner expression is recursively rewritten to ConstExpression if possible.
// Maybe rewrite this to a recursive version with caching either here or in provider.
private fun evaluate(functionCall: FirFunctionCall): FirConstExpression<*>? {
val function = functionCall.getOriginalFunction()!! as FirSimpleFunction
val opr1 = functionCall.explicitReceiver as? FirConstExpression<*> ?: return null
opr1.evaluate(function)?.let {
return it.adjustType(functionCall.typeRef)
}
val opr2 = functionCall.argument as? FirConstExpression<*> ?: return null
opr1.evaluate(function, opr2)?.let {
return it.adjustType(functionCall.typeRef)
}
return null
}
private fun FirConstExpression<*>.adjustType(expectedType: FirTypeRef): FirConstExpression<*> {
val expectedKind = expectedType.toConstantValueKind()
// Note that the resolved type for the const expression is not always matched with the const kind. For example,
// fun foo(x: Int) {
// when (x) {
// -2_147_483_628 -> ...
// } }
// That constant is encoded as `unaryMinus` call with the const 2147483628 of long type, while the resolved type is Int.
// After computing the compile time constant, we need to adjust its type here.
val expression =
if (expectedKind != null && expectedKind != kind && value is Number) {
val typeAdjustedValue = expectedKind.convertToNumber(value as Number)!!
expectedKind.toConstExpression(source, typeAdjustedValue)
} else {
this
}
// Lastly, we should preserve the resolved type of the original function call.
return expression.apply {
replaceTypeRef(expectedType)
} ?: this
}
private fun <T> ConstantValueKind<T>.toCompileTimeType(): CompileTimeType {
return when (this) {
ConstantValueKind.Byte -> CompileTimeType.BYTE
ConstantValueKind.Short -> CompileTimeType.SHORT
ConstantValueKind.Int -> CompileTimeType.INT
ConstantValueKind.Long -> CompileTimeType.LONG
ConstantValueKind.Double -> CompileTimeType.DOUBLE
ConstantValueKind.Float -> CompileTimeType.FLOAT
ConstantValueKind.Char -> CompileTimeType.CHAR
ConstantValueKind.Boolean -> CompileTimeType.BOOLEAN
ConstantValueKind.String -> CompileTimeType.STRING
else -> CompileTimeType.ANY
}
}
// Unary operators
private fun FirConstExpression<*>.evaluate(function: FirSimpleFunction): FirConstExpression<*>? {
if (value == null) return null
return evalUnaryOp(
function.name.asString(),
kind.toCompileTimeType(),
value!!
)?.let {
it.toConstantValueKind()?.toConstExpression(source, it)
}
}
// Binary operators
private fun FirConstExpression<*>.evaluate(
function: FirSimpleFunction,
other: FirConstExpression<*>
): FirConstExpression<*>? {
if (value == null || other.value == null) return null
return evalBinaryOp(
function.name.asString(),
kind.toCompileTimeType(),
value!!,
other.kind.toCompileTimeType(),
other.value!!
)?.let {
it.toConstantValueKind()?.toConstExpression(source, it)
}
}
////// KINDS
private fun FirTypeRef.toConstantValueKind(): ConstantValueKind<*>? =
when (this) {
!is FirResolvedTypeRef -> null
!is FirImplicitBuiltinTypeRef -> type.toConstantValueKind()
is FirImplicitByteTypeRef -> ConstantValueKind.Byte
is FirImplicitDoubleTypeRef -> ConstantValueKind.Double
is FirImplicitFloatTypeRef -> ConstantValueKind.Float
is FirImplicitIntTypeRef -> ConstantValueKind.Int
is FirImplicitLongTypeRef -> ConstantValueKind.Long
is FirImplicitShortTypeRef -> ConstantValueKind.Short
is FirImplicitCharTypeRef -> ConstantValueKind.Char
is FirImplicitStringTypeRef -> ConstantValueKind.String
is FirImplicitBooleanTypeRef -> ConstantValueKind.Boolean
else -> null
}
private fun ConeKotlinType.toConstantValueKind(): ConstantValueKind<*>? =
when (this) {
is ConeKotlinErrorType -> null
is ConeLookupTagBasedType -> lookupTag.name.asString().toConstantValueKind()
is ConeFlexibleType -> upperBound.toConstantValueKind()
is ConeCapturedType -> lowerType?.toConstantValueKind() ?: constructor.supertypes!!.first().toConstantValueKind()
is ConeDefinitelyNotNullType -> original.toConstantValueKind()
is ConeIntersectionType -> intersectedTypes.first().toConstantValueKind()
is ConeStubType -> null
is ConeIntegerLiteralType -> null
}
private fun String.toConstantValueKind(): ConstantValueKind<*>? =
when (this) {
"Byte" -> ConstantValueKind.Byte
"Double" -> ConstantValueKind.Double
"Float" -> ConstantValueKind.Float
"Int" -> ConstantValueKind.Int
"Long" -> ConstantValueKind.Long
"Short" -> ConstantValueKind.Short
"Char" -> ConstantValueKind.Char
"String" -> ConstantValueKind.String
"Boolean" -> ConstantValueKind.Boolean
else -> null
}
private fun <T : Any> T.toConstantValueKind(): ConstantValueKind<*>? =
when (this) {
is Byte -> ConstantValueKind.Byte
is Double -> ConstantValueKind.Double
is Float -> ConstantValueKind.Float
is Int -> ConstantValueKind.Int
is Long -> ConstantValueKind.Long
is Short -> ConstantValueKind.Short
is Char -> ConstantValueKind.Char
is String -> ConstantValueKind.String
is Boolean -> ConstantValueKind.Boolean
else -> null
}
private fun ConstantValueKind<*>.convertToNumber(value: Number?): Number? {
if (value == null) {
return null
}
return when {
this == ConstantValueKind.Byte -> value.toByte()
this == ConstantValueKind.Double -> value.toDouble()
this == ConstantValueKind.Float -> value.toFloat()
this == ConstantValueKind.Int -> value.toInt()
this == ConstantValueKind.Long -> value.toLong()
this == ConstantValueKind.Short -> value.toShort()
else -> null
}
}
private fun <T> ConstantValueKind<T>?.toConstExpression(source: FirSourceElement?, value: Any): FirConstExpression<T>? =
if (this == null) null else
@Suppress("UNCHECKED_CAST")
buildConstExpression(source, this, value as T)
private fun FirFunctionCall.getOriginalFunction(): FirCallableDeclaration? {
val symbol: FirBasedSymbol<*>? = when (val reference = calleeReference) {
is FirResolvedNamedReference -> reference.resolvedSymbol
else -> null
}
return symbol?.fir as? FirCallableDeclaration
}
}
@@ -0,0 +1,541 @@
/*
* 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 com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildImport
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticPropertySymbol
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnmatchedTypeArgumentsError
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.FirImportResolveTransformer
import org.jetbrains.kotlin.fir.scopes.impl.FirExplicitSimpleImportingScope
import org.jetbrains.kotlin.fir.scopes.processClassifiersByName
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols
import org.jetbrains.kotlin.analysis.api.fir.isImplicitFunctionCall
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.buildSymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirPackageSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability
import org.jetbrains.kotlin.utils.addIfNotNull
internal object FirReferenceResolveHelper {
fun FirResolvedTypeRef.toTargetSymbol(session: FirSession, symbolBuilder: KtSymbolByFirBuilder): KtSymbol? {
val type = getDeclaredType() as? ConeLookupTagBasedType
val resolvedSymbol = type?.lookupTag?.toSymbol(session) as? FirBasedSymbol<*>
val symbol = resolvedSymbol ?: run {
val diagnostic = (this as? FirErrorTypeRef)?.diagnostic
(diagnostic as? ConeUnmatchedTypeArgumentsError)?.candidateSymbol
}
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,
calleeReference: FirReference? = null,
): KtSymbol? {
val classLikeDeclaration = ConeClassLikeLookupTagImpl(this).toSymbol(session)?.fir
if (classLikeDeclaration is FirRegularClass) {
if (calleeReference is FirResolvedNamedReference) {
val callee = calleeReference.resolvedSymbol.fir as? FirCallableDeclaration
// TODO: check callee owner directly?
if (callee !is FirConstructor && callee?.isStatic != true) {
classLikeDeclaration.companionObject?.let { return it.buildSymbol(symbolBuilder) }
}
}
}
return classLikeDeclaration?.buildSymbol(symbolBuilder)
}
fun FirReference.toTargetSymbol(session: FirSession, symbolBuilder: KtSymbolByFirBuilder): Collection<KtSymbol> {
return when (this) {
is FirBackingFieldReference -> {
listOfNotNull(resolvedSymbol.fir.buildSymbol(symbolBuilder))
}
is FirResolvedNamedReference -> {
val fir = when (val symbol = resolvedSymbol) {
is FirSyntheticPropertySymbol -> {
val syntheticProperty = symbol.fir as FirSyntheticProperty
if (syntheticProperty.getter.delegate.symbol.callableId == symbol.accessorId) {
syntheticProperty.getter.delegate
} else {
syntheticProperty.setter!!.delegate
}
}
else -> symbol.fir
}
listOfNotNull(fir.buildSymbol(symbolBuilder))
}
is FirResolvedCallableReference -> {
listOfNotNull(resolvedSymbol.fir.buildSymbol(symbolBuilder))
}
is FirThisReference -> {
listOfNotNull(boundSymbol?.fir?.buildSymbol(symbolBuilder))
}
is FirSuperReference -> {
listOfNotNull((superTypeRef as? FirResolvedTypeRef)?.toTargetSymbol(session, symbolBuilder))
}
is FirErrorNamedReference -> {
getCandidateSymbols().map { it.fir.buildSymbol(symbolBuilder) }
}
else -> emptyList()
}
}
private fun getPackageSymbolFor(
expression: KtSimpleNameExpression,
symbolBuilder: KtSymbolByFirBuilder,
forQualifiedType: Boolean
): KtFirPackageSymbol? {
return symbolBuilder.createPackageSymbolIfOneExists(getQualifierSelected(expression, forQualifiedType))
}
private fun getQualifierSelected(
expression: KtSimpleNameExpression,
forQualifiedType: Boolean
): FqName {
val qualified = when {
forQualifiedType -> expression.parent?.takeIf { it is KtUserType && it.referenceExpression === expression }
else -> expression.getQualifiedExpressionForSelector()
}
return when (qualified) {
null -> FqName(expression.getReferencedName())
else -> {
qualified
.collectDescendantsOfType<KtSimpleNameExpression>()
.dropWhile { it.getReferencedName() == ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE }
.joinToString(separator = ".") { it.getReferencedName() }
.let(::FqName)
}
}
}
private fun KtSimpleNameExpression.isPartOfQualifiedExpression(): Boolean {
var parent = parent
while (parent is KtDotQualifiedExpression) {
if (parent.selectorExpression !== this) return true
parent = parent.parent
}
return false
}
private fun KtSimpleNameExpression.isPartOfUserTypeRefQualifier(): Boolean {
var parent = parent
while (parent is KtUserType) {
if (parent.referenceExpression !== this) return true
parent = parent.parent
}
return false
}
internal fun resolveSimpleNameReference(
ref: KtFirSimpleNameReference,
analysisSession: KtFirAnalysisSession
): Collection<KtSymbol> {
val expression = ref.expression
if (expression.isSyntheticOperatorReference()) return emptyList()
val symbolBuilder = analysisSession.firSymbolBuilder
val fir = expression.getOrBuildFir(analysisSession.firResolveState)
val session = analysisSession.firResolveState.rootModuleSession
return when (fir) {
is FirResolvedTypeRef -> getSymbolsForResolvedTypeRef(fir, expression, session, symbolBuilder)
is FirResolvedQualifier ->
getSymbolsForResolvedQualifier(fir, expression, session, symbolBuilder)
is FirAnnotation -> getSymbolsForAnnotationCall(fir, session, symbolBuilder)
is FirResolvedImport -> getSymbolsByResolvedImport(expression, symbolBuilder, fir, session)
is FirPackageDirective -> getSymbolsForPackageDirective(expression, symbolBuilder)
is FirFile -> getSymbolsByFirFile(symbolBuilder, fir)
is FirArrayOfCall -> {
// We can't yet find PsiElement for arrayOf, intArrayOf, etc.
emptyList()
}
is FirReturnExpression -> getSymbolsByReturnExpression(expression, fir, symbolBuilder)
is FirErrorNamedReference -> getSymbolsByErrorNamedReference(fir, symbolBuilder)
is FirVariableAssignment -> getSymbolsByVariableAssignment(fir, session, symbolBuilder)
is FirResolvedNamedReference -> getSymbolByResolvedNameReference(fir, expression, analysisSession, session, symbolBuilder)
is FirResolvable -> getSymbolsByResolvable(fir, expression, session, symbolBuilder)
is FirNamedArgumentExpression -> getSymbolsByNameArgumentExpression(expression, analysisSession, symbolBuilder)
else -> handleUnknownFirElement(expression, analysisSession, session, symbolBuilder)
}
}
private fun getSymbolsForPackageDirective(
expression: KtSimpleNameExpression,
symbolBuilder: KtSymbolByFirBuilder
): List<KtFirPackageSymbol> {
return listOfNotNull(getPackageSymbolFor(expression, symbolBuilder, forQualifiedType = false))
}
private fun getSymbolByResolvedNameReference(
fir: FirResolvedNamedReference,
expression: KtSimpleNameExpression,
analysisSession: KtFirAnalysisSession,
session: FirSession,
symbolBuilder: KtSymbolByFirBuilder
): Collection<KtSymbol> {
val parentAsCall = expression.parent as? KtCallExpression
if (parentAsCall != null) {
val firResolvable = parentAsCall.getOrBuildFirSafe<FirResolvable>(analysisSession.firResolveState)
if (firResolvable != null) {
return getSymbolsByResolvable(firResolvable, expression, session, symbolBuilder)
}
}
return fir.toTargetSymbol(session, symbolBuilder)
}
private fun KtSimpleNameExpression.isSyntheticOperatorReference() = when (this) {
is KtOperationReferenceExpression -> operationSignTokenType in syntheticTokenTypes
else -> false
}
@OptIn(ExperimentalStdlibApi::class)
private fun getSymbolsByVariableAssignment(
fir: FirVariableAssignment,
session: FirSession,
symbolBuilder: KtSymbolByFirBuilder
): Collection<KtSymbol> = fir.calleeReference.toTargetSymbol(session, symbolBuilder)
private fun getSymbolsByNameArgumentExpression(
expression: KtSimpleNameExpression,
analysisSession: KtFirAnalysisSession,
symbolBuilder: KtSymbolByFirBuilder
): Collection<KtSymbol> {
val ktValueArgumentName = expression.parent as? KtValueArgumentName ?: return emptyList()
val ktValueArgument = ktValueArgumentName.parent as? KtValueArgument ?: return emptyList()
val ktValueArgumentList = ktValueArgument.parent as? KtValueArgumentList ?: return emptyList()
val ktCallExpression = ktValueArgumentList.parent as? KtCallElement ?: return emptyList()
val firCall = ktCallExpression.getOrBuildFirSafe<FirCall>(analysisSession.firResolveState) ?: return emptyList()
val parameter = firCall.findCorrespondingParameter(ktValueArgument) ?: return emptyList()
return listOfNotNull(parameter.buildSymbol(symbolBuilder))
}
private fun FirCall.findCorrespondingParameter(ktValueArgument: KtValueArgument): FirValueParameter? =
argumentMapping?.entries?.firstNotNullOfOrNull { (firArgument, firParameter) ->
if (firArgument.psi == ktValueArgument) firParameter
else null
}
private fun handleUnknownFirElement(
expression: KtSimpleNameExpression,
analysisSession: KtFirAnalysisSession,
session: FirSession,
symbolBuilder: KtSymbolByFirBuilder
): List<KtSymbol> {
// Handle situation when we're in the middle/beginning of qualifier
// <caret>A.B.C.foo() or A.<caret>B.C.foo()
// NB: in this case we get some parent FIR, like FirBlock, FirProperty, FirFunction or the like
var parent = expression.parent as? KtDotQualifiedExpression
var unresolvedCounter = 1
while (parent != null) {
val selectorExpression = parent.selectorExpression ?: break
if (selectorExpression === expression) {
parent = parent.parent as? KtDotQualifiedExpression
continue
}
val parentFir = selectorExpression.getOrBuildFir(analysisSession.firResolveState)
if (parentFir is FirResolvedQualifier) {
var classId = parentFir.classId
while (unresolvedCounter > 0) {
unresolvedCounter--
classId = classId?.outerClassId
}
return listOfNotNull(classId?.toTargetPsi(session, symbolBuilder))
}
parent = parent.parent as? KtDotQualifiedExpression
unresolvedCounter++
}
return emptyList()
}
private fun getSymbolsByResolvable(
fir: FirResolvable,
expression: KtSimpleNameExpression,
session: FirSession,
symbolBuilder: KtSymbolByFirBuilder
): Collection<KtSymbol> {
val calleeReference =
if (fir is FirFunctionCall
&& fir.isImplicitFunctionCall()
&& expression is KtNameReferenceExpression
) {
// we are resolving implicit invoke call, like
// fun foo(a: () -> Unit) {
// <expression>a</expression>()
// }
(fir.dispatchReceiver as FirQualifiedAccessExpression).calleeReference
} else fir.calleeReference
return calleeReference.toTargetSymbol(session, symbolBuilder)
}
private fun getSymbolsByErrorNamedReference(
fir: FirErrorNamedReference,
symbolBuilder: KtSymbolByFirBuilder
): List<KtSymbol> =
fir.getCandidateSymbols().map { it.fir.buildSymbol(symbolBuilder) }
private fun getSymbolsByReturnExpression(
expression: KtSimpleNameExpression,
fir: FirReturnExpression,
symbolBuilder: KtSymbolByFirBuilder
): Collection<KtSymbol> {
return if (expression is KtLabelReferenceExpression) {
listOf(fir.target.labeledElement.buildSymbol(symbolBuilder))
} else emptyList()
}
private fun getSymbolsByFirFile(
symbolBuilder: KtSymbolByFirBuilder,
fir: FirFile
): List<KtSymbol> {
return listOf(symbolBuilder.buildSymbol(fir))
}
@OptIn(ExperimentalStdlibApi::class)
private fun getSymbolsByResolvedImport(
expression: KtSimpleNameExpression,
builder: KtSymbolByFirBuilder,
fir: FirResolvedImport,
session: FirSession
): List<KtSymbol> {
val fullFqName = fir.importedFqName
val selectedFqName = getQualifierSelected(expression, forQualifiedType = false)
val rawImportForSelectedFqName = buildImport {
importedFqName = selectedFqName
isAllUnder = false
}
val resolvedImport = FirImportResolveTransformer(session).transformImport(rawImportForSelectedFqName, null) as FirResolvedImport
val scope = FirExplicitSimpleImportingScope(listOf(resolvedImport), session, ScopeSession())
val selectedName = resolvedImport.importedName ?: return emptyList()
return buildList {
if (selectedFqName == fullFqName) {
// callables cannot be used as receiver expressions in imports
scope.processFunctionsByName(selectedName) { add(it.fir.buildSymbol(builder)) }
scope.processPropertiesByName(selectedName) { add(it.fir.buildSymbol(builder)) }
}
scope.processClassifiersByName(selectedName) { addIfNotNull(it.fir.buildSymbol(builder)) }
builder.createPackageSymbolIfOneExists(selectedFqName)?.let(::add)
}
}
private fun getSymbolsForResolvedTypeRef(
fir: FirResolvedTypeRef,
expression: KtSimpleNameExpression,
session: FirSession,
symbolBuilder: KtSymbolByFirBuilder,
): Collection<KtSymbol> {
val isPossiblyPackage = fir is FirErrorTypeRef && expression.isPartOfUserTypeRefQualifier()
val resultSymbol =
if (isPossiblyPackage) getPackageSymbolFor(expression, symbolBuilder, forQualifiedType = true)
else fir.toTargetSymbol(session, symbolBuilder)
return listOfNotNull(resultSymbol)
}
private fun getSymbolsForResolvedQualifier(
fir: FirResolvedQualifier,
expression: KtSimpleNameExpression,
session: FirSession,
symbolBuilder: KtSymbolByFirBuilder
): Collection<KtSymbol> {
val referencedSymbol = if (fir.resolvedToCompanionObject) {
(fir.symbol?.fir as? FirRegularClass)?.companionObject?.symbol
} else {
fir.symbol
}
if (referencedSymbol == null) {
// If referencedSymbol is null, it means the reference goes to a package.
val parent = expression.parent as? KtDotQualifiedExpression ?: return emptyList()
val fqNameSegments =
when (expression) {
parent.selectorExpression -> parent.fqNameSegments() ?: return emptyList()
parent.receiverExpression -> listOf(expression.getReferencedName())
else -> return emptyList()
}
return listOfNotNull(symbolBuilder.createPackageSymbolIfOneExists(FqName.fromSegments(fqNameSegments)))
}
val referencedClass = referencedSymbol.fir
val referencedSymbolsByFir = listOfNotNull(symbolBuilder.buildSymbol(referencedClass))
val firSourcePsi = fir.source.psi ?: referencedSymbolsByFir
if (firSourcePsi !is KtDotQualifiedExpression) return referencedSymbolsByFir
// When the source of an `FirResolvedQualifier` is a KtDotQualifiedExpression, we need to manually break up the qualified access and
// resolve individual parts of it because in FIR, the entire qualified access is one element.
if (referencedClass.isLocal) {
// TODO: handle local classes after KT-47135 is fixed
return referencedSymbolsByFir
} else {
var qualifiedAccess: KtDotQualifiedExpression = firSourcePsi
val referencedClassId =
if ((referencedClass as? FirRegularClass)?.isCompanion == true &&
(qualifiedAccess.selectorExpression as? KtNameReferenceExpression)?.getReferencedName() != referencedClass.classId.shortClassName.asString()
) {
// Remove the last companion name part if the qualified access does not contain it.
// This is needed because the companion name part is optional.
referencedClass.classId.outerClassId ?: return referencedSymbolsByFir
} else {
referencedClass.classId
}
val qualifiedAccessSegments = qualifiedAccess.fqNameSegments() ?: return referencedSymbolsByFir
assert(referencedClassId.asSingleFqName().pathSegments().takeLast(qualifiedAccessSegments.size)
.map { it.identifierOrNullIfSpecial } == qualifiedAccessSegments) {
"Referenced classId $referencedClassId should end with qualifiedAccess expression ${qualifiedAccess.text} "
}
// In the code below, we always maintain the contract that `classId` and `qualifiedAccess` should stay "in-sync", i.e. they
// refer to the same class and classId should be null if `qualifiedAccess` references to a package.
var classId: ClassId? = referencedClassId
// Handle nested classes.
while (classId != null) {
if (expression === qualifiedAccess.selectorExpression) {
return listOfNotNull(classId.toTargetPsi(session, symbolBuilder))
}
val outerClassId = classId.outerClassId
val receiverExpression = qualifiedAccess.receiverExpression
if (receiverExpression !is KtDotQualifiedExpression) {
// If the receiver is not a KtDotQualifiedExpression, it means we are hitting the end of nested receivers. In other
// words, this receiver expression should be pointing at an unqualified name of a class, whose class ID is
// `outerClassId`.
if (receiverExpression == expression) {
// If there is still an outer class, then return symbol of that class
outerClassId?.let { return listOfNotNull(it.toTargetPsi(session, symbolBuilder)) }
// Otherwise, it should be a package, so we return that
return listOfNotNull(symbolBuilder.createPackageSymbolIfOneExists(classId.packageFqName))
} else {
// This is unexpected. The code probably contains some weird structures. In this case, we just fail the resolution
// with zero results.
return emptyList()
}
}
qualifiedAccess = receiverExpression
classId = outerClassId
}
// Handle package names
var packageFqName = referencedClassId.packageFqName
while (!packageFqName.isRoot) {
if (expression === qualifiedAccess.selectorExpression) {
return listOfNotNull(symbolBuilder.createPackageSymbolIfOneExists(packageFqName))
}
val parentPackageFqName = packageFqName.parent()
val receiverExpression = qualifiedAccess.receiverExpression
if (receiverExpression !is KtDotQualifiedExpression) {
// If the receiver is not a KtDotQualifiedExpression, it means we are hitting the end of nested receivers. In other
// words, this receiver expression should be pointing at a top-level package now.
if (receiverExpression == expression) {
return listOfNotNull(symbolBuilder.createPackageSymbolIfOneExists(parentPackageFqName))
} else {
// This is unexpected. The code probably contains some weird structures. In this case, we just fail the resolution
// with zero results.
return emptyList()
}
}
qualifiedAccess = receiverExpression
packageFqName = parentPackageFqName
}
return referencedSymbolsByFir
}
}
/**
* Returns the segments of a qualified access PSI. For example, given `foo.bar.OuterClass.InnerClass`, this returns `["foo", "bar",
* "OuterClass", "InnerClass"]`.
*/
private fun KtDotQualifiedExpression.fqNameSegments(): List<String>? {
val result: MutableList<String> = mutableListOf()
var current: KtExpression = this
while (current is KtDotQualifiedExpression) {
result += (current.selectorExpression as? KtNameReferenceExpression)?.getReferencedName() ?: return null
current = current.receiverExpression
}
result += (current as? KtNameReferenceExpression)?.getReferencedName() ?: return null
result.reverse()
return result
}
private fun getSymbolsForAnnotationCall(
fir: FirAnnotation,
session: FirSession,
symbolBuilder: KtSymbolByFirBuilder
): Collection<KtSymbol> {
val type = fir.typeRef as? FirResolvedTypeRef ?: return emptyList()
return listOfNotNull(type.toTargetSymbol(session, symbolBuilder))
}
private fun findPossibleTypeQualifier(
qualifier: KtSimpleNameExpression,
wholeTypeFir: FirResolvedTypeRef
): ClassId? {
val qualifierToResolve = qualifier.parent as KtUserType
// FIXME make it work with generics in functional types (like () -> AA.BB<CC, AA.DD>)
val wholeType = when (val psi = wholeTypeFir.psi) {
is KtUserType -> psi
is KtTypeReference -> psi.typeElement?.unwrapNullability() as? KtUserType
else -> null
} ?: return null
val qualifiersToDrop = countQualifiersToDrop(wholeType, qualifierToResolve)
return wholeTypeFir.type.classId?.dropLastNestedClasses(qualifiersToDrop)
}
/**
* @return class id without [classesToDrop] last nested classes, or `null` if [classesToDrop] is too big.
*
* Example: `foo.bar.Baz.Inner` with 1 dropped class is `foo.bar.Baz`, and with 2 dropped class is `null`.
*/
private fun ClassId.dropLastNestedClasses(classesToDrop: Int) =
generateSequence(this) { it.outerClassId }.drop(classesToDrop).firstOrNull()
/**
* @return How many qualifiers needs to be dropped from [wholeType] to get [nestedType].
*
* Example: to get `foo.bar` from `foo.bar.Baz.Inner`, you need to drop 2 qualifiers (`Inner` and `Baz`).
*/
private fun countQualifiersToDrop(wholeType: KtUserType, nestedType: KtUserType): Int {
val qualifierIndex = generateSequence(wholeType) { it.qualifier }.indexOf(nestedType)
require(qualifierIndex != -1) { "Whole type $wholeType should contain $nestedType, but it didn't" }
return qualifierIndex
}
private val syntheticTokenTypes = TokenSet.create(KtTokens.ELVIS, KtTokens.EXCLEXCL)
}
@@ -0,0 +1,72 @@
/*
* 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 com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
internal class KtFirSimpleNameReference(
expression: KtSimpleNameExpression
) : KtSimpleNameReference(expression), KtFirReference {
private val isAnnotationCall: Boolean
get() {
val ktUserType = expression.parent as? KtUserType ?: return false
val ktTypeReference = ktUserType.parent as? KtTypeReference ?: return false
val ktConstructorCalleeExpression = ktTypeReference.parent as? KtConstructorCalleeExpression ?: return false
return ktConstructorCalleeExpression.parent is KtAnnotationEntry
}
private fun KtAnalysisSession.fixUpAnnotationCallResolveToCtor(resultsToFix: Collection<KtSymbol>): Collection<KtSymbol> {
if (resultsToFix.isEmpty() || !isAnnotationCall) return resultsToFix
return resultsToFix.map { targetSymbol ->
if (targetSymbol is KtFirNamedClassOrObjectSymbol && targetSymbol.classKind == KtClassKind.ANNOTATION_CLASS) {
targetSymbol.getMemberScope().getConstructors().firstOrNull() ?: targetSymbol
} else targetSymbol
}
}
override fun KtAnalysisSession.resolveToSymbols(): Collection<KtSymbol> {
check(this is KtFirAnalysisSession)
val results = FirReferenceResolveHelper.resolveSimpleNameReference(this@KtFirSimpleNameReference, this)
//This fix-up needed to resolve annotation call into annotation constructor (but not into the annotation type)
return fixUpAnnotationCallResolveToCtor(results)
}
override fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean {
return true // TODO
}
override fun isReferenceTo(element: PsiElement): Boolean {
return resolve() == element //todo
}
override fun handleElementRename(newElementName: String): PsiElement? {
TODO("Not yet implemented")
}
override fun bindToElement(element: PsiElement, shorteningMode: ShorteningMode): PsiElement {
TODO("Not yet implemented")
}
override fun bindToFqName(fqName: FqName, shorteningMode: ShorteningMode, targetElement: PsiElement?): PsiElement {
TODO("Not yet implemented")
}
override fun getImportAlias(): KtImportAlias? {
TODO("Not yet implemented")
}
override val resolver get() = KtFirReferenceResolver
}
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2021 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 com.intellij.psi.ContributedReferenceHost
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.psi.PsiReferenceService
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.util.containers.ConcurrentFactoryMap
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.idea.references.*
import org.jetbrains.kotlin.psi.KotlinReferenceProvidersService
import org.jetbrains.kotlin.utils.SmartList
class HLApiReferenceProviderService : KotlinReferenceProvidersService() {
private val originalProvidersBinding: MultiMap<Class<out PsiElement>, KotlinPsiReferenceProvider>
private val providersBindingCache: Map<Class<out PsiElement>, List<KotlinPsiReferenceProvider>>
init {
val registrar = KotlinPsiReferenceRegistrar()
KotlinReferenceProviderContributor.getInstance().registerReferenceProviders(registrar)
originalProvidersBinding = registrar.providers
providersBindingCache = ConcurrentFactoryMap.createMap<Class<out PsiElement>, List<KotlinPsiReferenceProvider>> { klass ->
val result = SmartList<KotlinPsiReferenceProvider>()
for (bindingClass in originalProvidersBinding.keySet()) {
if (bindingClass.isAssignableFrom(klass)) {
result.addAll(originalProvidersBinding.get(bindingClass))
}
}
result
}
}
private fun doGetKotlinReferencesFromProviders(context: PsiElement): Array<PsiReference> {
val providers: List<KotlinPsiReferenceProvider>? = providersBindingCache[context.javaClass]
if (providers.isNullOrEmpty()) return PsiReference.EMPTY_ARRAY
val result = SmartList<PsiReference>()
for (provider in providers) {
result.addAll(provider.getReferencesByElement(context))
}
if (result.isEmpty()) {
return PsiReference.EMPTY_ARRAY
}
return result.toTypedArray()
}
override fun getReferences(psiElement: PsiElement): Array<PsiReference> {
if (psiElement is ContributedReferenceHost) {
return ReferenceProvidersRegistry.getReferencesFromProviders(psiElement, PsiReferenceService.Hints.NO_HINTS)
}
return CachedValuesManager.getCachedValue(psiElement) {
CachedValueProvider.Result.create(
doGetKotlinReferencesFromProviders(psiElement),
PsiModificationTracker.MODIFICATION_COUNT
)
}
}
}
@@ -0,0 +1,21 @@
/*
* 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
class KotlinFirReferenceContributor : KotlinReferenceProviderContributor {
override fun registerReferenceProviders(registrar: KotlinPsiReferenceRegistrar) {
with(registrar) {
registerProvider(factory = ::KtFirSimpleNameReference)
registerProvider(factory = ::KtFirForLoopInReference)
registerProvider(factory = ::KtFirInvokeFunctionReference)
registerProvider(factory = ::KtFirPropertyDelegationMethodsReference)
registerProvider(factory = ::KtFirDestructuringDeclarationReference)
registerProvider(factory = ::KtFirArrayAccessReference)
registerProvider(factory = ::KtFirConstructorDelegationReference)
registerProvider(factory = ::KtFirCollectionLiteralReference)
}
}
}
@@ -0,0 +1,28 @@
/*
* 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 com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.analysis.api.fir.getCalleeSymbol
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.buildSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
class KtFirArrayAccessReference(
expression: KtArrayAccessExpression
) : KtArrayAccessReference(expression), KtFirReference {
override fun KtAnalysisSession.resolveToSymbols(): Collection<KtSymbol> {
check(this is KtFirAnalysisSession)
val fir = element.getOrBuildFirSafe<FirFunctionCall>(firResolveState) ?: return emptyList()
return listOfNotNull(fir.getCalleeSymbol()?.fir?.buildSymbol(firSymbolBuilder))
}
override fun handleElementRename(newElementName: String): PsiElement = TODO("Not yet implemented")
}
@@ -0,0 +1,56 @@
/*
* 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.FirSimpleFunction
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.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.symbolProvider.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.functionLikeBuilder.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.replaceFirstChar(Char::lowercaseChar)}Of")
}
}
@@ -0,0 +1,25 @@
/*
* 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.expressions.FirDelegatedConstructorCall
import org.jetbrains.kotlin.analysis.api.fir.getResolvedKtSymbolOfNameReference
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.psi.KtConstructorDelegationReferenceExpression
class KtFirConstructorDelegationReference(
expression: KtConstructorDelegationReferenceExpression
) : KtConstructorDelegationReference(expression), KtFirReference {
override fun KtAnalysisSession.resolveToSymbols(): Collection<KtSymbol> {
check(this is KtFirAnalysisSession)
val fir = expression.getOrBuildFirSafe<FirDelegatedConstructorCall>(firResolveState) ?: return emptyList()
return listOfNotNull(fir.calleeReference.getResolvedKtSymbolOfNameReference(firSymbolBuilder))
}
}
@@ -0,0 +1,36 @@
/*
* 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.FirProperty
import org.jetbrains.kotlin.fir.expressions.FirComponentCall
import org.jetbrains.kotlin.analysis.api.fir.getCalleeSymbol
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.buildSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
class KtFirDestructuringDeclarationReference(
element: KtDestructuringDeclarationEntry
) : KtDestructuringDeclarationReference(element), KtFirReference {
override fun canRename(): Boolean = false //todo
override fun KtAnalysisSession.resolveToSymbols(): Collection<KtSymbol> {
check(this is KtFirAnalysisSession)
val fir = expression.getOrBuildFirSafe<FirProperty>(firResolveState) ?: return emptyList()
return listOfNotNull(
fir.buildSymbol(firSymbolBuilder),
getComponentNSymbol(fir)
)
}
private fun KtFirAnalysisSession.getComponentNSymbol(fir: FirProperty): KtSymbol? {
val componentFunctionSymbol = (fir.initializer as? FirComponentCall)?.getCalleeSymbol() ?: return null
return componentFunctionSymbol.fir.buildSymbol(firSymbolBuilder)
}
}
@@ -0,0 +1,40 @@
/*
* 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.FirProperty
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirWhileLoop
import org.jetbrains.kotlin.analysis.api.fir.getResolvedSymbolOfNameReference
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.buildSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.psi.KtForExpression
open class KtFirForLoopInReference(expression: KtForExpression) : KtForLoopInReference(expression), KtFirReference {
override fun KtAnalysisSession.resolveToSymbols(): Collection<KtSymbol> {
check(this is KtFirAnalysisSession)
val firLoop = expression.getOrBuildFirSafe<FirWhileLoop>(firResolveState) ?: return emptyList()
val condition = firLoop.condition as? FirFunctionCall
val iterator = this@KtFirForLoopInReference.run {
val callee = (condition?.explicitReceiver as? FirQualifiedAccessExpression)?.calleeReference
(callee?.getResolvedSymbolOfNameReference()?.fir as? FirProperty)?.getInitializerFunctionCall()
}
val hasNext = condition?.calleeReference?.getResolvedSymbolOfNameReference()
val next = (firLoop.block.statements.firstOrNull() as? FirProperty?)?.getInitializerFunctionCall()
return listOfNotNull(
iterator?.fir?.buildSymbol(firSymbolBuilder),
hasNext?.fir?.buildSymbol(firSymbolBuilder),
next?.fir?.buildSymbol(firSymbolBuilder),
)
}
private fun FirProperty.getInitializerFunctionCall() =
(initializer as? FirFunctionCall)?.calleeReference?.getResolvedSymbolOfNameReference()
}
@@ -0,0 +1,26 @@
/*
* 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.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.calls.KtVariableWithInvokeFunctionCall
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtExpression
class KtFirInvokeFunctionReference(expression: KtCallExpression) : KtInvokeFunctionReference(expression), KtFirReference {
override fun doRenameImplicitConventionalCall(newName: String?): KtExpression {
TODO("Not yet implemented")
}
override fun KtAnalysisSession.resolveToSymbols(): Collection<KtSymbol> {
val call = expression.resolveCall() ?: return emptyList()
if (call is KtVariableWithInvokeFunctionCall) {
return call.targetFunction.candidates
}
return emptyList()
}
}
@@ -0,0 +1,39 @@
/*
* 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.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.analysis.api.fir.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.buildSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtPropertyDelegate
class KtFirPropertyDelegationMethodsReference(
element: KtPropertyDelegate
) : KtPropertyDelegationMethodsReference(element), KtFirReference {
override fun KtAnalysisSession.resolveToSymbols(): Collection<KtSymbol> {
check(this is KtFirAnalysisSession)
val property = (expression.parent as? KtElement)?.getOrBuildFirSafe<FirProperty>(firResolveState) ?: return emptyList()
if (property.delegate == null) return emptyList()
val getValueSymbol = (property.getter?.singleStatementOfType<FirReturnExpression>()?.result as? FirFunctionCall)?.getCalleeSymbol()
val setValueSymbol = property.setter?.singleStatementOfType<FirFunctionCall>()?.getCalleeSymbol()
return listOfNotNull(
getValueSymbol?.fir?.buildSymbol(firSymbolBuilder),
setValueSymbol?.fir?.buildSymbol(firSymbolBuilder)
)
}
private inline fun <reified S : FirStatement> FirPropertyAccessor.singleStatementOfType(): S? =
body?.statements?.singleOrNull() as? S
}
@@ -0,0 +1,41 @@
/*
* 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 com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.fir.findReferencePsi
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.KtSymbolBasedReference
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin
interface KtFirReference : KtReference, KtSymbolBasedReference {
fun getResolvedToPsi(analysisSession: KtAnalysisSession): Collection<PsiElement> = with(analysisSession) {
resolveToSymbols().flatMap { symbol ->
when (symbol) {
is KtFirSymbol<*> -> getPsiDeclarations(symbol)
else -> listOfNotNull(symbol.psi)
}
}
}
private fun KtAnalysisSession.getPsiDeclarations(symbol: KtFirSymbol<*>): Collection<PsiElement> {
val intersectionOverriddenSymbolsOrSingle = when {
symbol.origin == KtSymbolOrigin.INTERSECTION_OVERRIDE && symbol is KtCallableSymbol -> symbol.getIntersectionOverriddenSymbols()
else -> listOf(symbol)
}
return intersectionOverriddenSymbolsOrSingle.mapNotNull { it.findPsiForReferenceResolve() }
}
private fun KtSymbol.findPsiForReferenceResolve(): PsiElement? {
require(this is KtFirSymbol<*>)
return firRef.withFir { it.findReferencePsi() }
}
override val resolver get() = KtFirReferenceResolver
}
@@ -0,0 +1,40 @@
/*
* 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 com.intellij.openapi.diagnostic.ControlFlowException
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementResolveResult
import com.intellij.psi.ResolveResult
import com.intellij.psi.impl.source.resolve.ResolveCache
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext
import org.jetbrains.kotlin.analysis.api.tokens.HackToForceAllowRunningAnalyzeOnEDT
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.fir.utils.runInPossiblyEdtThread
object KtFirReferenceResolver : ResolveCache.PolyVariantResolver<KtReference> {
class KotlinResolveResult(element: PsiElement) : PsiElementResolveResult(element)
@OptIn(HackToForceAllowRunningAnalyzeOnEDT::class)
override fun resolve(ref: KtReference, incompleteCode: Boolean): Array<ResolveResult> {
check(ref is KtFirReference) { "reference should be FirKtReference, but was ${ref::class}" }
check(ref is AbstractKtReference<*>) { "reference should be AbstractKtReference, but was ${ref::class}" }
return runInPossiblyEdtThread {
val resolveToPsiElements = try {
analyse(ref.expression) { ref.getResolvedToPsi(this) }
} catch (e: Throwable) {
if (e is ControlFlowException) throw e
throw KtReferenceResolveException(ref, e)
}
resolveToPsiElements.map { KotlinResolveResult(it) }.toTypedArray()
}
}
}
class KtReferenceResolveException(
reference: KtReference,
cause: Throwable
) : RuntimeException("Reference is:\n${reference.element.getElementTextInContext()}", cause)
@@ -0,0 +1,350 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.renderer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.containingClassForLocal
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedError
import org.jetbrains.kotlin.fir.resolve.inference.*
import org.jetbrains.kotlin.fir.resolve.toFirRegularClass
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.LookupTagInternals
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.tryCollectDesignation
import org.jetbrains.kotlin.analysis.api.components.KtTypeRendererOptions
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
internal class ConeTypeIdeRenderer(
private val session: FirSession,
private val options: KtTypeRendererOptions,
) {
companion object {
const val ERROR_TYPE_TEXT = "ERROR_TYPE"
}
private fun StringBuilder.appendError(message: String? = null) {
append(ERROR_TYPE_TEXT)
if (message != null) append(" <$message>")
}
private var filterExtensionFunctionType: Boolean = false
private fun StringBuilder.renderAnnotationList(annotations: List<FirAnnotation>?) {
if (annotations != null) {
val filteredExtensionIfNeeded = annotations.applyIf(filterExtensionFunctionType) {
annotations.filterNot { it.toAnnotationClassId() == StandardClassIds.extensionFunctionType }
}
renderAnnotations(this@ConeTypeIdeRenderer, filteredExtensionIfNeeded, session)
}
}
fun renderType(type: ConeTypeProjection, annotations: List<FirAnnotation>? = null): String = buildString {
when (type) {
is ConeKotlinErrorType -> {
renderErrorType(type)
}
//is Dynamic??? -> append("dynamic")
is ConeClassLikeType -> {
if (options.renderFunctionType && shouldRenderAsPrettyFunctionType(type)) {
val oldFilterExtensionFunctionType = filterExtensionFunctionType
filterExtensionFunctionType = true
renderAnnotationList(annotations)
renderFunctionType(type)
filterExtensionFunctionType = oldFilterExtensionFunctionType
} else {
renderAnnotationList(annotations)
renderTypeConstructorAndArguments(type)
}
}
is ConeTypeParameterType -> {
renderAnnotationList(annotations)
append(type.lookupTag.name.asString())
renderNullability(type.type)
}
is ConeIntersectionType -> {
renderAnnotationList(annotations)
type.intersectedTypes.joinTo(this, "&", prefix = "(", postfix = ")") {
renderType(it)
}
renderNullability(type.type)
}
is ConeFlexibleType -> {
renderAnnotationList(annotations)
append(renderFlexibleType(renderType(type.lowerBound), renderType(type.upperBound)))
}
else -> appendError("Unexpected cone type ${type::class.qualifiedName}")
}
}
private fun StringBuilder.renderErrorType(type: ConeKotlinErrorType) {
val diagnostic = type.diagnostic
if (options.renderUnresolvedTypeAsResolved && diagnostic is ConeUnresolvedError) {
val qualifierRendered = diagnostic.qualifier?.let { FqName(it).render() }.orEmpty()
append(qualifierRendered)
} else {
appendError(diagnostic.reason)
}
}
private fun StringBuilder.renderNullability(type: ConeKotlinType) {
if (type.nullability == ConeNullability.NULLABLE) {
append("?")
}
}
fun shouldRenderAsPrettyFunctionType(type: ConeKotlinType): Boolean {
return type.type.isBuiltinFunctionalType(session) && type.typeArguments.none { it.kind == ProjectionKind.STAR }
}
private fun differsOnlyInNullability(lower: String, upper: String) =
lower == upper.replace("?", "") || upper.endsWith("?") && ("$lower?") == upper || "($lower)?" == upper
private fun renderFlexibleType(lowerRendered: String, upperRendered: String): String {
if (differsOnlyInNullability(lowerRendered, upperRendered)) {
if (upperRendered.startsWith("(")) {
// the case of complex type, e.g. (() -> Unit)?
return "($lowerRendered)!"
}
return "$lowerRendered!"
}
val kotlinCollectionsPrefix = "kotlin.collections."
val mutablePrefix = "Mutable"
// java.util.List<Foo> -> (Mutable)List<Foo!>!
val simpleCollection = replacePrefixes(
lowerRendered,
kotlinCollectionsPrefix + mutablePrefix,
upperRendered,
kotlinCollectionsPrefix,
"$kotlinCollectionsPrefix($mutablePrefix)"
)
if (simpleCollection != null) return simpleCollection
// java.util.Map.Entry<Foo, Bar> -> (Mutable)Map.(Mutable)Entry<Foo!, Bar!>!
val mutableEntry = replacePrefixes(
lowerRendered,
kotlinCollectionsPrefix + "MutableMap.MutableEntry",
upperRendered,
kotlinCollectionsPrefix + "Map.Entry",
"$kotlinCollectionsPrefix(Mutable)Map.(Mutable)Entry"
)
if (mutableEntry != null) return mutableEntry
val kotlinPrefix = "kotlin."
// Foo[] -> Array<(out) Foo!>!
val array = replacePrefixes(
lowerRendered,
kotlinPrefix + "Array<",
upperRendered,
kotlinPrefix + "Array<out ",
kotlinPrefix + "Array<(out) "
)
if (array != null) return array
return "($lowerRendered..$upperRendered)"
}
private fun replacePrefixes(
lowerRendered: String,
lowerPrefix: String,
upperRendered: String,
upperPrefix: String,
foldedPrefix: String
): String? {
if (lowerRendered.startsWith(lowerPrefix) && upperRendered.startsWith(upperPrefix)) {
val lowerWithoutPrefix = lowerRendered.substring(lowerPrefix.length)
val upperWithoutPrefix = upperRendered.substring(upperPrefix.length)
val flexibleCollectionName = foldedPrefix + lowerWithoutPrefix
if (lowerWithoutPrefix == upperWithoutPrefix) return flexibleCollectionName
if (differsOnlyInNullability(lowerWithoutPrefix, upperWithoutPrefix)) {
return "$flexibleCollectionName!"
}
}
return null
}
private fun FirRegularClass.collectForLocal(): List<FirClassLikeDeclaration> {
require(isLocal)
var containingClassLookUp = containingClassForLocal()
val designation = mutableListOf<FirClassLikeDeclaration>(this)
@OptIn(LookupTagInternals::class)
while (containingClassLookUp != null && containingClassLookUp.classId.isLocal) {
val currentClass = containingClassLookUp.toFirRegularClass(moduleData.session) ?: break
designation.add(currentClass)
containingClassLookUp = currentClass.containingClassForLocal()
}
return designation
}
private fun collectDesignationPathForLocal(declaration: FirDeclaration): List<FirDeclaration>? {
@OptIn(LookupTagInternals::class)
val containingClass = when (declaration) {
is FirCallableDeclaration -> declaration.containingClass()?.toFirRegularClass(declaration.moduleData.session)
is FirAnonymousObject -> return listOf(declaration)
is FirClassLikeDeclaration -> declaration.let {
if (!declaration.isLocal) return null
(it as? FirRegularClass)?.containingClassForLocal()?.toFirRegularClass(declaration.moduleData.session)
}
else -> error("Invalid declaration ${declaration.renderWithType()}")
} ?: return listOf(declaration)
return if(containingClass.isLocal) { containingClass.collectForLocal().reversed() } else null
}
private fun StringBuilder.renderTypeConstructorAndArguments(type: ConeClassLikeType) {
fun renderTypeArguments(typeArguments: Array<out ConeTypeProjection>, range: IntRange) {
if (range.any()) {
typeArguments.slice(range).joinTo(this, ", ", prefix = "<", postfix = ">") {
renderTypeProjection(it)
}
}
}
val classSymbolToRender = type.lookupTag.toSymbol(session)
if (classSymbolToRender == null) {
appendError("Unresolved type")
return
}
if (!options.shortQualifiedNames && !classSymbolToRender.classId.isLocal) {
val packageName = classSymbolToRender.classId.packageFqName.asString()
if (packageName.isNotEmpty()) {
append(packageName).append(".")
}
}
if (classSymbolToRender !is FirRegularClassSymbol) {
append(classSymbolToRender.classId.shortClassName)
if (type.typeArguments.any()) {
type.typeArguments.joinTo(this, ", ", prefix = "<", postfix = ">") {
renderTypeProjection(it)
}
}
return
}
val designation = classSymbolToRender.fir.let {
val nonLocalDesignation = it.tryCollectDesignation()
nonLocalDesignation?.toSequence(includeTarget = true)?.toList()
?: collectDesignationPathForLocal(it)
?: emptyList()
}
var typeParametersLeft = type.typeArguments.count()
fun needToRenderTypeParameters(index: Int): Boolean {
if (typeParametersLeft <= 0) return false
return index == designation.lastIndex ||
(designation[index] as? FirRegularClass)?.isInner == true ||
(designation[index + 1] as? FirRegularClass)?.isInner == true
}
designation.filterIsInstance<FirRegularClass>().forEachIndexed { index, currentClass ->
if (index != 0) append(".")
append(currentClass.name)
if (needToRenderTypeParameters(index)) {
val typeParametersCount = currentClass.typeParameters.count { it is FirTypeParameter }
val begin = typeParametersLeft - typeParametersCount
val end = typeParametersLeft
check(begin >= 0)
typeParametersLeft -= typeParametersCount
renderTypeArguments(type.typeArguments, begin until end)
}
}
renderNullability(type)
}
private fun renderTypeProjection(typeProjection: ConeTypeProjection): String {
val type = typeProjection.type?.let(::renderType) ?: "???"
return when (typeProjection.kind) {
ProjectionKind.STAR -> "*"
ProjectionKind.IN -> "in $type"
ProjectionKind.OUT -> "out $type"
ProjectionKind.INVARIANT -> type
}
}
private fun StringBuilder.renderFunctionType(type: ConeClassLikeType) {
val lengthBefore = length
val hasAnnotations = length != lengthBefore
val isSuspend = type.isSuspendFunctionType(session)
val isNullable = type.isMarkedNullable
val receiverType = type.receiverType(session)
val needParenthesis = isNullable || (hasAnnotations && receiverType != null)
if (needParenthesis) {
if (isSuspend) {
insert(lengthBefore, '(')
} else {
if (hasAnnotations) {
check(last() == ' ')
if (get(lastIndex - 1) != ')') {
// last annotation rendered without parenthesis - need to add them otherwise parsing will be incorrect
insert(lastIndex, "()")
}
}
append("(")
}
}
if (isSuspend) {
append("suspend")
append(" ")
}
if (receiverType != null) {
val surroundReceiver = shouldRenderAsPrettyFunctionType(receiverType) &&
!receiverType.isMarkedNullable ||
receiverType.isSuspendFunctionType(session)
if (surroundReceiver) {
append("(")
}
append(renderType(receiverType))
if (surroundReceiver) {
append(")")
}
append(".")
}
append("(")
val notNullParametersType = type
.valueParameterTypesIncludingReceiver(session)
.applyIf(receiverType != null) { drop(1) }
notNullParametersType.forEachIndexed { index, typeProjection ->
if (index != 0) append(", ")
append(renderTypeProjection(typeProjection))
}
append(") -> ")
val returnType = type.returnType(session)
append(renderType(returnType))
if (needParenthesis) append(")")
renderNullability(type)
}
}
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.renderer
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.analysis.api.fir.utils.mapAnnotationParameters
internal fun StringBuilder.renderAnnotations(
coneTypeIdeRenderer: ConeTypeIdeRenderer,
annotations: List<FirAnnotation>,
session: FirSession
) {
for (annotation in annotations) {
if (!annotation.isParameterName()) {
append(renderAnnotation(annotation, coneTypeIdeRenderer, session))
append(" ")
}
}
}
private fun FirAnnotation.isParameterName(): Boolean {
return toAnnotationClassId()?.asSingleFqName() == StandardNames.FqNames.parameterName
}
private fun renderAnnotation(annotation: FirAnnotation, coneTypeIdeRenderer: ConeTypeIdeRenderer, session: FirSession): String {
return buildString {
append('@')
val resolvedTypeRef = annotation.typeRef as? FirResolvedTypeRef
check(resolvedTypeRef != null)
append(coneTypeIdeRenderer.renderType(resolvedTypeRef.type))
val arguments = renderAndSortAnnotationArguments(annotation, session)
if (arguments.isNotEmpty()) {
arguments.joinTo(this, ", ", "(", ")")
}
}
}
private fun renderAndSortAnnotationArguments(descriptor: FirAnnotation, session: FirSession): List<String> {
val argumentList = mapAnnotationParameters(descriptor, session).entries.map { (name, value) ->
"$name = ${renderConstant(value)}"
}
return argumentList.sorted()
}
private fun renderConstant(value: FirExpression): String {
return when (value) {
is FirConstExpression<*> -> value.toString()
else -> "NOT_CONST_EXPRESSION"
}
}
@@ -0,0 +1,707 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.renderer
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions
import org.jetbrains.kotlin.analysis.api.components.RendererModifier
import org.jetbrains.kotlin.analysis.api.fir.types.PublicTypeApproximator
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
internal class FirIdeRenderer private constructor(
private var containingDeclaration: FirDeclaration?,
private val options: KtDeclarationRendererOptions,
private val session: FirSession
) : FirVisitor<Unit, StringBuilder>() {
private val typeIdeRenderer: ConeTypeIdeRenderer = ConeTypeIdeRenderer(session, options.typeRendererOptions)
private fun StringBuilder.renderAnnotations(annotated: FirAnnotatedDeclaration) {
if (RendererModifier.ANNOTATIONS in options.modifiers) {
renderAnnotations(typeIdeRenderer, annotated.annotations, session)
}
}
private fun renderType(type: ConeTypeProjection, annotations: List<FirAnnotation>? = null): String =
typeIdeRenderer.renderType(type, annotations)
private fun renderType(firRef: FirTypeRef, approximate: Boolean = false): String {
require(firRef is FirResolvedTypeRef)
val approximatedIfNeeded = approximate.ifTrue {
PublicTypeApproximator.approximateTypeToPublicDenotable(firRef.coneType, session)
} ?: firRef.coneType
val annotations = if (RendererModifier.ANNOTATIONS in options.modifiers) {
firRef.annotations
} else {
null
}
return renderType(approximatedIfNeeded, annotations)
}
private fun StringBuilder.renderName(declaration: FirDeclaration) {
if (declaration is FirAnonymousObject) {
append("<no name provided>")
return
}
val name = when (declaration) {
is FirRegularClass -> declaration.name
is FirSimpleFunction -> declaration.name
is FirProperty -> declaration.name
is FirValueParameter -> declaration.name
is FirTypeParameter -> declaration.name
is FirTypeAlias -> declaration.name
is FirEnumEntry -> declaration.name
else -> TODO("Unexpected declaration ${declaration::class.qualifiedName}")
}
append(name.render())
}
private fun StringBuilder.renderCompanionObjectName(firClass: FirRegularClass) {
if (firClass.name != SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT) {
tabRightBySpace()
append(firClass.name.render())
}
}
private fun StringBuilder.renderVisibility(visibility: Visibility) {
if (RendererModifier.VISIBILITY !in options.modifiers) return
val currentVisibility = when (visibility) {
Visibilities.Local -> Visibilities.Public
Visibilities.PrivateToThis -> Visibilities.Public
Visibilities.InvisibleFake -> Visibilities.Public
Visibilities.Inherited -> Visibilities.Public
Visibilities.Unknown -> Visibilities.Public
else -> visibility
}.applyIf(options.normalizedVisibilities) {
normalize()
}
if (currentVisibility == Visibilities.DEFAULT_VISIBILITY) return
append(currentVisibility.internalDisplayName)
append(" ")
}
private fun StringBuilder.renderModality(modality: Modality, defaultModality: Modality) {
if (modality == defaultModality) return
renderModifier(RendererModifier.MODALITY in options.modifiers, modality.name.toLowerCaseAsciiOnly())
}
private fun FirMemberDeclaration.implicitModalityWithoutExtensions(containingDeclaration: FirDeclaration?): Modality {
if (this is FirRegularClass) {
return if (classKind == ClassKind.INTERFACE) Modality.ABSTRACT else Modality.FINAL
}
val containingFirClass = containingDeclaration as? FirRegularClass ?: return Modality.FINAL
if (this !is FirCallableDeclaration) return Modality.FINAL
if (isOverride) {
if (containingFirClass.modality != Modality.FINAL) return Modality.OPEN
}
return if (containingFirClass.classKind == ClassKind.INTERFACE && this.visibility != Visibilities.Private) {
if (this.modality == Modality.ABSTRACT) Modality.ABSTRACT else Modality.OPEN
} else
Modality.FINAL
}
private fun StringBuilder.renderModalityForCallable(
callable: FirCallableDeclaration,
containingDeclaration: FirDeclaration?
) {
val modality = callable.modality ?: return
val isTopLevel = containingDeclaration == null
if (!isTopLevel || modality != Modality.FINAL) {
if (callable.isOverride) return
renderModality(modality, callable.implicitModalityWithoutExtensions(containingDeclaration))
}
}
private fun StringBuilder.renderOverride(callableMember: FirCallableDeclaration) {
if (RendererModifier.OVERRIDE !in options.modifiers) return
renderModifier(callableMember.isOverride || options.forceRenderingOverrideModifier, "override")
}
private fun StringBuilder.renderModifier(value: Boolean, modifier: String) {
if (value) {
append(modifier)
append(" ")
}
}
private fun StringBuilder.renderMemberModifiers(declaration: FirMemberDeclaration) {
renderModifier(declaration.isExternal, "external")
renderModifier(RendererModifier.EXPECT in options.modifiers && declaration.isExpect, "expect")
renderModifier(RendererModifier.ACTUAL in options.modifiers && declaration.isActual, "actual")
}
private fun StringBuilder.renderAdditionalModifiers(firMember: FirMemberDeclaration) {
val isOperator =
firMember.isOperator//TODO make similar to functionDescriptor.overriddenDescriptors.none { it.isOperator }
val isInfix =
firMember.isInfix//TODO make similar to functionDescriptor.overriddenDescriptors.none { it.isInfix }
renderModifier(firMember.isTailRec, "tailrec")
renderSuspendModifier(firMember)
renderModifier(firMember.isInline, "inline")
renderModifier(isInfix, "infix")
renderModifier(RendererModifier.OPERATOR in options.modifiers && isOperator, "operator")
}
private fun StringBuilder.renderSuspendModifier(functionDescriptor: FirMemberDeclaration) {
renderModifier(functionDescriptor.isSuspend, "suspend")
}
override fun visitValueParameter(valueParameter: FirValueParameter, data: StringBuilder) {
with(data) {
appendLine()
appendTabs()
append("value-parameter").append(" ")
renderValueParameter(valueParameter)
}
}
override fun visitProperty(property: FirProperty, data: StringBuilder) = with(data) {
appendLine()
appendTabs()
if (options.renderDeclarationHeader) {
renderAnnotations(property)
renderVisibility(property.visibility)
renderModifier(RendererModifier.CONST in options.modifiers && property.isConst, "const")
renderMemberModifiers(property)
renderModalityForCallable(property, containingDeclaration)
renderOverride(property)
renderModifier(RendererModifier.LATEINIT in options.modifiers && property.isLateInit, "lateinit")
renderValVarPrefix(property)
renderTypeParameters(property.typeParameters, true)
}
renderReceiver(property)
renderName(property)
append(": ").append(renderType(property.returnTypeRef, approximate = options.approximateTypes))
renderWhereSuffix(property.typeParameters)
fun FirPropertyAccessor?.needToRender() = this != null && (hasBody || visibility != property.visibility)
val needToRenderAccessors = options.renderContainingDeclarations &&
(property.getter.needToRender() || (property.isVar && property.setter.needToRender()))
fun FirPropertyAccessor?.render(isGetterByDefault: Boolean) {
if (this == null) {
appendLine()
appendTabs()
append(if (isGetterByDefault) "get" else "set")
} else {
visitPropertyAccessor(this, data)
}
}
if (needToRenderAccessors) {
underBlockDeclaration(property, withBrackets = false) {
property.getter.render(isGetterByDefault = true)
if (property.isVar) property.setter.render(isGetterByDefault = false)
}
}
}
override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor, data: StringBuilder) {
require(containingDeclaration is FirProperty) { "Invalid containing declaration" }
with(data) {
appendLine()
appendTabs()
if (options.renderDeclarationHeader) {
renderAnnotations(propertyAccessor)
renderVisibility(propertyAccessor.visibility)
renderModalityForCallable(propertyAccessor, containingDeclaration)
renderMemberModifiers(propertyAccessor)
renderAdditionalModifiers(propertyAccessor)
}
append(if (propertyAccessor.isGetter) "get" else "set")
if (propertyAccessor.isSetter) {
append("(value: ")
val renderedType = propertyAccessor.valueParameters.singleOrNull()?.returnTypeRef?.let { renderType(it) }
if (renderedType != null) append(renderedType) else append(ConeTypeIdeRenderer.ERROR_TYPE_TEXT)
append(")")
} else {
append("()")
}
}
if (options.renderContainingDeclarations) {
propertyAccessor.body?.let {
underBlockDeclaration(propertyAccessor, it, data)
}
}
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: StringBuilder) {
with(data) {
appendLine()
appendTabs()
if (options.renderDeclarationHeader) {
renderAnnotations(simpleFunction)
renderVisibility(simpleFunction.visibility)
renderModalityForCallable(simpleFunction, containingDeclaration)
renderMemberModifiers(simpleFunction)
renderOverride(simpleFunction)
renderAdditionalModifiers(simpleFunction)
append("fun ")
renderTypeParameters(simpleFunction.typeParameters, true)
}
renderReceiver(simpleFunction)
renderName(simpleFunction)
renderValueParameters(simpleFunction.valueParameters)
val returnType = simpleFunction.returnTypeRef
if (options.renderUnitReturnType || (!returnType.isUnit)) {
append(": ")
append(renderType(returnType, approximate = options.approximateTypes))
}
renderWhereSuffix(simpleFunction.typeParameters)
}
if (options.renderContainingDeclarations) {
simpleFunction.body?.let {
underBlockDeclaration(simpleFunction, it, data)
}
}
}
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: StringBuilder) {
with(data) {
appendLine()
appendTabs()
if (options.renderDeclarationHeader) {
renderAnnotations(anonymousObject)
}
append(getClassifierKindPrefix(anonymousObject))
renderSuperTypes(anonymousObject)
}
if (options.renderContainingDeclarations) {
data.underBlockDeclaration(anonymousObject) {
anonymousObject.declarations.forEach {
it.accept(this, data)
}
}
}
}
override fun visitConstructor(constructor: FirConstructor, data: StringBuilder) {
with(data) {
appendLine()
appendTabs()
val containingClass = containingDeclaration
check(containingClass is FirDeclaration && (containingClass is FirClass || containingClass is FirEnumEntry)) {
"Invalid renderer containing declaration for constructor"
}
if (options.renderDeclarationHeader) {
renderAnnotations(constructor)
}
append("constructor")
renderValueParameters(constructor.valueParameters)
}
if (options.renderContainingDeclarations) {
constructor.body?.let {
underBlockDeclaration(constructor, it, data)
}
}
}
override fun visitTypeParameter(typeParameter: FirTypeParameter, data: StringBuilder) {
data.renderTypeParameter(typeParameter, true)
}
override fun visitRegularClass(regularClass: FirRegularClass, data: StringBuilder) {
with(data) {
appendLine()
appendTabs()
if (options.renderDeclarationHeader) {
renderAnnotations(regularClass)
if (regularClass.classKind != ClassKind.ENUM_ENTRY) {
renderVisibility(regularClass.visibility)
}
val haveNotModality = regularClass.classKind == ClassKind.INTERFACE && regularClass.modality == Modality.ABSTRACT ||
regularClass.classKind.isSingleton && regularClass.modality == Modality.FINAL
if (!haveNotModality) {
regularClass.modality?.let {
renderModality(it, regularClass.implicitModalityWithoutExtensions(containingDeclaration))
}
}
renderMemberModifiers(regularClass)
renderModifier(RendererModifier.INNER in options.modifiers && regularClass.isInner, "inner")
renderModifier(RendererModifier.DATA in options.modifiers && regularClass.isData, "data")
renderModifier(RendererModifier.INLINE in options.modifiers && regularClass.isInline, "inline")
//TODO renderModifier(data, RendererModifier.VALUE in modifiers && regularClass.isValue, "value")
renderModifier(RendererModifier.FUN in options.modifiers && regularClass.isFun, "fun")
append(getClassifierKindPrefix(regularClass))
}
if (!regularClass.isCompanion) {
tabRightBySpace()
renderName(regularClass)
} else {
renderCompanionObjectName(regularClass)
}
if (regularClass.classKind == ClassKind.ENUM_ENTRY) return
val typeParameters = regularClass.typeParameters.filterIsInstance<FirTypeParameter>()
renderTypeParameterRefs(typeParameters, false)
renderSuperTypes(regularClass)
renderWhereSuffix(typeParameters)
}
fun FirDeclaration.isDefaultPrimaryConstructor() =
this is FirConstructor &&
isPrimary &&
valueParameters.isEmpty() &&
!hasBody &&
(visibility == Visibilities.DEFAULT_VISIBILITY || regularClass.classKind == ClassKind.OBJECT)
fun FirDeclaration.skipDeclarationForEnumClass(): Boolean {
if (this is FirConstructor) return isPrimary && valueParameters.isEmpty()
if (this !is FirSimpleFunction) return false
if (name.asString() == "values" && valueParameters.isEmpty()) return true
if (name.asString() == "valueOf") {
return valueParameters.count() == 1 && (valueParameters[0].returnTypeRef.coneType).classId == StandardClassIds.String
}
return false
}
fun renderDeclarationForEnumClass() {
check(regularClass.isEnumClass)
val partitioned = regularClass.declarations.partition { it is FirEnumEntry }
partitioned.first.forEach { enumEntry ->
check(enumEntry is FirEnumEntry)
visitEnumEntry(enumEntry, data)
data.append(",")
}
partitioned.second.forEach {
if (!it.skipDeclarationForEnumClass()) {
it.accept(this, data)
}
}
}
fun renderDeclarationForNotEnumClass() {
check(!regularClass.isEnumClass)
regularClass.declarations.forEach {
if (!it.isDefaultPrimaryConstructor()) {
it.accept(this, data)
}
}
}
if (options.renderContainingDeclarations) {
data.underBlockDeclaration(regularClass) {
if (regularClass.isEnumClass) {
renderDeclarationForEnumClass()
} else {
renderDeclarationForNotEnumClass()
}
}
}
}
private var tabbedString = ""
private inline fun underTabbedBlock(body: () -> Unit) {
val oldTabbedString = tabbedString
tabbedString = " ".repeat(tabbedString.length + 4)
body()
tabbedString = oldTabbedString
}
private inline fun underContainingDeclaration(firDeclaration: FirDeclaration, body: () -> Unit) {
val oldContainingDeclaration = containingDeclaration
containingDeclaration = firDeclaration
body()
containingDeclaration = oldContainingDeclaration
}
private inline fun StringBuilder.underBlockDeclaration(firDeclaration: FirDeclaration, withBrackets: Boolean = true, body: () -> Unit) {
val oldLength = length
if (withBrackets) append(" {")
val unchangedLength = length
underContainingDeclaration(firDeclaration) {
underTabbedBlock(body)
}
if (unchangedLength != length) {
if (withBrackets) {
appendLine()
appendTabs()
append("}")
}
} else {
delete(oldLength, unchangedLength)
}
}
private fun StringBuilder.appendTabs() = append(tabbedString)
private fun underBlockDeclaration(firDeclaration: FirDeclaration, firBlock: FirBlock, data: StringBuilder) {
data.underBlockDeclaration(firDeclaration) {
firBlock.accept(this, data)
}
}
override fun visitTypeAlias(typeAlias: FirTypeAlias, data: StringBuilder) = with(data) {
if (options.renderDeclarationHeader) {
renderAnnotations(typeAlias)
renderVisibility(typeAlias.visibility)
renderMemberModifiers(typeAlias)
append("typealias").append(" ")
}
renderName(typeAlias)
renderTypeParameters(typeAlias.typeParameters, false)
append(" = ").append(renderType(typeAlias.expandedTypeRef))
Unit
}
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: StringBuilder) {
with(data) {
appendLine()
appendTabs()
renderName(enumEntry)
}
}
override fun visitElement(element: FirElement, data: StringBuilder) {
element.acceptChildren(this, data)
}
companion object {
fun render(
firDeclaration: FirDeclaration,
containingDeclaration: FirDeclaration?,
options: KtDeclarationRendererOptions,
session: FirSession
): String {
val renderer = FirIdeRenderer(
containingDeclaration,
options,
session,
)
return buildString {
firDeclaration.accept(renderer, this)
}.trim(' ', '\n', '\t')
}
}
/* TYPE PARAMETERS */
private fun StringBuilder.renderTypeParameter(typeParameter: FirTypeParameter, topLevel: Boolean) {
if (topLevel) {
append("<")
}
renderModifier(typeParameter.isReified, "reified")
val variance = typeParameter.variance.label
renderModifier(variance.isNotEmpty(), variance)
renderAnnotations(typeParameter)
renderName(typeParameter)
val upperBoundsCount = typeParameter.bounds.size
if ((upperBoundsCount > 1 && !topLevel) || upperBoundsCount == 1) {
val upperBound = typeParameter.bounds.first()
if (!upperBound.isNullableAny) {
append(" : ").append(renderType(upperBound))
}
} else if (topLevel) {
typeParameter.bounds.filterNot { it.isNullableAny }.forEachIndexed { index, upperBound ->
val separator = if (index == 0) " : " else " & "
append(separator)
append(renderType(upperBound))
}
} else {
// rendered with "where"
}
if (topLevel) {
append(">")
}
}
private fun StringBuilder.renderTypeParameterRefs(typeParameters: List<FirTypeParameterRef>, withSpace: Boolean) =
renderTypeParameters(typeParameters.map { it.symbol.fir }, withSpace)
private fun StringBuilder.renderTypeParameters(typeParameters: List<FirTypeParameter>, withSpace: Boolean) {
if (typeParameters.isNotEmpty()) {
append("<")
renderTypeParameterList(typeParameters)
append(">")
if (withSpace) {
append(" ")
}
}
}
private fun StringBuilder.renderTypeParameterList(typeParameters: List<FirTypeParameter>) {
val iterator = typeParameters.iterator()
while (iterator.hasNext()) {
val firTypeParameter = iterator.next()
renderTypeParameter(firTypeParameter, false)
if (iterator.hasNext()) {
append(", ")
}
}
}
private fun StringBuilder.renderReceiver(firCallableDeclaration: FirCallableDeclaration) {
val receiverType = firCallableDeclaration.receiverTypeRef
if (receiverType != null) {
if (options.renderDeclarationHeader) {
renderAnnotations(firCallableDeclaration)
}
val needBrackets =
typeIdeRenderer.shouldRenderAsPrettyFunctionType(receiverType.coneType) && receiverType.isMarkedNullable == true
val result = renderType(receiverType).applyIf(needBrackets) { "($this)" }
append(result)
append(".")
}
}
private fun StringBuilder.renderWhereSuffix(typeParameters: List<FirTypeParameterRef>) {
val upperBoundStrings = ArrayList<String>(0)
for (typeParameter in typeParameters) {
val typeParameterFir = typeParameter.symbol.fir
typeParameterFir.bounds
.drop(1) // first parameter is rendered by renderTypeParameter
.mapTo(upperBoundStrings) { typeParameterFir.name.render() + " : " + renderType(it) }
}
if (upperBoundStrings.isNotEmpty()) {
append(" where ")
upperBoundStrings.joinTo(this, ", ")
}
}
/* VARIABLES */
private fun StringBuilder.renderValueParameters(valueParameters: List<FirValueParameter>) {
append("(")
valueParameters.forEachIndexed { index, valueParameter ->
if (index != 0) append(", ")
renderValueParameter(valueParameter)
}
append(")")
}
private fun StringBuilder.renderValueParameter(valueParameter: FirValueParameter) {
if (options.renderDeclarationHeader) {
renderAnnotations(valueParameter)
}
renderModifier(valueParameter.isCrossinline, "crossinline")
renderModifier(valueParameter.isNoinline, "noinline")
renderVariable(valueParameter)
if (options.renderDefaultParameterValue) {
val withDefaultValue = valueParameter.defaultValue != null //TODO check if default value is inherited
if (withDefaultValue) {
append(" = ...")
}
}
}
private fun StringBuilder.renderValVarPrefix(variable: FirVariable, isInPrimaryConstructor: Boolean = false) {
if (!isInPrimaryConstructor || variable !is FirValueParameter) {
append(if (variable.isVar) "var" else "val").append(" ")
}
}
private fun StringBuilder.renderVariable(variable: FirVariable) {
val typeToRender = variable.returnTypeRef
val isVarArg = (variable as? FirValueParameter)?.isVararg ?: false
renderModifier(isVarArg, "vararg")
renderName(variable)
append(": ")
val parameterType = typeToRender.coneType
if (isVarArg) {
append(renderType(parameterType.arrayElementType() ?: parameterType, typeToRender.annotations))
} else {
append(renderType(typeToRender))
}
}
private fun StringBuilder.renderSuperTypes(klass: FirClass) {
if (klass.defaultType().isNothing) return
val supertypes = klass.superTypeRefs.applyIf(klass.classKind == ClassKind.ENUM_CLASS) {
filterNot {
(it as? FirResolvedTypeRef)?.coneType?.classId == StandardClassIds.Enum
}
}.applyIf(klass.classKind == ClassKind.ANNOTATION_CLASS) {
filterNot {
(it as? FirResolvedTypeRef)?.coneType?.classId == StandardClassIds.Annotation
}
}
if (supertypes.isEmpty() || klass.superTypeRefs.singleOrNull()?.let { it.isAny || it.isNullableAny } == true) return
tabRightBySpace()
append(": ")
supertypes.joinTo(this, ", ") { renderType(it) }
}
private fun getClassifierKindPrefix(classifier: FirDeclaration): String = when (classifier) {
is FirTypeAlias -> "typealias"
is FirRegularClass ->
if (classifier.isCompanion) {
"companion object"
} else {
when (classifier.classKind) {
ClassKind.CLASS -> "class"
ClassKind.INTERFACE -> "interface"
ClassKind.ENUM_CLASS -> "enum class"
ClassKind.OBJECT -> "object"
ClassKind.ANNOTATION_CLASS -> "annotation class"
ClassKind.ENUM_ENTRY -> "enum entry"
}
}
is FirAnonymousObject -> "object"
is FirEnumEntry -> "enum entry"
else ->
throw AssertionError("Unexpected classifier: $classifier")
}
private fun StringBuilder.tabRightBySpace() {
if (length == 0 || last() != ' ') append(' ')
}
}
@@ -0,0 +1,72 @@
/*
* 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.analysis.api.fir.scopes
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.scopes.KtCompositeScope
import org.jetbrains.kotlin.analysis.api.scopes.KtScope
import org.jetbrains.kotlin.analysis.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassifierSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.name.Name
// todo do we need caches here?
@OptIn(ExperimentalStdlibApi::class)
class KtFirCompositeScope(
override val subScopes: List<KtScope>,
override val token: ValidityToken
) : KtCompositeScope, ValidityTokenOwner {
override fun getAllPossibleNames(): Set<Name> = withValidityAssertion {
buildSet {
subScopes.flatMapTo(this) { it.getAllPossibleNames() }
}
}
override fun getPossibleCallableNames(): Set<Name> = withValidityAssertion {
buildSet {
subScopes.flatMapTo(this) { it.getPossibleCallableNames() }
}
}
override fun getPossibleClassifierNames(): Set<Name> = withValidityAssertion {
buildSet {
subScopes.flatMapTo(this) { it.getPossibleClassifierNames() }
}
}
override fun getAllSymbols(): Sequence<KtSymbol> = withValidityAssertion {
sequence {
subScopes.forEach { yieldAll(it.getAllSymbols()) }
}
}
override fun getCallableSymbols(nameFilter: KtScopeNameFilter): Sequence<KtCallableSymbol> = withValidityAssertion {
sequence {
subScopes.forEach { yieldAll(it.getCallableSymbols(nameFilter)) }
}
}
override fun getClassifierSymbols(nameFilter: KtScopeNameFilter): Sequence<KtClassifierSymbol> = withValidityAssertion {
sequence {
subScopes.forEach { yieldAll(it.getClassifierSymbols(nameFilter)) }
}
}
override fun getConstructors(): Sequence<KtConstructorSymbol> = withValidityAssertion {
sequence {
subScopes.forEach { yieldAll(it.getConstructors()) }
}
}
override fun mayContainName(name: Name): Boolean = withValidityAssertion {
subScopes.any { it.mayContainName(name) }
}
}
@@ -0,0 +1,26 @@
/*
* 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.analysis.api.fir.scopes
import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.scopes.KtDeclaredMemberScope
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
internal class KtFirDeclaredMemberScope(
override val owner: KtSymbolWithMembers,
firScope: FirClassDeclaredMemberScope,
token: ValidityToken,
builder: KtSymbolByFirBuilder
) : KtFirDelegatingScope<FirClassDeclaredMemberScope>(builder, token),
KtDeclaredMemberScope,
ValidityTokenOwner {
override val firScope: FirClassDeclaredMemberScope by weakRef(firScope)
}
@@ -0,0 +1,107 @@
/*
* 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.analysis.api.fir.scopes
import org.jetbrains.kotlin.fir.isSubstitutionOverride
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.processClassifiersByName
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.scopes.KtScope
import org.jetbrains.kotlin.analysis.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassifierSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.name.Name
internal abstract class KtFirDelegatingScope<S>(
private val builder: KtSymbolByFirBuilder,
final override val token: ValidityToken
) : KtScope where S : FirContainingNamesAwareScope, S : FirScope {
abstract val firScope: S
private val allNamesCached by cached {
getPossibleCallableNames() + getPossibleClassifierNames()
}
override fun getAllPossibleNames(): Set<Name> = allNamesCached
override fun getPossibleCallableNames(): Set<Name> = withValidityAssertion {
firScope.getCallableNames()
}
override fun getPossibleClassifierNames(): Set<Name> = withValidityAssertion {
firScope.getClassifierNames()
}
override fun getCallableSymbols(nameFilter: KtScopeNameFilter): Sequence<KtCallableSymbol> = withValidityAssertion {
firScope.getCallableSymbols(getPossibleCallableNames().filter(nameFilter), builder)
}
override fun getClassifierSymbols(nameFilter: KtScopeNameFilter): Sequence<KtClassifierSymbol> = withValidityAssertion {
firScope.getClassifierSymbols(getPossibleClassifierNames().filter(nameFilter), builder)
}
override fun getConstructors(): Sequence<KtConstructorSymbol> = withValidityAssertion {
firScope.getConstructors(builder)
}
override fun mayContainName(name: Name): Boolean = withValidityAssertion {
name in getAllPossibleNames()
}
}
internal fun FirScope.getCallableSymbols(callableNames: Collection<Name>, builder: KtSymbolByFirBuilder) = sequence {
callableNames.forEach { name ->
val callables = mutableListOf<KtCallableSymbol>()
processFunctionsByName(name) { firSymbol ->
callables.add(builder.functionLikeBuilder.buildFunctionSymbol(firSymbol.fir))
}
processPropertiesByName(name) { firSymbol ->
val symbol = when {
firSymbol is FirPropertySymbol && firSymbol.fir.isSubstitutionOverride -> {
builder.variableLikeBuilder.buildVariableSymbol(firSymbol.fir)
}
else -> builder.callableBuilder.buildCallableSymbol(firSymbol.fir)
}
callables.add(symbol)
}
yieldAll(callables)
}
}
internal class KtFirDelegatingScopeImpl<S>(
override val firScope: S,
builder: KtSymbolByFirBuilder,
token: ValidityToken
) : KtFirDelegatingScope<S>(builder, token) where S : FirContainingNamesAwareScope, S : FirScope
internal fun FirScope.getClassifierSymbols(classLikeNames: Collection<Name>, builder: KtSymbolByFirBuilder): Sequence<KtClassifierSymbol> =
sequence {
classLikeNames.forEach { name ->
val classifierSymbols = mutableListOf<KtClassifierSymbol>()
processClassifiersByName(name) { firSymbol ->
classifierSymbols.add(builder.classifierBuilder.buildClassifierSymbol(firSymbol))
}
yieldAll(classifierSymbols)
}
}
internal fun FirScope.getConstructors(builder: KtSymbolByFirBuilder): Sequence<KtConstructorSymbol> =
sequence {
val constructorSymbols = mutableListOf<KtConstructorSymbol>()
processDeclaredConstructors { firSymbol ->
constructorSymbols.add(builder.functionLikeBuilder.buildConstructorSymbol(firSymbol.fir))
}
yieldAll(constructorSymbols)
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.scopes
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.scopes.KtDeclaredMemberScope
import org.jetbrains.kotlin.analysis.api.scopes.KtMemberScope
import org.jetbrains.kotlin.analysis.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassifierSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
import org.jetbrains.kotlin.name.Name
internal class KtFirEmptyMemberScope(override val owner: KtSymbolWithMembers) : KtMemberScope, KtDeclaredMemberScope, ValidityTokenOwner {
override fun getPossibleCallableNames(): Set<Name> = emptySet()
override fun getPossibleClassifierNames(): Set<Name> = emptySet()
override fun getCallableSymbols(nameFilter: KtScopeNameFilter): Sequence<KtCallableSymbol> =
emptySequence()
override fun getClassifierSymbols(nameFilter: KtScopeNameFilter): Sequence<KtClassifierSymbol> =
emptySequence()
override fun getConstructors(): Sequence<KtConstructorSymbol> =
emptySequence()
override fun mayContainName(name: Name): Boolean = false
override val token: ValidityToken
get() = owner.token
}
@@ -0,0 +1,98 @@
/*
* 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.analysis.api.fir.scopes
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirFileSymbol
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.scopes.KtDeclarationScope
import org.jetbrains.kotlin.analysis.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassifierSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithDeclarations
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.name.Name
internal class KtFirFileScope(
override val owner: KtFirFileSymbol,
override val token: ValidityToken,
private val builder: KtSymbolByFirBuilder
) : KtDeclarationScope<KtSymbolWithDeclarations>,
ValidityTokenOwner {
private val allNamesCached by cached {
_callableNames + _classifierNames
}
override fun getAllPossibleNames(): Set<Name> = allNamesCached
private val _callableNames: Set<Name> by cached {
val result = mutableSetOf<Name>()
owner.firRef.withFir {
it.declarations.mapNotNullTo(result) { firDeclaration ->
when (firDeclaration) {
is FirSimpleFunction -> firDeclaration.name
is FirProperty -> firDeclaration.name
else -> null
}
}
}
result
}
override fun getPossibleCallableNames(): Set<Name> = _callableNames
private val _classifierNames: Set<Name> by cached {
val result = mutableSetOf<Name>()
owner.firRef.withFir {
it.declarations.mapNotNullTo(result) { firDeclaration ->
(firDeclaration as? FirRegularClass)?.name
}
}
result
}
override fun getPossibleClassifierNames(): Set<Name> = _classifierNames
override fun getCallableSymbols(nameFilter: KtScopeNameFilter): Sequence<KtCallableSymbol> = withValidityAssertion {
owner.firRef.withFir {
sequence {
it.declarations.forEach { firDeclaration ->
val callableDeclaration = when (firDeclaration) {
is FirSimpleFunction -> firDeclaration.takeIf { nameFilter(firDeclaration.name) }
is FirProperty -> firDeclaration.takeIf { nameFilter(firDeclaration.name) }
else -> null
}
if (callableDeclaration != null) {
yield(builder.callableBuilder.buildCallableSymbol(callableDeclaration))
}
}
}
}
}
override fun getClassifierSymbols(nameFilter: KtScopeNameFilter): Sequence<KtClassifierSymbol> = withValidityAssertion {
owner.firRef.withFir {
sequence {
it.declarations.forEach { firDeclaration ->
val classLikeDeclaration = (firDeclaration as? FirRegularClass)?.takeIf { klass -> nameFilter(klass.name) }
if (classLikeDeclaration != null) {
yield(builder.classifierBuilder.buildClassLikeSymbol(classLikeDeclaration))
}
}
}
}
}
override fun getConstructors(): Sequence<KtConstructorSymbol> = emptySequence()
}
@@ -0,0 +1,24 @@
/*
* 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.analysis.api.fir.scopes
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.scopes.KtMemberScope
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
internal class KtFirMemberScope(
override val owner: KtSymbolWithMembers,
firScope: FirTypeScope,
token: ValidityToken,
builder: KtSymbolByFirBuilder
) : KtFirDelegatingScope<FirTypeScope>(builder, token), KtMemberScope, ValidityTokenOwner {
override val firScope: FirTypeScope by weakRef(firScope)
}
@@ -0,0 +1,66 @@
/*
* 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.analysis.api.fir.scopes
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractSimpleImportingScope
import org.jetbrains.kotlin.fir.scopes.impl.FirDefaultSimpleImportingScope
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.scopes.KtNonStarImportingScope
import org.jetbrains.kotlin.analysis.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.analysis.api.scopes.NonStarImport
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassifierSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.name.Name
internal class KtFirNonStarImportingScope(
firScope: FirAbstractSimpleImportingScope,
private val builder: KtSymbolByFirBuilder,
override val token: ValidityToken
) : KtNonStarImportingScope, ValidityTokenOwner {
private val firScope: FirAbstractSimpleImportingScope by weakRef(firScope)
@OptIn(ExperimentalStdlibApi::class)
override val imports: List<NonStarImport> by cached {
buildList {
firScope.simpleImports.values.forEach { imports ->
imports.forEach { import ->
NonStarImport(
import.packageFqName,
import.relativeClassName,
import.resolvedClassId,
import.importedName
).let(::add)
}
}
}
}
override fun getCallableSymbols(nameFilter: KtScopeNameFilter): Sequence<KtCallableSymbol> = withValidityAssertion {
firScope.getCallableSymbols(getPossibleCallableNames().filter(nameFilter), builder)
}
override fun getClassifierSymbols(nameFilter: KtScopeNameFilter): Sequence<KtClassifierSymbol> = withValidityAssertion {
firScope.getClassifierSymbols(getPossibleClassifierNames().filter(nameFilter), builder)
}
override fun getConstructors(): Sequence<KtConstructorSymbol> = emptySequence()
override fun getPossibleCallableNames(): Set<Name> = withValidityAssertion {
imports.mapNotNullTo(hashSetOf()) { it.callableName }
}
override fun getPossibleClassifierNames(): Set<Name> = withValidityAssertion {
imports.mapNotNullTo((hashSetOf())) { it.relativeClassName?.shortName() }
}
override val isDefaultImportingScope: Boolean = withValidityAssertion { firScope is FirDefaultSimpleImportingScope }
}
@@ -0,0 +1,96 @@
/*
* 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.analysis.api.fir.scopes
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.createPackageProvider
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.components.KtFirScopeProvider
import org.jetbrains.kotlin.analysis.api.fir.utils.lazyThreadUnsafeWeakRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.scopes.KtPackageScope
import org.jetbrains.kotlin.analysis.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassifierSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtPackageSymbol
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.jvm.isJvm
internal class KtFirPackageScope(
override val fqName: FqName,
private val project: Project,
private val builder: KtSymbolByFirBuilder,
_scopeProvider: KtFirScopeProvider,
override val token: ValidityToken,
private val searchScope: GlobalSearchScope,
private val targetPlatform: TargetPlatform,
) : KtPackageScope {
private val scopeProvider by weakRef(_scopeProvider)
private val declarationsProvider = project.createDeclarationProvider(searchScope)
private val packageProvider = project.createPackageProvider(searchScope)
private val firScope: FirPackageMemberScope by lazyThreadUnsafeWeakRef {
val scope = FirPackageMemberScope(fqName, builder.rootSession)
scopeProvider.registerScope(scope)
scope
}
override fun getPossibleCallableNames() = withValidityAssertion {
hashSetOf<Name>().apply {
addAll(declarationsProvider.getFunctionsNamesInPackage(fqName))
addAll(declarationsProvider.getPropertyNamesInPackage(fqName))
}
}
override fun getPossibleClassifierNames(): Set<Name> = withValidityAssertion {
hashSetOf<Name>().apply {
addAll(declarationsProvider.getClassNamesInPackage(fqName))
addAll(declarationsProvider.getTypeAliasNamesInPackage(fqName))
JavaPsiFacade.getInstance(project)
.findPackage(fqName.asString())
?.getClasses(searchScope)
?.mapNotNullTo(this) { it.name?.let(Name::identifier) }
}
}
override fun getCallableSymbols(nameFilter: KtScopeNameFilter): Sequence<KtCallableSymbol> = withValidityAssertion {
firScope.getCallableSymbols(getPossibleCallableNames().filter(nameFilter), builder)
}
override fun getClassifierSymbols(nameFilter: KtScopeNameFilter): Sequence<KtClassifierSymbol> = withValidityAssertion {
firScope.getClassifierSymbols(getPossibleClassifierNames().filter(nameFilter), builder)
}
override fun getPackageSymbols(nameFilter: KtScopeNameFilter): Sequence<KtPackageSymbol> = withValidityAssertion {
sequence {
if (targetPlatform.isJvm()) {
val javaPackage = JavaPsiFacade.getInstance(project).findPackage(fqName.asString())
if (javaPackage != null) {
for (psiPackage in javaPackage.getSubPackages(searchScope)) {
val fqName = FqName(psiPackage.qualifiedName)
if (nameFilter(fqName.shortName())) {
yield(builder.createPackageSymbol(fqName))
}
}
}
}
packageProvider.getKotlinSubPackageFqNames(fqName).forEach {
if (nameFilter(it)) {
yield(builder.createPackageSymbol(fqName.child(it)))
}
}
}
}
}
@@ -0,0 +1,88 @@
/*
* 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.analysis.api.fir.scopes
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider
import org.jetbrains.kotlin.fir.scopes.getContainingCallableNamesIfPresent
import org.jetbrains.kotlin.fir.scopes.getContainingClassifierNamesIfPresent
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractStarImportingScope
import org.jetbrains.kotlin.fir.scopes.impl.FirDefaultStarImportingScope
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.scopes.Import
import org.jetbrains.kotlin.analysis.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.analysis.api.scopes.KtStarImportingScope
import org.jetbrains.kotlin.analysis.api.scopes.StarImport
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassifierSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.name.Name
internal class KtFirStarImportingScope(
firScope: FirAbstractStarImportingScope,
private val builder: KtSymbolByFirBuilder,
project: Project,
override val token: ValidityToken,
) : KtStarImportingScope, ValidityTokenOwner {
private val firScope: FirAbstractStarImportingScope by weakRef(firScope)
override val isDefaultImportingScope: Boolean = withValidityAssertion { firScope is FirDefaultStarImportingScope }
//todo use more concrete scope
private val declarationProvider = project.createDeclarationProvider(GlobalSearchScope.allScope(project))
override val imports: List<StarImport> by cached {
firScope.starImports.map { import ->
StarImport(
import.packageFqName,
import.relativeClassName,
import.resolvedClassId
)
}
}
override fun getCallableSymbols(nameFilter: KtScopeNameFilter): Sequence<KtCallableSymbol> = withValidityAssertion {
firScope.getCallableSymbols(getPossibleCallableNames().filter(nameFilter), builder)
}
override fun getClassifierSymbols(nameFilter: KtScopeNameFilter): Sequence<KtClassifierSymbol> = withValidityAssertion {
firScope.getClassifierSymbols(getPossibleClassifierNames().filter(nameFilter), builder)
}
override fun getConstructors(): Sequence<KtConstructorSymbol> = emptySequence()
// todo cache?
@OptIn(ExperimentalStdlibApi::class)
override fun getPossibleCallableNames(): Set<Name> = withValidityAssertion {
imports.flatMapTo(hashSetOf()) { import: Import ->
if (import.relativeClassName == null) { // top level callable
declarationProvider.getFunctionsNamesInPackage(import.packageFqName) +
declarationProvider.getPropertyNamesInPackage(import.packageFqName)
} else { //member
val classId = import.resolvedClassId ?: error("Class id should not be null as relativeClassName is not null")
firScope.getStaticsScope(classId)?.getContainingCallableNamesIfPresent().orEmpty()
}
}
}
override fun getPossibleClassifierNames(): Set<Name> = withValidityAssertion {
imports.flatMapTo(hashSetOf()) { import ->
if (import.relativeClassName == null) {
declarationProvider.getClassNamesInPackage(import.packageFqName) +
declarationProvider.getTypeAliasNamesInPackage(import.packageFqName)
} else {
val classId = import.resolvedClassId ?: error("Class id should not be null as relativeClassName is not null")
firScope.getStaticsScope(classId)?.getContainingClassifierNamesIfPresent().orEmpty()
}
}
}
}
@@ -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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.getHasStableParameterNames
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtAnonymousFunctionSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
internal class KtFirAnonymousFunctionSymbol(
fir: FirAnonymousFunction,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtAnonymousFunctionSymbol(), KtFirSymbol<FirAnonymousFunction> {
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val annotatedType: KtTypeAndAnnotations by cached {
firRef.returnTypeAndAnnotations(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE, builder)
}
override val valueParameters: List<KtValueParameterSymbol> by firRef.withFirAndCache { fir ->
fir.valueParameters.map { valueParameter ->
builder.variableLikeBuilder.buildValueParameterSymbol(valueParameter)
}
}
override val hasStableParameterNames: Boolean = firRef.withFir { it.getHasStableParameterNames(it.moduleData.session) }
override val isExtension: Boolean get() = firRef.withFir { it.receiverTypeRef != null }
override val receiverType: KtTypeAndAnnotations? by cached {
firRef.receiverTypeAndAnnotations(builder)
}
override fun createPointer(): KtSymbolPointer<KtAnonymousFunctionSymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
error("Could not create a pointer for anonymous function from library")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,52 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtAnonymousObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.CanNotCreateSymbolPointerForLocalLibraryDeclarationException
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.name.ClassId
internal class KtFirAnonymousObjectSymbol(
fir: FirAnonymousObject,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtAnonymousObjectSymbol(), KtFirSymbol<FirAnonymousObject> {
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
override val superTypes: List<KtTypeAndAnnotations> by cached {
firRef.superTypesAndAnnotationsList(builder)
}
override fun createPointer(): KtSymbolPointer<KtAnonymousObjectSymbol> =
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)
?: throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException("Cannot create pointer for KtFirAnonymousObjectSymbol")
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,56 @@
/*
* 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.analysis.api.fir.symbols
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirBackingFieldSymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtBackingFieldSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtKotlinPropertySymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
internal class KtFirBackingFieldSymbol(
propertyFir: FirProperty,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtBackingFieldSymbol(){
private val builder by weakRef(_builder)
private val propertyFirRef = firRef(propertyFir, resolveState)
override val annotatedType: KtTypeAndAnnotations by cached {
propertyFirRef.returnTypeAndAnnotations(FirResolvePhase.TYPES, builder)
}
override val owningProperty: KtKotlinPropertySymbol by propertyFirRef.withFirAndCache { fir ->
builder.variableLikeBuilder.buildPropertySymbol(fir)
}
override fun createPointer(): KtSymbolPointer<KtBackingFieldSymbol> {
return KtFirBackingFieldSymbolPointer(owningProperty.createPointer())
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as KtFirBackingFieldSymbol
if (this.token != other.token) return false
return this.propertyFirRef == other.propertyFirRef
}
override fun hashCode(): Int {
return propertyFirRef.hashCode() * 31 + token.hashCode()
}
}
@@ -0,0 +1,93 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.getHasStableParameterNames
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirConstructorSymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.createSignature
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.CanNotCreateSymbolPointerForLocalLibraryDeclarationException
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.name.ClassId
internal class KtFirConstructorSymbol(
fir: FirConstructor,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtConstructorSymbol(), KtFirSymbol<FirConstructor> {
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val annotatedType: KtTypeAndAnnotations by cached {
firRef.returnTypeAndAnnotations(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE, builder)
}
override val valueParameters: List<KtValueParameterSymbol> by firRef.withFirAndCache { fir ->
fir.valueParameters.map { valueParameter ->
builder.variableLikeBuilder.buildValueParameterSymbol(valueParameter)
}
}
override val hasStableParameterNames: Boolean = firRef.withFir { it.getHasStableParameterNames(it.moduleData.session) }
override val visibility: Visibility get() = getVisibility()
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
override val containingClassIdIfNonLocal: ClassId?
get() = firRef.withFir { fir -> fir.containingClass()?.classId /* TODO check if local */ }
override val isPrimary: Boolean get() = firRef.withFir { it.isPrimary }
override val typeParameters by firRef.withFirAndCache { fir ->
fir.typeParameters.map { typeParameter ->
builder.classifierBuilder.buildTypeParameterSymbol(typeParameter.symbol.fir)
}
}
override val dispatchType: KtType? by cached {
firRef.dispatchReceiverTypeAndAnnotations(builder)
}
override fun createPointer(): KtSymbolPointer<KtConstructorSymbol> = withValidityAssertion {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
if (symbolKind == KtSymbolKind.LOCAL) {
throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException("constructor")
}
val ownerClassId = containingClassIdIfNonLocal
?: error("ClassId should present for member declaration")
return KtFirConstructorSymbolPointer(ownerClassId, isPrimary, firRef.withFir { it.createSignature() })
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,61 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirEnumEntrySymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal class KtFirEnumEntrySymbol(
fir: FirEnumEntry,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtEnumEntrySymbol(), KtFirSymbol<FirEnumEntry> {
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val name: Name get() = firRef.withFir { it.name }
override val annotatedType: KtTypeAndAnnotations by cached {
firRef.returnTypeAndAnnotations(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE, builder)
}
override val containingEnumClassIdIfNonLocal: ClassId?
get() = firRef.withFir { it.containingClass()?.classId?.takeUnless { it.isLocal } }
override val callableIdIfNonLocal: CallableId? get() = getCallableIdIfNonLocal()
override fun createPointer(): KtSymbolPointer<KtEnumEntrySymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
return firRef.withFir { fir ->
KtFirEnumEntrySymbolPointer(
fir.symbol.containingClass()?.classId ?: error("Containing class should present for enum entry"),
fir.name
)
}
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,44 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithDeclarations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.name.ClassId
internal class KtFirFileSymbol(
fir: FirFile,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
) : KtFileSymbol(), KtSymbolWithDeclarations, KtFirSymbol<FirFile> {
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override fun createPointer(): KtSymbolPointer<KtFileSymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
TODO("Creating pointers for files from library is not supported yet")
}
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,125 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.resolve.getHasStableParameterNames
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirMemberFunctionSymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirTopLevelFunctionSymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.createSignature
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.*
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal class KtFirFunctionSymbol(
fir: FirSimpleFunction,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtFunctionSymbol(), KtFirSymbol<FirSimpleFunction> {
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val name: Name get() = firRef.withFir { it.name }
override val annotatedType: KtTypeAndAnnotations by cached {
firRef.returnTypeAndAnnotations(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE, builder)
}
override val valueParameters: List<KtValueParameterSymbol> by firRef.withFirAndCache { fir ->
fir.valueParameters.map { valueParameter ->
builder.variableLikeBuilder.buildValueParameterSymbol(valueParameter)
}
}
override val typeParameters by firRef.withFirAndCache { fir ->
fir.typeParameters.map { typeParameter ->
builder.classifierBuilder.buildTypeParameterSymbol(typeParameter.symbol.fir)
}
}
override val hasStableParameterNames: Boolean = firRef.withFir { it.getHasStableParameterNames(it.moduleData.session) }
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
override val isSuspend: Boolean get() = firRef.withFir { it.isSuspend }
override val isOverride: Boolean get() = firRef.withFir { it.isOverride }
override val isInfix: Boolean get() = firRef.withFir { it.isInfix }
override val isStatic: Boolean get() = firRef.withFir { it.isStatic }
override val dispatchType: KtType? by cached {
firRef.dispatchReceiverTypeAndAnnotations(builder)
}
override val receiverType: KtTypeAndAnnotations? by cached {
firRef.receiverTypeAndAnnotations(builder)
}
override val isOperator: Boolean get() = firRef.withFir { it.isOperator }
override val isExternal: Boolean get() = firRef.withFir { it.isExternal }
override val isInline: Boolean get() = firRef.withFir { it.isInline }
override val isExtension: Boolean get() = firRef.withFir { it.receiverTypeRef != null }
override val callableIdIfNonLocal: CallableId? get() = getCallableIdIfNonLocal()
override val symbolKind: KtSymbolKind
get() = firRef.withFir { fir ->
when {
fir.isLocal -> KtSymbolKind.LOCAL
fir.containingClass()?.classId == null -> KtSymbolKind.TOP_LEVEL
else -> KtSymbolKind.MEMBER
}
}
override val modality: Modality get() = getModality()
override val visibility: Visibility get() = getVisibility()
override fun createPointer(): KtSymbolPointer<KtFunctionSymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
return when (symbolKind) {
KtSymbolKind.TOP_LEVEL -> firRef.withFir { fir ->
KtFirTopLevelFunctionSymbolPointer(fir.symbol.callableId, fir.createSignature())
}
KtSymbolKind.MEMBER -> firRef.withFir { fir ->
KtFirMemberFunctionSymbolPointer(
fir.containingClass()?.classId ?: error("ClassId should not be null for member function"),
fir.name,
fir.createSignature()
)
}
KtSymbolKind.ACCESSOR -> TODO("Creating symbol for accessors fun is not supported yet")
KtSymbolKind.LOCAL -> throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException(
callableIdIfNonLocal?.toString() ?: name.asString()
)
KtSymbolKind.SAM_CONSTRUCTOR -> throw WrongSymbolForSamConstructor(this::class.java.simpleName)
}
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,56 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.declarations.FirField
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtJavaFieldSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
internal class KtFirJavaFieldSymbol(
fir: FirField,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtJavaFieldSymbol(), KtFirSymbol<FirField> {
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val annotatedType: KtTypeAndAnnotations by cached {
firRef.returnTypeAndAnnotations(FirResolvePhase.TYPES, builder)
}
override val isVal: Boolean get() = firRef.withFir { it.isVal }
override val name: Name get() = firRef.withFir { it.name }
override val callableIdIfNonLocal: CallableId? get() = getCallableIdIfNonLocal()
override val modality: Modality get() = getModality()
override val visibility: Visibility get() = getVisibility()
override val isStatic: Boolean get() = firRef.withFir { it.isStatic }
override fun createPointer(): KtSymbolPointer<KtJavaFieldSymbol> {
TODO("Creating pointers for java fields is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,136 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirMemberPropertySymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.createSignature
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.convertConstantExpression
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtKotlinPropertySymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertyGetterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySetterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtConstantValue
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.*
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal class KtFirKotlinPropertySymbol(
fir: FirProperty,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtKotlinPropertySymbol(), KtFirSymbol<FirProperty> {
init {
assert(!fir.isLocal)
check(fir !is FirSyntheticProperty)
}
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val isVal: Boolean get() = firRef.withFir { it.isVal }
override val name: Name get() = firRef.withFir { it.name }
override val annotatedType: KtTypeAndAnnotations by cached {
firRef.returnTypeAndAnnotations(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE, builder)
}
override val dispatchType: KtType? by cached {
firRef.dispatchReceiverTypeAndAnnotations(builder)
}
override val receiverType: KtTypeAndAnnotations? by cached {
firRef.receiverTypeAndAnnotations(builder)
}
override val isExtension: Boolean get() = firRef.withFir { it.receiverTypeRef != null }
override val initializer: KtConstantValue? by firRef.withFirAndCache(FirResolvePhase.BODY_RESOLVE) { fir -> fir.initializer?.convertConstantExpression() }
override val symbolKind: KtSymbolKind
get() = firRef.withFir { fir ->
when (fir.containingClass()?.classId) {
null -> KtSymbolKind.TOP_LEVEL
else -> KtSymbolKind.MEMBER
}
}
override val modality: Modality get() = getModality()
override val visibility: Visibility get() = getVisibility()
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
override val callableIdIfNonLocal: CallableId? get() = getCallableIdIfNonLocal()
override val getter: KtPropertyGetterSymbol? by firRef.withFirAndCache(FirResolvePhase.RAW_FIR) { property ->
property.getter?.let { builder.callableBuilder.buildPropertyAccessorSymbol(it) } as? KtPropertyGetterSymbol
}
override val setter: KtPropertySetterSymbol? by firRef.withFirAndCache(FirResolvePhase.RAW_FIR) { property ->
property.setter?.let { builder.callableBuilder.buildPropertyAccessorSymbol(it) } as? KtPropertySetterSymbol
}
// NB: `field` in accessors indicates the property should have a backing field. To see that, though, we need BODY_RESOLVE.
override val hasBackingField: Boolean get() = firRef.withFir(FirResolvePhase.BODY_RESOLVE) { it.hasBackingField }
override val isLateInit: Boolean get() = firRef.withFir { it.isLateInit }
override val isConst: Boolean get() = firRef.withFir { it.isConst }
override val isFromPrimaryConstructor: Boolean
get() = firRef.withFir {
it.fromPrimaryConstructor == true || it.source?.kind == FirFakeSourceElementKind.PropertyFromParameter
}
override val isOverride: Boolean get() = firRef.withFir { it.isOverride }
override val isStatic: Boolean get() = firRef.withFir { it.isStatic }
override val hasGetter: Boolean get() = firRef.withFir { it.getter != null }
override val hasSetter: Boolean get() = firRef.withFir { it.setter != null }
override fun createPointer(): KtSymbolPointer<KtKotlinPropertySymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
return when (symbolKind) {
KtSymbolKind.TOP_LEVEL -> TODO("Creating symbol for top level properties is not supported yet")
KtSymbolKind.MEMBER -> firRef.withFir { fir ->
KtFirMemberPropertySymbolPointer(
fir.containingClass()?.classId ?: error("ClassId should not be null for member property"),
fir.name,
fir.createSignature()
)
}
KtSymbolKind.ACCESSOR -> TODO("Creating symbol for accessors is not supported yet")
KtSymbolKind.LOCAL -> throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException(name.asString())
KtSymbolKind.SAM_CONSTRUCTOR -> throw WrongSymbolForSamConstructor(this::class.java.simpleName)
}
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,55 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtLocalVariableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.CanNotCreateSymbolPointerForLocalLibraryDeclarationException
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.name.Name
internal class KtFirLocalVariableSymbol(
fir: FirProperty,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtLocalVariableSymbol(),
KtFirSymbol<FirProperty> {
init {
assert(fir.isLocal)
}
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val isVal: Boolean get() = firRef.withFir { it.isVal }
override val name: Name get() = firRef.withFir { it.name }
override val annotatedType: KtTypeAndAnnotations by cached {
firRef.returnTypeAndAnnotations(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE, builder)
}
override val symbolKind: KtSymbolKind get() = KtSymbolKind.LOCAL
override fun createPointer(): KtSymbolPointer<KtLocalVariableSymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException(name.asString())
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,126 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirClassOrObjectInLibrarySymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.CanNotCreateSymbolPointerForLocalLibraryDeclarationException
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal class KtFirNamedClassOrObjectSymbol(
fir: FirRegularClass,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtNamedClassOrObjectSymbol(), KtFirSymbol<FirRegularClass> {
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val name: Name get() = firRef.withFir { it.name }
override val classIdIfNonLocal: ClassId?
get() = firRef.withFir { fir ->
fir.symbol.classId.takeUnless { it.isLocal }
}
/* FirRegularClass modality does not modified by STATUS so it can be taken from RAW */
override val modality: Modality
get() = getModality(
FirResolvePhase.RAW_FIR,
when (classKind) { // default modality
KtClassKind.INTERFACE -> Modality.ABSTRACT
// Enum class should not be `final`, since its entries extend it.
// It could be either `abstract` w/o ctor, or empty modality w/ private ctor.
KtClassKind.ENUM_CLASS -> Modality.OPEN
else -> Modality.FINAL
}
)
/* FirRegularClass visibility are not modified by STATUS only for Unknown so it can be taken from RAW */
override val visibility: Visibility
get() = when (val possiblyRawVisibility = getVisibility(FirResolvePhase.RAW_FIR)) {
Visibilities.Unknown -> if (firRef.withFir { it.isLocal }) Visibilities.Local else Visibilities.Public
else -> possiblyRawVisibility
}
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
override val isInner: Boolean get() = firRef.withFir { it.isInner }
override val isData: Boolean get() = firRef.withFir { it.isData }
override val isInline: Boolean get() = firRef.withFir { it.isInline }
override val isFun: Boolean get() = firRef.withFir { it.isFun }
override val isExternal: Boolean get() = firRef.withFir { it.isExternal }
override val companionObject: KtFirNamedClassOrObjectSymbol? by firRef.withFirAndCache { fir ->
fir.companionObject?.let { builder.classifierBuilder.buildNamedClassOrObjectSymbol(it) }
}
override val superTypes: List<KtTypeAndAnnotations> by cached {
firRef.superTypesAndAnnotationsListForRegularClass(builder)
}
override val typeParameters by firRef.withFirAndCache { fir ->
fir.typeParameters.filterIsInstance<FirTypeParameter>().map { typeParameter ->
builder.classifierBuilder.buildTypeParameterSymbol(typeParameter.symbol.fir)
}
}
override val classKind: KtClassKind
get() = firRef.withFir { fir ->
when (fir.classKind) {
ClassKind.INTERFACE -> KtClassKind.INTERFACE
ClassKind.ENUM_CLASS -> KtClassKind.ENUM_CLASS
ClassKind.ENUM_ENTRY -> KtClassKind.ENUM_ENTRY
ClassKind.ANNOTATION_CLASS -> KtClassKind.ANNOTATION_CLASS
ClassKind.CLASS -> KtClassKind.CLASS
ClassKind.OBJECT -> if (fir.isCompanion) KtClassKind.COMPANION_OBJECT else KtClassKind.OBJECT
}
}
override val symbolKind: KtSymbolKind
get() = firRef.withFir { fir ->
when {
fir.isLocal -> KtSymbolKind.LOCAL
fir.symbol.classId.isNestedClass -> KtSymbolKind.MEMBER
else -> KtSymbolKind.TOP_LEVEL
}
}
override fun createPointer(): KtSymbolPointer<KtNamedClassOrObjectSymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
if (symbolKind == KtSymbolKind.LOCAL) {
throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException(classIdIfNonLocal?.asString().orEmpty())
}
return KtFirClassOrObjectInLibrarySymbolPointer(classIdIfNonLocal!!)
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,103 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.symbols
import org.jetbrains.kotlin.fir.analysis.checkers.getImplementationStatus
import org.jetbrains.kotlin.fir.analysis.checkers.isVisibleInClass
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.originalForIntersectionOverrideAttr
import org.jetbrains.kotlin.fir.originalForSubstitutionOverride
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.SessionHolderImpl
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.components.KtOverrideInfoProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.buildSymbol
import org.jetbrains.kotlin.analysis.api.fir.components.KtFirAnalysisSessionComponent
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.util.ImplementationStatus
internal class KtFirOverrideInfoProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken,
) : KtOverrideInfoProvider(), KtFirAnalysisSessionComponent {
override fun isVisible(memberSymbol: KtCallableSymbol, classSymbol: KtClassOrObjectSymbol): Boolean {
require(memberSymbol is KtFirSymbol<*>)
require(classSymbol is KtFirSymbol<*>)
// Inspecting visibility requires resolving to status
return memberSymbol.firRef.withFir(FirResolvePhase.STATUS) outer@{ memberFir ->
if (memberFir !is FirCallableDeclaration) return@outer false
classSymbol.firRef.withFir inner@{ parentClassFir ->
if (parentClassFir !is FirClass) return@inner false
memberFir.isVisibleInClass(parentClassFir)
}
}
}
override fun getImplementationStatus(memberSymbol: KtCallableSymbol, parentClassSymbol: KtClassOrObjectSymbol): ImplementationStatus? {
require(memberSymbol is KtFirSymbol<*>)
require(parentClassSymbol is KtFirSymbol<*>)
// Inspecting implementation status requires resolving to status
return memberSymbol.firRef.withFir(FirResolvePhase.STATUS) outer@{ memberFir ->
if (memberFir !is FirCallableDeclaration) return@outer null
parentClassSymbol.firRef.withFir inner@{ parentClassFir ->
if (parentClassFir !is FirClass) return@inner null
memberFir.symbol.getImplementationStatus(
SessionHolderImpl(rootModuleSession, ScopeSession()),
parentClassFir.symbol
)
}
}
}
override fun getOriginalContainingClassForOverride(symbol: KtCallableSymbol): KtClassOrObjectSymbol? {
require(symbol is KtFirSymbol<*>)
return symbol.firRef.withFir(FirResolvePhase.STATUS) { firDeclaration ->
if (firDeclaration !is FirCallableDeclaration) return@withFir null
val containingClass =
getOriginalOverriddenSymbol(firDeclaration)?.containingClass()?.toSymbol(rootModuleSession) ?: return@withFir null
analysisSession.firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(containingClass.fir) as? KtClassOrObjectSymbol
}
}
override fun getOriginalOverriddenSymbol(symbol: KtCallableSymbol): KtCallableSymbol? {
require(symbol is KtFirSymbol<*>)
return symbol.firRef.withFir(FirResolvePhase.STATUS) { firDeclaration ->
if (firDeclaration !is FirCallableDeclaration) return@withFir null
with(analysisSession) {
getOriginalOverriddenSymbol(firDeclaration)
?.buildSymbol((analysisSession as KtFirAnalysisSession).firSymbolBuilder) as KtCallableSymbol?
}
}
}
private fun getOriginalOverriddenSymbol(member: FirCallableDeclaration): FirCallableDeclaration? {
val originalForSubstitutionOverride = member.originalForSubstitutionOverride
if (originalForSubstitutionOverride != null) return getOriginalOverriddenSymbol(originalForSubstitutionOverride)
val originalForIntersectionOverrideAttr = member.originalForIntersectionOverrideAttr
if (originalForIntersectionOverrideAttr != null) return getOriginalOverriddenSymbol(originalForIntersectionOverrideAttr)
val delegatedWrapperData = member.delegatedWrapperData
if (delegatedWrapperData != null) return getOriginalOverriddenSymbol(delegatedWrapperData.wrapped)
return member
}
}
@@ -0,0 +1,69 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.file.PsiPackageImpl
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.providers.createPackageProvider
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.symbolPointer
import org.jetbrains.kotlin.name.FqName
class KtFirPackageSymbol(
override val fqName: FqName,
private val project: Project,
override val token: ValidityToken
) : KtPackageSymbol(), ValidityTokenOwner {
override val psi: PsiElement? by cached {
JavaPsiFacade.getInstance(project).findPackage(fqName.asString())
?: KtPackage(PsiManager.getInstance(project), fqName, GlobalSearchScope.allScope(project)/*TODO*/)
}
override val origin: KtSymbolOrigin
get() = KtSymbolOrigin.SOURCE // TODO
override fun createPointer(): KtSymbolPointer<KtPackageSymbol> = symbolPointer { session ->
check(session is KtFirAnalysisSession)
session.firSymbolBuilder.createPackageSymbolIfOneExists(fqName)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as KtFirPackageSymbol
if (fqName != other.fqName) return false
if (token != other.token) return false
return true
}
override fun hashCode(): Int {
var result = fqName.hashCode()
result = 31 * result + token.hashCode()
return result
}
}
class KtPackage(
manager: PsiManager,
private val fqName: FqName,
private val scope: GlobalSearchScope
) : PsiPackageImpl(manager, fqName.asString().replace('/', '.')) {
override fun copy() = KtPackage(manager, fqName, scope)
override fun isValid(): Boolean = project.createPackageProvider(scope).isPackageExists(fqName)
}
@@ -0,0 +1,96 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
import org.jetbrains.kotlin.fir.resolve.getHasStableParameterNames
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertyGetterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
internal class KtFirPropertyGetterSymbol(
fir: FirPropertyAccessor,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder,
) : KtPropertyGetterSymbol(), KtFirSymbol<FirPropertyAccessor> {
init {
require(fir.isGetter)
}
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val isDefault: Boolean get() = firRef.withFir { it is FirDefaultPropertyAccessor }
override val isInline: Boolean get() = firRef.withFir { it.isInline }
override val isOverride: Boolean get() = firRef.withFir { it.isOverride }
override val hasBody: Boolean get() = firRef.withFir { it.body != null }
override val annotatedType: KtTypeAndAnnotations by cached {
firRef.returnTypeAndAnnotations(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE, builder)
}
override val modality: Modality get() = getModality()
override val visibility: Visibility get() = getVisibility()
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
/**
* Returns [CallableId] of the delegated Java method if the corresponding property of this getter is a synthetic Java property.
* Otherwise, returns `null`
*/
override val callableIdIfNonLocal: CallableId? by firRef.withFirAndCache { fir ->
if (fir is FirSyntheticPropertyAccessor) {
fir.delegate.symbol.callableId
} else null
}
override val dispatchType: KtType? by cached {
firRef.dispatchReceiverTypeAndAnnotations(builder)
}
override val receiverType: KtTypeAndAnnotations? by cached {
firRef.receiverTypeAndAnnotations(builder)
}
override val valueParameters: List<KtValueParameterSymbol>
get() = emptyList()
override val hasStableParameterNames: Boolean = firRef.withFir { it.getHasStableParameterNames(it.moduleData.session) }
override fun createPointer(): KtSymbolPointer<KtPropertyGetterSymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
TODO("Creating pointers for getters from library is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,101 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
import org.jetbrains.kotlin.fir.resolve.getHasStableParameterNames
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySetterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
internal class KtFirPropertySetterSymbol(
fir: FirPropertyAccessor,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder,
) : KtPropertySetterSymbol(), KtFirSymbol<FirPropertyAccessor> {
init {
require(fir.isSetter)
}
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val isDefault: Boolean get() = firRef.withFir { it is FirDefaultPropertyAccessor }
override val isInline: Boolean get() = firRef.withFir { it.isInline }
override val isOverride: Boolean get() = firRef.withFir { it.isOverride }
override val hasBody: Boolean get() = firRef.withFir { it.body != null }
override val modality: Modality get() = getModality()
override val visibility: Visibility get() = getVisibility()
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
/**
* Returns [CallableId] of the delegated Java method if the corresponding property of this setter is a synthetic Java property.
* Otherwise, returns `null`
*/
override val callableIdIfNonLocal: CallableId? by firRef.withFirAndCache { fir ->
if (fir is FirSyntheticPropertyAccessor) {
fir.delegate.symbol.callableId
} else null
}
override val parameter: KtValueParameterSymbol by firRef.withFirAndCache { fir ->
builder.variableLikeBuilder.buildValueParameterSymbol(fir.valueParameters.single())
}
override val valueParameters: List<KtValueParameterSymbol> by cached { listOf(parameter) }
override val annotatedType: KtTypeAndAnnotations by cached {
firRef.returnTypeAndAnnotations(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE, builder)
}
override val dispatchType: KtType? by cached {
firRef.dispatchReceiverTypeAndAnnotations(builder)
}
override val receiverType: KtTypeAndAnnotations? by cached {
firRef.receiverTypeAndAnnotations(builder)
}
override val hasStableParameterNames: Boolean = firRef.withFir { it.getHasStableParameterNames(it.moduleData.session) }
override fun createPointer(): KtSymbolPointer<KtPropertySetterSymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
TODO("Creating pointers for setters from library is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.resolve.getHasStableParameterNames
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirSamConstructorSymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtSamConstructorSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal class KtFirSamConstructorSymbol(
fir: FirSimpleFunction,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtSamConstructorSymbol(), KtFirSymbol<FirSimpleFunction> {
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val name: Name get() = firRef.withFir { it.name }
override val annotatedType: KtTypeAndAnnotations by cached {
firRef.returnTypeAndAnnotations(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE, builder)
}
override val valueParameters: List<KtValueParameterSymbol> by firRef.withFirAndCache { fir ->
fir.valueParameters.map { valueParameter ->
builder.variableLikeBuilder.buildValueParameterSymbol(valueParameter)
}
}
override val hasStableParameterNames: Boolean = firRef.withFir { it.getHasStableParameterNames(it.moduleData.session) }
override val isExtension: Boolean get() = firRef.withFir { it.receiverTypeRef != null }
override val receiverType: KtTypeAndAnnotations? by cached {
firRef.receiverTypeAndAnnotations(builder)
}
override val callableIdIfNonLocal: CallableId? get() = getCallableIdIfNonLocal()
override fun createPointer(): KtSymbolPointer<KtSamConstructorSymbol> {
return firRef.withFir { fir ->
val callableId = fir.symbol.callableId
KtFirSamConstructorSymbolPointer(ClassId(callableId.packageName, callableId.callableName))
}
}
}
@@ -0,0 +1,73 @@
/*
* 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.analysis.api.fir.symbols
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.originalIfFakeOverride
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectData
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.fir.utils.FirRefWithValidityCheck
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin
internal interface KtFirSymbol<out F : FirDeclaration> : KtSymbol, ValidityTokenOwner {
val firRef: FirRefWithValidityCheck<F>
override val origin: KtSymbolOrigin get() = firRef.withFir { it.ktSymbolOrigin() }
}
internal fun KtFirSymbol<*>.symbolEquals(other: Any?): Boolean {
if (other !is KtFirSymbol<*>) return false
if (this.token != other.token) return false
return this.firRef == other.firRef
}
internal fun KtFirSymbol<*>.symbolHashCode(): Int = firRef.hashCode() * 31 + token.hashCode()
private tailrec fun FirDeclaration.ktSymbolOrigin(): KtSymbolOrigin = when (origin) {
FirDeclarationOrigin.Source -> {
when (source?.kind) {
FirFakeSourceElementKind.ImplicitConstructor,
FirFakeSourceElementKind.DataClassGeneratedMembers,
FirFakeSourceElementKind.EnumGeneratedDeclaration,
FirFakeSourceElementKind.ItLambdaParameter -> KtSymbolOrigin.SOURCE_MEMBER_GENERATED
else -> KtSymbolOrigin.SOURCE
}
}
FirDeclarationOrigin.Library, FirDeclarationOrigin.BuiltIns -> KtSymbolOrigin.LIBRARY
FirDeclarationOrigin.Java -> KtSymbolOrigin.JAVA
FirDeclarationOrigin.SamConstructor -> KtSymbolOrigin.SAM_CONSTRUCTOR
FirDeclarationOrigin.Enhancement -> KtSymbolOrigin.JAVA
FirDeclarationOrigin.IntersectionOverride -> KtSymbolOrigin.INTERSECTION_OVERRIDE
FirDeclarationOrigin.Delegated -> KtSymbolOrigin.DELEGATED
FirDeclarationOrigin.Synthetic -> {
when {
this is FirSyntheticProperty -> KtSymbolOrigin.JAVA_SYNTHETIC_PROPERTY
else -> throw InvalidFirDeclarationOriginForSymbol(this)
}
}
FirDeclarationOrigin.ImportedFromObject -> {
val importedFromObjectData = (this as FirCallableDeclaration).importedFromObjectData
?: error("Declaration has ImportedFromObject origin, but no importedFromObjectData present")
importedFromObjectData.original.ktSymbolOrigin()
}
else -> {
val overridden = (this as? FirCallableDeclaration)?.originalIfFakeOverride()
?: throw InvalidFirDeclarationOriginForSymbol(this)
overridden.ktSymbolOrigin()
}
}
class InvalidFirDeclarationOriginForSymbol(declaration: FirDeclaration) :
IllegalStateException("Invalid FirDeclarationOrigin ${declaration.origin::class.simpleName} for ${declaration.render()}")
@@ -0,0 +1,144 @@
/*
* 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.analysis.api.fir.symbols
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.*
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
internal class KtFirSymbolProvider(
override val analysisSession: KtAnalysisSession,
firSymbolProvider: FirSymbolProvider,
private val resolveState: FirModuleResolveState,
private val firSymbolBuilder: KtSymbolByFirBuilder,
override val token: ValidityToken,
) : KtSymbolProvider(), ValidityTokenOwner {
private val firSymbolProvider by weakRef(firSymbolProvider)
override fun getParameterSymbol(psi: KtParameter): KtValueParameterSymbol = withValidityAssertion {
if (psi.isFunctionTypeParameter) {
error("Creating KtValueParameterSymbol for function type parameter is not possible. Please see the KDoc of getParameterSymbol")
}
psi.withFirDeclarationOfType<FirValueParameter, KtValueParameterSymbol>(resolveState) {
firSymbolBuilder.variableLikeBuilder.buildValueParameterSymbol(it)
}
}
override fun getFileSymbol(psi: KtFile): KtFileSymbol = withValidityAssertion {
firSymbolBuilder.buildFileSymbol(psi.getOrBuildFirFile(resolveState))
}
override fun getFunctionLikeSymbol(psi: KtNamedFunction): KtFunctionLikeSymbol = withValidityAssertion {
psi.withFirDeclarationOfType<FirFunction, KtFunctionLikeSymbol>(resolveState) { fir ->
when (fir) {
is FirSimpleFunction -> {
if (fir.origin == FirDeclarationOrigin.SamConstructor) {
firSymbolBuilder.functionLikeBuilder.buildSamConstructorSymbol(fir)
} else {
firSymbolBuilder.functionLikeBuilder.buildFunctionSymbol(fir)
}
}
is FirAnonymousFunction -> firSymbolBuilder.functionLikeBuilder.buildAnonymousFunctionSymbol(fir)
else -> error("Unexpected ${fir.renderWithType()}")
}
}
}
override fun getConstructorSymbol(psi: KtConstructor<*>): KtConstructorSymbol = withValidityAssertion {
psi.withFirDeclarationOfType<FirConstructor, KtConstructorSymbol>(resolveState) {
firSymbolBuilder.functionLikeBuilder.buildConstructorSymbol(it)
}
}
override fun getTypeParameterSymbol(psi: KtTypeParameter): KtTypeParameterSymbol = withValidityAssertion {
psi.withFirDeclarationOfType<FirTypeParameter, KtTypeParameterSymbol>(resolveState) {
firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol(it)
}
}
override fun getTypeAliasSymbol(psi: KtTypeAlias): KtTypeAliasSymbol = withValidityAssertion {
psi.withFirDeclarationOfType<FirTypeAlias, KtTypeAliasSymbol>(resolveState) {
firSymbolBuilder.classifierBuilder.buildTypeAliasSymbol(it)
}
}
override fun getEnumEntrySymbol(psi: KtEnumEntry): KtEnumEntrySymbol = withValidityAssertion {
psi.withFirDeclarationOfType<FirEnumEntry, KtEnumEntrySymbol>(resolveState) {
firSymbolBuilder.buildEnumEntrySymbol(it)
}
}
override fun getAnonymousFunctionSymbol(psi: KtNamedFunction): KtAnonymousFunctionSymbol = withValidityAssertion {
psi.withFirDeclarationOfType<FirSimpleFunction, KtFunctionSymbol>(resolveState) {
firSymbolBuilder.functionLikeBuilder.buildFunctionSymbol(it)
}
firSymbolBuilder.functionLikeBuilder.buildAnonymousFunctionSymbol(psi.getOrBuildFirOfType(resolveState))
}
override fun getAnonymousFunctionSymbol(psi: KtFunctionLiteral): KtAnonymousFunctionSymbol = withValidityAssertion {
psi.withFirDeclarationOfType<FirAnonymousFunction, KtAnonymousFunctionSymbol>(resolveState) {
firSymbolBuilder.functionLikeBuilder.buildAnonymousFunctionSymbol(it)
}
}
override fun getVariableSymbol(psi: KtProperty): KtVariableSymbol = withValidityAssertion {
psi.withFirDeclarationOfType<FirProperty, KtVariableSymbol>(resolveState) {
firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(it)
}
}
override fun getAnonymousObjectSymbol(psi: KtObjectLiteralExpression): KtAnonymousObjectSymbol = withValidityAssertion {
psi.objectDeclaration.withFirDeclarationOfType<FirAnonymousObject, KtAnonymousObjectSymbol>(resolveState) {
firSymbolBuilder.classifierBuilder.buildAnonymousObjectSymbol(it)
}
}
override fun getClassOrObjectSymbol(psi: KtClassOrObject): KtClassOrObjectSymbol = withValidityAssertion {
psi.withFirDeclarationOfType<FirClass, KtClassOrObjectSymbol>(resolveState) {
firSymbolBuilder.classifierBuilder.buildClassOrObjectSymbol(it)
}
}
override fun getNamedClassOrObjectSymbol(psi: KtClassOrObject): KtNamedClassOrObjectSymbol? = withValidityAssertion {
require(psi !is KtObjectDeclaration || psi.parent !is KtObjectLiteralExpression)
// A KtClassOrObject may also map to an FirEnumEntry. Hence, we need to return null in this case.
if (psi is KtEnumEntry) return null
psi.withFirDeclarationOfType<FirRegularClass, KtNamedClassOrObjectSymbol>(resolveState) {
firSymbolBuilder.classifierBuilder.buildNamedClassOrObjectSymbol(it)
}
}
override fun getPropertyAccessorSymbol(psi: KtPropertyAccessor): KtPropertyAccessorSymbol = withValidityAssertion {
psi.withFirDeclarationOfType<FirPropertyAccessor, KtPropertyAccessorSymbol>(resolveState) {
firSymbolBuilder.callableBuilder.buildPropertyAccessorSymbol(it)
}
}
override fun getClassOrObjectSymbolByClassId(classId: ClassId): KtClassOrObjectSymbol? = withValidityAssertion {
val symbol = firSymbolProvider.getClassLikeSymbolByClassId(classId) as? FirRegularClassSymbol ?: return null
firSymbolBuilder.classifierBuilder.buildNamedClassOrObjectSymbol(symbol.fir)
}
override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): Sequence<KtSymbol> {
val firs = firSymbolProvider.getTopLevelCallableSymbols(packageFqName, name)
return firs.asSequence().map { firSymbol -> firSymbolBuilder.buildSymbol(firSymbol.fir) }
}
override val ROOT_PACKAGE_SYMBOL: KtPackageSymbol = KtFirPackageSymbol(FqName.ROOT, resolveState.project, token)
}
@@ -0,0 +1,103 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.convertConstantExpression
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtConstantValue
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal class KtFirSyntheticJavaPropertySymbol(
fir: FirSyntheticProperty,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtSyntheticJavaPropertySymbol(), KtFirSymbol<FirSyntheticProperty> {
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val isVal: Boolean get() = firRef.withFir { it.isVal }
override val name: Name get() = firRef.withFir { it.name }
override val annotatedType: KtTypeAndAnnotations by cached {
firRef.returnTypeAndAnnotations(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE, builder)
}
override val dispatchType: KtType? by cached {
firRef.dispatchReceiverTypeAndAnnotations(builder)
}
override val receiverType: KtTypeAndAnnotations? by cached {
firRef.receiverTypeAndAnnotations(builder)
}
override val isExtension: Boolean get() = firRef.withFir { it.receiverTypeRef != null }
override val initializer: KtConstantValue? by firRef.withFirAndCache(FirResolvePhase.BODY_RESOLVE) { fir -> fir.initializer?.convertConstantExpression() }
override val modality: Modality get() = getModality()
override val visibility: Visibility get() = getVisibility()
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
override val callableIdIfNonLocal: CallableId? get() = getCallableIdIfNonLocal()
override val getter: KtPropertyGetterSymbol by firRef.withFirAndCache(FirResolvePhase.RAW_FIR) { property ->
property.getter.let { builder.callableBuilder.buildPropertyAccessorSymbol(it) } as KtPropertyGetterSymbol
}
override val javaGetterSymbol: KtFunctionSymbol
get() {
return firRef.withFir { builder.functionLikeBuilder.buildFunctionSymbol(it.getter.delegate) }
}
override val javaSetterSymbol: KtFunctionSymbol?
get() {
return firRef.withFir { fir ->
fir.setter?.delegate?.let { setter -> builder.functionLikeBuilder.buildFunctionSymbol(setter) }
}
}
override val setter: KtPropertySetterSymbol? by firRef.withFirAndCache(FirResolvePhase.RAW_FIR) { property ->
property.setter?.let { builder.callableBuilder.buildPropertyAccessorSymbol(it) } as? KtPropertySetterSymbol
}
override val isFromPrimaryConstructor: Boolean get() = false
override val isOverride: Boolean get() = firRef.withFir { it.isOverride }
override val isStatic: Boolean get() = firRef.withFir { it.isStatic }
override val hasSetter: Boolean get() = firRef.withFir { it.setter != null }
override val origin: KtSymbolOrigin get() = withValidityAssertion { KtSymbolOrigin.JAVA_SYNTHETIC_PROPERTY }
override fun createPointer(): KtSymbolPointer<KtSyntheticJavaPropertySymbol> {
TODO("pointers to KtSyntheticJavaPropertySymbol is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,64 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtTypeAliasSymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal class KtFirTypeAliasSymbol(
fir: FirTypeAlias,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder,
) : KtTypeAliasSymbol(), KtFirSymbol<FirTypeAlias> {
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val name: Name get() = firRef.withFir { it.name }
override val classIdIfNonLocal: ClassId get() = firRef.withFir { it.symbol.classId }
override val visibility: Visibility
get() = when (val possiblyRawVisibility = getVisibility(FirResolvePhase.RAW_FIR)) {
Visibilities.Unknown -> Visibilities.Public
else -> possiblyRawVisibility
}
override val typeParameters by firRef.withFirAndCache { fir ->
fir.typeParameters.filterIsInstance<FirTypeParameter>().map { typeParameter ->
builder.classifierBuilder.buildTypeParameterSymbol(typeParameter.symbol.fir)
}
}
override val expandedType: KtType by firRef.withFirAndCache(FirResolvePhase.SUPER_TYPES) { fir ->
builder.typeBuilder.buildKtType(fir.expandedTypeRef)
}
override fun createPointer(): KtSymbolPointer<KtTypeAliasSymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
TODO("Creating symbols for library typealiases is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,105 @@
/*
* 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.analysis.api.fir.symbols
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.transformers.resolveSupertypesInTheAir
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveType
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.KtFirAnnotationCall
import org.jetbrains.kotlin.analysis.api.fir.utils.FirRefWithValidityCheck
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
internal class KtFirTypeAndAnnotations<T : FirDeclaration>(
private val containingDeclaration: FirRefWithValidityCheck<T>,
@Suppress("UNUSED_PARAMETER") typeResolvePhase: FirResolvePhase,
_builder: KtSymbolByFirBuilder,
private val typeRef: (T) -> FirTypeRef,
) : KtTypeAndAnnotations() {
private val builder by weakRef(_builder)
override val token: ValidityToken get() = containingDeclaration.token
override val type: KtType by containingDeclaration.withFirAndCache(ResolveType.CallableReturnType) { fir ->
builder.typeBuilder.buildKtType(typeRef(fir))
}
override val annotations: List<KtAnnotationCall> by containingDeclaration.withFirAndCache { fir ->
typeRef(fir).annotations.map {
KtFirAnnotationCall(containingDeclaration, it)
}
}
}
internal class KtSimpleFirTypeAndAnnotations(
coneType: ConeKotlinType,
annotationsList: List<KtAnnotationCall>,
builder: KtSymbolByFirBuilder,
override val token: ValidityToken
) : KtTypeAndAnnotations() {
private val coneTypeRef by weakRef(coneType)
private val annotationsListRef by weakRef(annotationsList)
override val type: KtType by cached {
builder.typeBuilder.buildKtType(coneTypeRef)
}
override val annotations: List<KtAnnotationCall> get() = annotationsListRef
}
internal fun FirRefWithValidityCheck<FirClass>.superTypesAndAnnotationsList(builder: KtSymbolByFirBuilder): List<KtTypeAndAnnotations> =
withFir(FirResolvePhase.SUPER_TYPES) { fir ->
fir.superTypeRefs.mapToTypeAndAnnotations(this, builder)
}
internal fun FirRefWithValidityCheck<FirRegularClass>.superTypesAndAnnotationsListForRegularClass(builder: KtSymbolByFirBuilder): List<KtTypeAndAnnotations> {
return withFir { fir ->
if(fir.resolvePhase >= FirResolvePhase.SUPER_TYPES) {
fir.superTypeRefs.mapToTypeAndAnnotations(this, builder)
} else null
} ?: withFirByType(ResolveType.NoResolve) { fir ->
fir.resolveSupertypesInTheAir(builder.rootSession).mapToTypeAndAnnotations(this, builder)
}
}
private fun List<FirTypeRef>.mapToTypeAndAnnotations(
containingDeclaration: FirRefWithValidityCheck<FirClass>,
builder: KtSymbolByFirBuilder,
) = map { typeRef ->
val annotations = typeRef.annotations.map { annotation ->
KtFirAnnotationCall(containingDeclaration, annotation)
}
KtSimpleFirTypeAndAnnotations(typeRef.coneType, annotations, builder, containingDeclaration.token)
}
internal fun FirRefWithValidityCheck<FirTypedDeclaration>.returnTypeAndAnnotations(
typeResolvePhase: FirResolvePhase,
builder: KtSymbolByFirBuilder
) = KtFirTypeAndAnnotations(this, typeResolvePhase, builder) { it.returnTypeRef }
internal fun FirRefWithValidityCheck<FirCallableDeclaration>.receiverTypeAndAnnotations(builder: KtSymbolByFirBuilder) = withFir { fir ->
fir.receiverTypeRef?.let { _ ->
KtFirTypeAndAnnotations(this, FirResolvePhase.TYPES, builder) {
it.receiverTypeRef ?: error { "Receiver expected for callable declaration but it is null" }
}
}
}
internal fun FirRefWithValidityCheck<FirCallableDeclaration>.dispatchReceiverTypeAndAnnotations(builder: KtSymbolByFirBuilder) =
withFir { fir ->
fir.dispatchReceiverType?.let {
builder.typeBuilder.buildKtType(it)
}
}
@@ -0,0 +1,50 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
internal class KtFirTypeParameterSymbol(
fir: FirTypeParameter,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtTypeParameterSymbol(), KtFirSymbol<FirTypeParameter> {
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val name: Name get() = firRef.withFir { it.name }
override val upperBounds: List<KtType> by firRef.withFirAndCache(FirResolvePhase.TYPES) { fir ->
fir.bounds.map { type -> builder.typeBuilder.buildKtType(type) }
}
override val variance: Variance get() = firRef.withFir { it.variance }
override val isReified: Boolean get() = firRef.withFir { it.isReified }
override fun createPointer(): KtSymbolPointer<KtTypeParameterSymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
TODO("Creating symbols for library type parameters is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,72 @@
/*
* 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.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.types.arrayElementType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.KtFirAnnotationCall
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.containsAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.getAnnotationClassIds
import org.jetbrains.kotlin.analysis.api.fir.symbols.annotations.toAnnotationsList
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.firRef
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtTypeAndAnnotations
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal class KtFirValueParameterSymbol(
fir: FirValueParameter,
resolveState: FirModuleResolveState,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder
) : KtValueParameterSymbol(), KtFirSymbol<FirValueParameter> {
private val builder by weakRef(_builder)
override val firRef = firRef(fir, resolveState)
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
override val name: Name get() = firRef.withFir { it.name }
override val isVararg: Boolean get() = firRef.withFir { it.isVararg }
override val annotatedType: KtTypeAndAnnotations by firRef.withFirAndCache(FirResolvePhase.TYPES) { fir ->
if (fir.isVararg) {
val annotations = fir.returnTypeRef.annotations.map { annotation ->
KtFirAnnotationCall(firRef, annotation)
}
// There SHOULD always be an array element type (even if it is an error type, e.g., unresolved).
val arrayElementType = fir.returnTypeRef.coneType.arrayElementType()
?: error("No array element type for vararg value parameter: ${fir.renderWithType()}")
KtSimpleFirTypeAndAnnotations(arrayElementType, annotations, builder, firRef.token)
} else {
firRef.returnTypeAndAnnotations(FirResolvePhase.TYPES, builder)
}
}
override val hasDefaultValue: Boolean get() = firRef.withFir { it.defaultValue != null }
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
override fun createPointer(): KtSymbolPointer<KtValueParameterSymbol> {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it }
TODO("Creating pointers for functions parameters from library is not supported yet")
}
override fun equals(other: Any?): Boolean = symbolEquals(other)
override fun hashCode(): Int = symbolHashCode()
}
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.symbols.annotations
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.analysis.api.fir.findPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveType
import org.jetbrains.kotlin.analysis.api.fir.utils.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotationCall
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedConstantValue
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtCallElement
internal class KtFirAnnotationCall(
private val containingDeclaration: FirRefWithValidityCheck<FirDeclaration>,
annotation: FirAnnotation
) : KtAnnotationCall() {
private val annotationCallRef by weakRef(annotation)
override val token: ValidityToken get() = containingDeclaration.token
override val psi: KtCallElement? by containingDeclaration.withFirAndCache { fir ->
annotationCallRef.findPsi(fir.moduleData.session) as? KtCallElement
}
override val classId: ClassId? by cached {
containingDeclaration.withFirByType(ResolveType.AnnotationType) { fir ->
annotationCallRef.getClassId(fir.moduleData.session)
}
}
override val useSiteTarget: AnnotationUseSiteTarget? get() = annotationCallRef.useSiteTarget
override val arguments: List<KtNamedConstantValue> by containingDeclaration.withFirAndCache(ResolveType.AnnotationsArguments) { fir ->
mapAnnotationParameters(annotationCallRef, fir.moduleData.session).map { (name, expression) ->
KtNamedConstantValue(name, expression.convertConstantExpression())
}
}
override fun equals(other: Any?): Boolean {
if (other !is KtFirAnnotationCall) return false
if (this.token != other.token) return false
return annotationCallRef == other.annotationCallRef
}
override fun hashCode(): Int {
return token.hashCode() * 31 + annotationCallRef.hashCode()
}
}
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.symbols.annotations
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.coneClassLikeType
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveType
import org.jetbrains.kotlin.analysis.api.fir.utils.FirRefWithValidityCheck
import org.jetbrains.kotlin.name.ClassId
internal fun FirAnnotation.getClassId(session: FirSession): ClassId? =
coneClassLikeType?.fullyExpandedType(session)?.classId
internal fun FirRefWithValidityCheck<FirAnnotatedDeclaration>.toAnnotationsList() = withFir { fir ->
fir.annotations.map { KtFirAnnotationCall(this, it) }
}
internal fun FirRefWithValidityCheck<FirAnnotatedDeclaration>.containsAnnotation(classId: ClassId): Boolean =
withFirByType(ResolveType.AnnotationType) { fir ->
fir.annotations.any { it.getClassId(fir.moduleData.session) == classId }
}
internal fun FirRefWithValidityCheck<FirAnnotatedDeclaration>.getAnnotationClassIds(): Collection<ClassId> =
withFirByType(ResolveType.AnnotationType) { fir ->
fir.annotations.mapNotNull { it.getClassId(fir.moduleData.session) }
}
@@ -0,0 +1,51 @@
/*
* 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.analysis.api.fir.symbols
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirRenderer
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.psi.KtDeclaration
internal fun <F> KtFirSymbol<F>.getModality(
phase: FirResolvePhase = FirResolvePhase.STATUS,
defaultModality: Modality? = null
): Modality where F : FirDeclaration, F : FirMemberDeclaration {
return firRef.withFir(phase) { fir ->
fir.modality
?: defaultModality
?: fir.invalidModalityError()
}
}
private fun FirDeclaration.invalidModalityError(): Nothing {
error(
"""|Symbol modality should not be null, looks like the FIR symbol was not properly resolved
|
|${renderWithType(FirRenderer.RenderMode.WithResolvePhases)}
|
|${(psi as? KtDeclaration)?.getElementTextInContext()}""".trimMargin()
)
}
internal fun <F> KtFirSymbol<F>.getVisibility(
phase: FirResolvePhase = FirResolvePhase.STATUS
): Visibility where F : FirMemberDeclaration, F : FirDeclaration =
firRef.withFir(phase) { fir -> fir.visibility }
internal fun KtFirSymbol<FirCallableDeclaration>.getCallableIdIfNonLocal(): CallableId? =
firRef.withFir { fir -> fir.symbol.callableId.takeUnless { it.isLocal } }
@@ -0,0 +1,29 @@
/*
* 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.analysis.api.fir.symbols.pointers
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirKotlinPropertySymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtBackingFieldSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtKotlinPropertySymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
internal class KtFirBackingFieldSymbolPointer(
private val propertySymbolPointer: KtSymbolPointer<KtKotlinPropertySymbol>,
) : KtSymbolPointer<KtBackingFieldSymbol>() {
@Deprecated("Consider using org.jetbrains.kotlin.analysis.api.KtAnalysisSession.restoreSymbol")
override fun restoreSymbol(analysisSession: KtAnalysisSession): KtBackingFieldSymbol? {
require(analysisSession is KtFirAnalysisSession)
@Suppress("DEPRECATION")
val propertySymbol = propertySymbolPointer.restoreSymbol(analysisSession) ?: return null
check(propertySymbol is KtFirKotlinPropertySymbol)
return propertySymbol.firRef.withFir { firProperty ->
analysisSession.firSymbolBuilder.variableLikeBuilder.buildBackingFieldSymbolByProperty(firProperty)
}
}
}
@@ -0,0 +1,20 @@
/*
* 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.analysis.api.fir.symbols.pointers
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.name.ClassId
class KtFirClassOrObjectInLibrarySymbolPointer(private val classId: ClassId) : KtSymbolPointer<KtNamedClassOrObjectSymbol>() {
@Deprecated("Consider using org.jetbrains.kotlin.analysis.api.KtAnalysisSession.restoreSymbol")
override fun restoreSymbol(analysisSession: KtAnalysisSession): KtNamedClassOrObjectSymbol? {
require(analysisSession is KtFirAnalysisSession)
return analysisSession.firSymbolBuilder.classifierBuilder.buildClassLikeSymbolByClassId(classId) as? KtNamedClassOrObjectSymbol
}
}
@@ -0,0 +1,32 @@
/*
* 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.analysis.api.fir.symbols.pointers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.name.ClassId
internal class KtFirConstructorSymbolPointer(
ownerClassId: ClassId,
private val isPrimary: Boolean,
private val signature: IdSignature
) : KtFirMemberSymbolPointer<KtConstructorSymbol>(ownerClassId) {
override fun KtFirAnalysisSession.chooseCandidateAndCreateSymbol(
candidates: FirScope,
firSession: FirSession
): KtConstructorSymbol? {
val firConstructor =
candidates.findDeclarationWithSignature<FirConstructor>(signature, firSession) { processDeclaredConstructors(it) }
?: return null
if (firConstructor.isPrimary != isPrimary) return null
return firSymbolBuilder.functionLikeBuilder.buildConstructorSymbol(firConstructor)
}
}
@@ -0,0 +1,44 @@
/*
* 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.analysis.api.fir.symbols.pointers
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal class KtFirEnumEntrySymbolPointer(
private val ownerClassId: ClassId,
private val name: Name
) : KtSymbolPointer<KtEnumEntrySymbol>() {
@Deprecated("Consider using org.jetbrains.kotlin.analysis.api.KtAnalysisSession.restoreSymbol")
override fun restoreSymbol(analysisSession: KtAnalysisSession): KtEnumEntrySymbol? {
require(analysisSession is KtFirAnalysisSession)
val enumClass = getEnumClass(analysisSession, ownerClassId)
?: return null
val enumEntry = enumClass.enumEntryByName(name)
?: return null
return analysisSession.firSymbolBuilder.buildEnumEntrySymbol(enumEntry)
}
private fun getEnumClass(analysisSession: KtFirAnalysisSession, classId: ClassId): FirRegularClass? {
val enumClass = analysisSession.firSymbolProvider.getClassLikeSymbolByClassId(classId)?.fir as? FirRegularClass
?: return null
if (enumClass.classKind != ClassKind.ENUM_CLASS) return null
return enumClass
}
private fun FirRegularClass.enumEntryByName(name: Name): FirEnumEntry? =
declarations.firstOrNull { member ->
member is FirEnumEntry && member.name == name
} as FirEnumEntry?
}
@@ -0,0 +1,32 @@
/*
* 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.analysis.api.fir.symbols.pointers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal class KtFirMemberFunctionSymbolPointer(
ownerClassId: ClassId,
private val name: Name,
private val signature: IdSignature
) : KtFirMemberSymbolPointer<KtFunctionSymbol>(ownerClassId) {
override fun KtFirAnalysisSession.chooseCandidateAndCreateSymbol(
candidates: FirScope,
firSession: FirSession
): KtFunctionSymbol? {
val firFunction = candidates.findDeclarationWithSignature<FirSimpleFunction>(signature, firSession) {
processFunctionsByName(name, it)
} ?: return null
return firSymbolBuilder.functionLikeBuilder.buildFunctionSymbol(firFunction)
}
}
@@ -0,0 +1,32 @@
/*
* 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.analysis.api.fir.symbols.pointers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtKotlinPropertySymbol
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal class KtFirMemberPropertySymbolPointer(
ownerClassId: ClassId,
private val name: Name,
private val signature: IdSignature
) : KtFirMemberSymbolPointer<KtKotlinPropertySymbol>(ownerClassId) {
override fun KtFirAnalysisSession.chooseCandidateAndCreateSymbol(
candidates: FirScope,
firSession: FirSession
): KtKotlinPropertySymbol? {
val firProperty = candidates.findDeclarationWithSignature<FirProperty>(signature, firSession) { processPropertiesByName(name, it) }
?: return null
return firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firProperty) as? KtKotlinPropertySymbol
}
}
@@ -0,0 +1,39 @@
/*
* 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.analysis.api.fir.symbols.pointers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.name.ClassId
internal abstract class KtFirMemberSymbolPointer<S : KtSymbol>(
private val ownerClassId: ClassId,
) : KtSymbolPointer<S>() {
@Deprecated("Consider using org.jetbrains.kotlin.analysis.api.KtAnalysisSession.restoreSymbol")
final override fun restoreSymbol(analysisSession: KtAnalysisSession): S? {
require(analysisSession is KtFirAnalysisSession)
val owner = analysisSession.getClassLikeSymbol(ownerClassId) as? FirRegularClass
?: return null
val scope = owner.unsubstitutedScope(
analysisSession.firResolveState.rootModuleSession,
ScopeSession(),
withForcedTypeCalculator = false
)
return analysisSession.chooseCandidateAndCreateSymbol(scope, owner.moduleData.session)
}
protected abstract fun KtFirAnalysisSession.chooseCandidateAndCreateSymbol(
candidates: FirScope,
firSession: FirSession
): S?
}
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.symbols.pointers
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtSamConstructorSymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.name.ClassId
internal class KtFirSamConstructorSymbolPointer(
private val ownerClassId: ClassId,
) : KtSymbolPointer<KtSamConstructorSymbol>() {
@Deprecated("Consider using org.jetbrains.kotlin.analysis.api.KtAnalysisSession.restoreSymbol")
override fun restoreSymbol(analysisSession: KtAnalysisSession): KtSamConstructorSymbol? {
require(analysisSession is KtFirAnalysisSession)
val owner = analysisSession.getClassLikeSymbol(ownerClassId) as? FirRegularClass ?: return null
val classSymbol = analysisSession.firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(owner)
with(analysisSession) {
return classSymbol.getSamConstructor()
}
}
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2021 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.analysis.api.fir.symbols.pointers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.name.CallableId
internal abstract class KtTopLevelCallableSymbolPointer<S : KtCallableSymbol>(
private val callableId: CallableId
) : KtSymbolPointer<S>() {
@Deprecated("Consider using org.jetbrains.kotlin.analysis.api.KtAnalysisSession.restoreSymbol")
final override fun restoreSymbol(analysisSession: KtAnalysisSession): S? {
require(analysisSession is KtFirAnalysisSession)
val candidates = analysisSession.getCallableSymbols(callableId)
if (candidates.isEmpty()) return null
val session = candidates.first().fir.moduleData.session
return analysisSession.chooseCandidateAndCreateSymbol(candidates, session)
}
protected abstract fun KtFirAnalysisSession.chooseCandidateAndCreateSymbol(
candidates: Collection<FirCallableSymbol<*>>,
firSession: FirSession
): S?
}
private fun KtFirAnalysisSession.getCallableSymbols(callableId: CallableId) =
firResolveState.rootModuleSession.symbolProvider.getTopLevelCallableSymbols(callableId.packageName, callableId.callableName)
@@ -0,0 +1,30 @@
/*
* 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.analysis.api.fir.symbols.pointers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
internal class KtFirTopLevelFunctionSymbolPointer(
callableId: CallableId,
private val signature: IdSignature
) : KtTopLevelCallableSymbolPointer<KtFunctionSymbol>(callableId) {
override fun KtFirAnalysisSession.chooseCandidateAndCreateSymbol(
candidates: Collection<FirCallableSymbol<*>>,
firSession: FirSession
): KtFunctionSymbol? {
val firFunction = candidates.findDeclarationWithSignatureBySymbols<FirSimpleFunction>(signature, firSession) ?: return null
return firSymbolBuilder.functionLikeBuilder.buildFunctionSymbol(firFunction)
}
}
@@ -0,0 +1,58 @@
/*
* 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.analysis.api.fir.symbols.pointers
import org.jetbrains.kotlin.fir.FirRenderer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.analysis.low.level.api.fir.ideSessionComponents
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.name.ClassId
internal inline fun <reified D : FirDeclaration> FirScope.findDeclarationWithSignature(
signature: IdSignature,
firSession: FirSession,
processor: FirScope.((FirBasedSymbol<*>) -> Unit) -> Unit
): D? {
val signatureComposer = firSession.ideSessionComponents.signatureComposer
var foundSymbol: D? = null
processor { symbol ->
val declaration = symbol.fir
if (declaration is D && signatureComposer.composeSignature(declaration) == signature) {
foundSymbol = declaration
}
}
return foundSymbol
}
internal inline fun <reified D : FirDeclaration> Collection<FirCallableSymbol<*>>.findDeclarationWithSignatureBySymbols(
signature: IdSignature,
firSession: FirSession
): D? {
val signatureComposer = firSession.ideSessionComponents.signatureComposer
for (symbol in this) {
val declaration = symbol.fir
if (declaration is D && signatureComposer.composeSignature(declaration) == signature) {
return declaration
}
}
return null
}
internal fun FirDeclaration.createSignature(): IdSignature {
val signatureComposer = moduleData.session.ideSessionComponents.signatureComposer
return signatureComposer.composeSignature(this)
?: error("Could not compose signature for ${this.renderWithType(FirRenderer.RenderMode.WithResolvePhases)}, looks like it is private or local")
}
internal fun KtFirAnalysisSession.getClassLikeSymbol(classId: ClassId) =
firResolveState.rootModuleSession.symbolProvider.getClassLikeSymbolByClassId(classId)?.fir
@@ -0,0 +1,227 @@
/*
* 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.analysis.api.fir.types
import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType
import org.jetbrains.kotlin.fir.resolve.inference.receiverType
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols
import org.jetbrains.kotlin.analysis.api.KtTypeArgument
import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.fir.utils.weakRef
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.*
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal interface KtFirType : ValidityTokenOwner {
val coneType: ConeKotlinType
}
private fun KtFirType.typeEquals(other: Any?): Boolean {
if (other !is KtFirType) return false
if (this.token != other.token) return false
return this.coneType == other.coneType
}
private fun KtFirType.typeHashcode(): Int = token.hashCode() * 31 + coneType.hashCode()
internal class KtFirUsualClassType(
_coneType: ConeClassLikeTypeImpl,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder,
) : KtUsualClassType(), KtFirType {
override val coneType by weakRef(_coneType)
private val builder by weakRef(_builder)
override val classId: ClassId get() = withValidityAssertion { coneType.lookupTag.classId }
override val classSymbol: KtClassLikeSymbol by cached {
builder.classifierBuilder.buildClassLikeSymbolByLookupTag(coneType.lookupTag)
?: error("Class ${coneType.lookupTag} was not found")
}
override val typeArguments: List<KtTypeArgument> by cached {
coneType.typeArguments.map { typeArgument ->
builder.typeBuilder.buildTypeArgument(typeArgument)
}
}
override val nullability: KtTypeNullability get() = withValidityAssertion { coneType.nullability.asKtNullability() }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirFunctionalType(
_coneType: ConeClassLikeTypeImpl,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder,
) : KtFunctionalType(), KtFirType {
override val coneType by weakRef(_coneType)
private val builder by weakRef(_builder)
override val classId: ClassId get() = withValidityAssertion { coneType.lookupTag.classId }
override val classSymbol: KtClassLikeSymbol by cached {
builder.classifierBuilder.buildClassLikeSymbolByLookupTag(coneType.lookupTag)
?: error("Class ${coneType.lookupTag} was not found")
}
override val typeArguments: List<KtTypeArgument> by cached {
coneType.typeArguments.map { typeArgument ->
builder.typeBuilder.buildTypeArgument(typeArgument)
}
}
override val nullability: KtTypeNullability get() = withValidityAssertion { coneType.nullability.asKtNullability() }
override val isSuspend: Boolean get() = withValidityAssertion { coneType.isSuspendFunctionType(builder.rootSession) }
override val arity: Int
get() = withValidityAssertion {
if (coneType.isExtensionFunctionType) coneType.typeArguments.size - 2
else coneType.typeArguments.size - 1
}
override val receiverType: KtType?
get() = withValidityAssertion {
if (coneType.isExtensionFunctionType) (typeArguments.first() as KtTypeArgumentWithVariance).type
else null
}
override val hasReceiver: Boolean
get() = withValidityAssertion {
coneType.receiverType(builder.rootSession) != null
}
override val parameterTypes: List<KtType> by cached {
val parameterTypeArgs = if (coneType.isExtensionFunctionType) typeArguments.subList(1, typeArguments.lastIndex)
else typeArguments.subList(0, typeArguments.lastIndex)
parameterTypeArgs.map { (it as KtTypeArgumentWithVariance).type }
}
override val returnType: KtType
get() = withValidityAssertion { (typeArguments.last() as KtTypeArgumentWithVariance).type }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirClassErrorType(
_coneType: ConeClassErrorType,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder,
) : KtClassErrorType(), KtFirType {
override val coneType by weakRef(_coneType)
private val builder by weakRef(_builder)
override val error: String get() = withValidityAssertion { coneType.diagnostic.reason }
override val nullability: KtTypeNullability get() = withValidityAssertion { coneType.nullability.asKtNullability() }
override val candidateClassSymbols: Collection<KtClassLikeSymbol> by cached {
val symbols = coneType.diagnostic.getCandidateSymbols().filterIsInstance<FirClassLikeSymbol<*>>()
symbols.map { builder.classifierBuilder.buildClassLikeSymbol(it.fir) }
}
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirCapturedType(
_coneType: ConeCapturedType,
override val token: ValidityToken,
) : KtCapturedType(), KtFirType {
override val coneType by weakRef(_coneType)
override val nullability: KtTypeNullability get() = withValidityAssertion { coneType.nullability.asKtNullability() }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirDefinitelyNotNullType(
_coneType: ConeDefinitelyNotNullType,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder,
) : KtDefinitelyNotNullType(), KtFirType {
override val coneType by weakRef(_coneType)
private val builder by weakRef(_builder)
override val original: KtType by cached { builder.typeBuilder.buildKtType(this.coneType.original) }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirTypeParameterType(
_coneType: ConeTypeParameterType,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder,
) : KtTypeParameterType(), KtFirType {
override val coneType by weakRef(_coneType)
private val builder by weakRef(_builder)
override val name: Name get() = withValidityAssertion { coneType.lookupTag.name }
override val symbol: KtTypeParameterSymbol by cached {
builder.classifierBuilder.buildTypeParameterSymbolByLookupTag(coneType.lookupTag)
?: error("Type parameter ${coneType.lookupTag} was not found")
}
override val nullability: KtTypeNullability get() = withValidityAssertion { coneType.nullability.asKtNullability() }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirFlexibleType(
_coneType: ConeFlexibleType,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder,
) : KtFlexibleType(), KtFirType {
override val coneType by weakRef(_coneType)
private val builder by weakRef(_builder)
override val lowerBound: KtType by cached { builder.typeBuilder.buildKtType(coneType.lowerBound) }
override val upperBound: KtType by cached { builder.typeBuilder.buildKtType(coneType.upperBound) }
override val nullability: KtTypeNullability get() = withValidityAssertion { coneType.nullability.asKtNullability() }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
internal class KtFirIntersectionType(
_coneType: ConeIntersectionType,
override val token: ValidityToken,
_builder: KtSymbolByFirBuilder,
) : KtIntersectionType(), KtFirType {
override val coneType by weakRef(_coneType)
private val builder by weakRef(_builder)
override val conjuncts: List<KtType> by cached {
coneType.intersectedTypes.map { conjunct -> builder.typeBuilder.buildKtType(conjunct) }
}
override val nullability: KtTypeNullability get() = withValidityAssertion { coneType.nullability.asKtNullability() }
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
override fun equals(other: Any?) = typeEquals(other)
override fun hashCode() = typeHashcode()
}
private fun ConeNullability.asKtNullability(): KtTypeNullability = when (this) {
ConeNullability.NULLABLE -> KtTypeNullability.NULLABLE
ConeNullability.UNKNOWN -> KtTypeNullability.UNKNOWN
ConeNullability.NOT_NULL -> KtTypeNullability.NON_NULLABLE
}

Some files were not shown because too many files have changed in this diff Show More