FIR IDE: move analysis api fir main sources to the analysis directory
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
+153
@@ -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()
|
||||
}
|
||||
+147
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -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]
|
||||
}
|
||||
+433
@@ -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)
|
||||
+72
@@ -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)
|
||||
}
|
||||
}
|
||||
+46
@@ -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
|
||||
}
|
||||
}
|
||||
+290
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+96
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -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
|
||||
}
|
||||
}
|
||||
+34
@@ -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)
|
||||
}
|
||||
}
|
||||
+224
@@ -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 }
|
||||
+387
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -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)
|
||||
}
|
||||
}
|
||||
+129
@@ -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
|
||||
}
|
||||
}
|
||||
+629
@@ -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
|
||||
}
|
||||
+66
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+231
@@ -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
|
||||
}
|
||||
}
|
||||
+59
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
+123
@@ -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")
|
||||
}
|
||||
}
|
||||
+190
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
@@ -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}")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+95
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -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
|
||||
}
|
||||
}
|
||||
+29
@@ -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
|
||||
}
|
||||
+98
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
+82
@@ -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)
|
||||
}
|
||||
+39
@@ -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
|
||||
}
|
||||
+91
@@ -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()
|
||||
}
|
||||
}
|
||||
+4129
File diff suppressed because it is too large
Load Diff
+2872
File diff suppressed because it is too large
Load Diff
+4675
File diff suppressed because it is too large
Load Diff
+216
@@ -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
|
||||
}
|
||||
}
|
||||
+541
@@ -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)
|
||||
}
|
||||
+72
@@ -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
|
||||
}
|
||||
+70
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -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")
|
||||
}
|
||||
+56
@@ -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")
|
||||
|
||||
}
|
||||
}
|
||||
+25
@@ -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))
|
||||
}
|
||||
}
|
||||
+36
@@ -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)
|
||||
}
|
||||
}
|
||||
+40
@@ -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()
|
||||
}
|
||||
+26
@@ -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()
|
||||
}
|
||||
}
|
||||
+39
@@ -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
|
||||
}
|
||||
+41
@@ -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
|
||||
}
|
||||
+40
@@ -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)
|
||||
+350
@@ -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)
|
||||
}
|
||||
}
|
||||
+60
@@ -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"
|
||||
}
|
||||
}
|
||||
+707
@@ -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(' ')
|
||||
}
|
||||
}
|
||||
+72
@@ -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) }
|
||||
}
|
||||
}
|
||||
+26
@@ -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)
|
||||
}
|
||||
|
||||
+107
@@ -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)
|
||||
}
|
||||
+37
@@ -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
|
||||
}
|
||||
+98
@@ -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()
|
||||
}
|
||||
+24
@@ -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)
|
||||
}
|
||||
|
||||
+66
@@ -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 }
|
||||
}
|
||||
+96
@@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+88
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -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()
|
||||
}
|
||||
+52
@@ -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()
|
||||
}
|
||||
+56
@@ -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()
|
||||
}
|
||||
}
|
||||
+93
@@ -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()
|
||||
}
|
||||
+61
@@ -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()
|
||||
}
|
||||
+44
@@ -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()
|
||||
}
|
||||
+125
@@ -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()
|
||||
}
|
||||
+56
@@ -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()
|
||||
}
|
||||
+136
@@ -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()
|
||||
}
|
||||
+55
@@ -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()
|
||||
}
|
||||
+126
@@ -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()
|
||||
}
|
||||
+103
@@ -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
|
||||
}
|
||||
}
|
||||
+69
@@ -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)
|
||||
}
|
||||
+96
@@ -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()
|
||||
}
|
||||
+101
@@ -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()
|
||||
}
|
||||
+63
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
+73
@@ -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()}")
|
||||
+144
@@ -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)
|
||||
}
|
||||
+103
@@ -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()
|
||||
}
|
||||
+64
@@ -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()
|
||||
}
|
||||
+105
@@ -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)
|
||||
}
|
||||
}
|
||||
+50
@@ -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()
|
||||
}
|
||||
+72
@@ -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()
|
||||
}
|
||||
+56
@@ -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()
|
||||
}
|
||||
}
|
||||
+34
@@ -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) }
|
||||
}
|
||||
+51
@@ -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 } }
|
||||
+29
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+20
@@ -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
|
||||
}
|
||||
}
|
||||
+32
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+44
@@ -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?
|
||||
}
|
||||
|
||||
+32
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+32
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+39
@@ -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?
|
||||
}
|
||||
+27
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -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)
|
||||
|
||||
+30
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+58
@@ -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
|
||||
+227
@@ -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
Reference in New Issue
Block a user