org.jetbrains.kotlin.fir.scopes.impl.FirActualizingScope.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* Copyright 2010-2024 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.scopes.impl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.getSingleMatchedExpectForActualOrNull
import org.jetbrains.kotlin.fir.declarations.utils.isActual
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.DelicateScopeAPI
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.name.Name
/**
* A scope that filters out `expect` callables that have matched `actual` callables.
*/
class FirActualizingScope(private val delegate: FirScope) : FirScope() {
init {
// Cases with `FirTypeScope` should be handled by `MemberScopeTowerLevel`
require(delegate !is FirTypeScope)
}
override fun mayContainName(name: Name): Boolean = delegate.mayContainName(name)
override val scopeOwnerLookupNames: List = delegate.scopeOwnerLookupNames
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
// No filtering is needed for classifiers because the first classifier always wins, and `actual` classifier is always first in platform source-set
delegate.processClassifiersByNameWithSubstitution(name, processor)
}
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
delegate.processDeclaredConstructors(processor)
}
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
processCallableSymbolsByName(name, FirScope::processFunctionsByName, processor)
}
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
processCallableSymbolsByName(name, FirScope::processPropertiesByName, processor)
}
private fun > processCallableSymbolsByName(
name: Name,
processingFactory: FirScope.(Name, (S) -> Unit) -> Unit,
processor: (S) -> Unit,
) {
val filteredSymbols = mutableSetOf()
// All matched `expect` callables should be preserved to make it possible to filter them out later if corresponding actuals are found
val ignoredExpectSymbols = mutableSetOf>()
delegate.processingFactory(name) { symbol ->
if (symbol.isActual) {
val matchedExpectSymbol = symbol.getSingleMatchedExpectForActualOrNull()
if (matchedExpectSymbol != null) {
filteredSymbols.remove(matchedExpectSymbol) // Filter out matched expects candidates
ignoredExpectSymbols.add(matchedExpectSymbol)
}
} else if (symbol.isExpect && symbol in ignoredExpectSymbols) {
// Skip the found `expect` because there is already a matched actual
return@processingFactory
}
filteredSymbols.add(symbol)
}
for (symbol in filteredSymbols) {
processor(symbol)
}
}
@DelicateScopeAPI
override fun withReplacedSessionOrNull(newSession: FirSession, newScopeSession: ScopeSession): FirActualizingScope? {
return delegate.withReplacedSessionOrNull(newSession, newScopeSession)?.let { FirActualizingScope(it) }
}
}