All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.fir.resolve.providers.impl.FirDependenciesSymbolProviderImpl.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * 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.fir.resolve.providers.impl

import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.ThreadSafeMutableState
import org.jetbrains.kotlin.fir.caches.createCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.caches.getValue
import org.jetbrains.kotlin.fir.nullableModuleData
import org.jetbrains.kotlin.fir.resolve.providers.*
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name

@ThreadSafeMutableState
open class FirDependenciesSymbolProviderImpl(session: FirSession) : FirDependenciesSymbolProvider(session) {
    private val classCache = session.firCachesFactory.createCache(::computeClass)
    private val topLevelCallableCache = session.firCachesFactory.createCache(::computeTopLevelCallables)
    private val topLevelFunctionCache = session.firCachesFactory.createCache(::computeTopLevelFunctions)
    private val topLevelPropertyCache = session.firCachesFactory.createCache(::computeTopLevelProperties)
    private val packageCache = session.firCachesFactory.createCache(::computePackage)


    protected open val dependencyProviders by lazy {
        val moduleData = session.nullableModuleData ?: return@lazy emptyList()
        (moduleData.dependencies + moduleData.friendDependencies + moduleData.dependsOnDependencies)
            .mapNotNull { session.sessionProvider?.getSession(it) }
            .sortedBy { it.kind }
            .map {
                if (it.kind == FirSession.Kind.Source) {
                    it.symbolProvider.loadTransitiveSourceProvides()
                } else {
                    listOf(it.symbolProvider)
                }
            }
            .flatten()
    }

    private fun FirSymbolProvider.loadTransitiveSourceProvides(): List {
        val result = mutableListOf()
        val visited = hashSetOf()

        fun loadTransitiveSourceProvides(provider: FirSymbolProvider) {
            if (!visited.add(provider)) {
                return
            }

            when {
                provider is FirDependenciesSymbolProviderImpl -> {
                    for (p in provider.dependencyProviders) {
                        loadTransitiveSourceProvides(p)
                    }
                }
                provider is FirCompositeSymbolProvider -> {
                    for (p in provider.providers) {
                        loadTransitiveSourceProvides(p)
                    }
                }
                provider.session.kind == FirSession.Kind.Source -> {
                    result.add(provider)
                }
            }
        }

        loadTransitiveSourceProvides(this)

        return result
    }

    @OptIn(FirSymbolProviderInternals::class, ExperimentalStdlibApi::class)
    private fun computeTopLevelCallables(callableId: CallableId): List> = buildList {
        dependencyProviders.forEach { it.getTopLevelCallableSymbolsTo(this, callableId.packageName, callableId.callableName) }
    }

    @OptIn(FirSymbolProviderInternals::class, ExperimentalStdlibApi::class)
    private fun computeTopLevelFunctions(callableId: CallableId): List = buildList {
        dependencyProviders.forEach { it.getTopLevelFunctionSymbolsTo(this, callableId.packageName, callableId.callableName) }
    }

    @OptIn(FirSymbolProviderInternals::class, ExperimentalStdlibApi::class)
    private fun computeTopLevelProperties(callableId: CallableId): List = buildList {
        dependencyProviders.forEach { it.getTopLevelPropertySymbolsTo(this, callableId.packageName, callableId.callableName) }
    }

    private fun computePackage(it: FqName): FqName? =
        dependencyProviders.firstNotNullOfOrNull { provider -> provider.getPackage(it) }

    private fun computeClass(classId: ClassId): FirClassLikeSymbol<*>? =
        dependencyProviders.firstNotNullOfOrNull { provider -> provider.getClassLikeSymbolByClassId(classId) }


    @FirSymbolProviderInternals
    override fun getTopLevelFunctionSymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) {
        destination += topLevelFunctionCache.getValue(CallableId(packageFqName, name))
    }

    @FirSymbolProviderInternals
    override fun getTopLevelPropertySymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) {
        destination += topLevelPropertyCache.getValue(CallableId(packageFqName, name))
    }

    @FirSymbolProviderInternals
    override fun getTopLevelCallableSymbolsTo(destination: MutableList>, packageFqName: FqName, name: Name) {
        destination += getTopLevelCallableSymbols(packageFqName, name)
    }

    override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List> {
        return topLevelCallableCache.getValue(CallableId(packageFqName, name))
    }

    override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? {
        return classCache.getValue(classId)
    }

    override fun getPackage(fqName: FqName): FqName? {
        return packageCache.getValue(fqName)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy