[AA] Provide separate non-static and static declared member scopes
- Member scopes already don't contain static callables, only their static member scope counterparts. However, declared member scopes contained both non-static and static callables, which was confusing to users. See for example KT-61255. - Now declared member scopes only contain non-static callables and static declared member scopes only contain static callables. - In `KtFirScopeProvider`, the new implementation is different for Kotlin and Java classes, because the standard declared member scope doesn't work for Java. Instead, we have to get the Java *enhancement* scopes from `JavaScopeProvider`. Unfortunately, `JavaScopeProvider` doesn't have a direct enhancement declared member scope. This results in a somewhat complex scope structure with the declared members filter scope around the use-site/static Java enhancement scope, but since the declared members filtering scope properly reduces the set of callable names and scopes in general are cached, this shouldn't be an issue. - `getCombinedDeclaredMemberScope` is introduced as a separate public function because for Kotlin scopes, we don't actually have to create a combined scope, as the non-static and static scopes are just filters around a combined declared member scope provided by the compiler. It's also important to have a convenient function to get the combined declared member scope, because some usages explicitly want access to all declared members (such as symbol light classes). - This commit also fixes KT-61901, because `getFirJavaDeclaredMemberScope` now provides a proper static scope for Java classes, which will be accessible via the combined declared member scope as well. ^KT-61800 fixed ^KT-61901 fixed ^KT-61255 fixed
This commit is contained in:
committed by
Space Team
parent
8b5f87f15f
commit
71017298d9
+24
-6
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.analysis.api.descriptors.scopes.KtFe10FileScope
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.scopes.KtFe10PackageScope
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.scopes.KtFe10ScopeLexical
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.scopes.KtFe10ScopeMember
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.scopes.KtFe10ScopeNonStaticMember
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.KtFe10FileSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.KtFe10PackageSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.base.KtFe10Symbol
|
||||
@@ -63,10 +64,33 @@ internal class KtFe10ScopeProvider(
|
||||
return KtFe10ScopeMember(descriptor.unsubstitutedMemberScope, descriptor.constructors, analysisContext)
|
||||
}
|
||||
|
||||
override fun getStaticMemberScope(symbol: KtSymbolWithMembers): KtScope {
|
||||
val descriptor = getDescriptor<ClassDescriptor>(symbol) ?: return getEmptyScope()
|
||||
return KtFe10ScopeMember(descriptor.staticScope, emptyList(), analysisContext)
|
||||
}
|
||||
|
||||
override fun getDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtScope {
|
||||
val descriptor = getDescriptor<ClassDescriptor>(classSymbol)
|
||||
?: return getEmptyScope()
|
||||
|
||||
return KtFe10ScopeNonStaticMember(DeclaredMemberScope(descriptor), descriptor.constructors, analysisContext)
|
||||
}
|
||||
|
||||
override fun getStaticDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtScope {
|
||||
val descriptor = getDescriptor<ClassDescriptor>(classSymbol)
|
||||
?: return getEmptyScope()
|
||||
|
||||
return KtFe10ScopeMember(
|
||||
DeclaredMemberScope(descriptor.staticScope, descriptor, forDelegatedMembersOnly = false),
|
||||
emptyList(),
|
||||
analysisContext,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getCombinedDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtScope {
|
||||
val descriptor = getDescriptor<ClassDescriptor>(classSymbol)
|
||||
?: return getEmptyScope()
|
||||
|
||||
return KtFe10ScopeMember(DeclaredMemberScope(descriptor), descriptor.constructors, analysisContext)
|
||||
}
|
||||
|
||||
@@ -157,12 +181,6 @@ internal class KtFe10ScopeProvider(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun getStaticMemberScope(symbol: KtSymbolWithMembers): KtScope {
|
||||
val descriptor = getDescriptor<ClassDescriptor>(symbol) ?: return getEmptyScope()
|
||||
return KtFe10ScopeMember(descriptor.staticScope, emptyList(), analysisContext)
|
||||
}
|
||||
|
||||
override fun getEmptyScope(): KtScope {
|
||||
return KtEmptyScope(token)
|
||||
}
|
||||
|
||||
+18
@@ -16,7 +16,9 @@ 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.KtFunctionSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtPackageSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossiblyNamedSymbol
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -102,6 +104,22 @@ internal open class KtFe10ScopeMember(
|
||||
}
|
||||
}
|
||||
|
||||
internal open class KtFe10ScopeNonStaticMember(
|
||||
scope: MemberScope,
|
||||
constructors: Collection<ConstructorDescriptor>,
|
||||
analysisContext: Fe10AnalysisContext
|
||||
) : KtFe10ScopeMember(scope, constructors, analysisContext) {
|
||||
override fun getCallableSymbols(nameFilter: KtScopeNameFilter): Sequence<KtCallableSymbol> = withValidityAssertion {
|
||||
super.getCallableSymbols(nameFilter).filter { symbol ->
|
||||
when (symbol) {
|
||||
is KtFunctionSymbol -> !symbol.isStatic
|
||||
is KtPropertySymbol -> !symbol.isStatic
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class KtFe10ScopeImporting(
|
||||
override val scope: ImportingScope,
|
||||
override val analysisContext: Fe10AnalysisContext
|
||||
|
||||
+74
-39
@@ -24,10 +24,8 @@ import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
|
||||
import org.jetbrains.kotlin.analysis.utils.errors.unexpectedElementError
|
||||
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.declarations.utils.classId
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.delegateFields
|
||||
import org.jetbrains.kotlin.fir.java.JavaScopeProvider
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
|
||||
@@ -83,23 +81,82 @@ internal class KtFirScopeProvider(
|
||||
return KtFirDelegatingNamesAwareScope(firScope, builder)
|
||||
}
|
||||
|
||||
override fun getDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtScope {
|
||||
val useSiteSession = analysisSession.useSiteSession
|
||||
if (classSymbol is KtFirScriptSymbol) {
|
||||
return KtFirDelegatingNamesAwareScope(
|
||||
FirScriptDeclarationsScope(useSiteSession, classSymbol.firSymbol.fir),
|
||||
builder,
|
||||
)
|
||||
override fun getDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtScope =
|
||||
getDeclaredMemberScope(classSymbol, DeclaredMemberScopeKind.NON_STATIC)
|
||||
|
||||
override fun getStaticDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtScope =
|
||||
getDeclaredMemberScope(classSymbol, DeclaredMemberScopeKind.STATIC)
|
||||
|
||||
private enum class DeclaredMemberScopeKind { NON_STATIC, STATIC }
|
||||
|
||||
private fun getDeclaredMemberScope(classSymbol: KtSymbolWithMembers, kind: DeclaredMemberScopeKind): KtScope {
|
||||
val firDeclaration = classSymbol.firSymbol.fir
|
||||
val firScope = when (firDeclaration) {
|
||||
is FirJavaClass -> getFirJavaDeclaredMemberScope(firDeclaration, kind) ?: return getEmptyScope()
|
||||
else -> getFirKotlinDeclaredMemberScope(classSymbol, kind)
|
||||
}
|
||||
|
||||
val fir = classSymbol.getFirForScope()
|
||||
val firScope = when (val regularClass = classSymbol.firSymbol.fir) {
|
||||
is FirJavaClass -> buildJavaEnhancementDeclaredMemberScope(useSiteSession, regularClass.symbol, getScopeSession())
|
||||
else -> useSiteSession.declaredMemberScope(fir, memberRequiredPhase = null)
|
||||
}
|
||||
return KtFirDelegatingNamesAwareScope(firScope, builder)
|
||||
}
|
||||
|
||||
private fun getFirKotlinDeclaredMemberScope(
|
||||
classSymbol: KtSymbolWithMembers,
|
||||
kind: DeclaredMemberScopeKind,
|
||||
): FirContainingNamesAwareScope {
|
||||
val combinedScope = getCombinedFirKotlinDeclaredMemberScope(classSymbol)
|
||||
return when (kind) {
|
||||
DeclaredMemberScopeKind.NON_STATIC -> FirNonStaticCallablesScope(combinedScope)
|
||||
DeclaredMemberScopeKind.STATIC -> FirStaticScope(combinedScope)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFirJavaDeclaredMemberScope(firJavaClass: FirJavaClass, kind: DeclaredMemberScopeKind): FirContainingNamesAwareScope? {
|
||||
val useSiteSession = analysisSession.useSiteSession
|
||||
val scopeSession = getScopeSession()
|
||||
|
||||
val firScope = when (kind) {
|
||||
DeclaredMemberScopeKind.NON_STATIC -> JavaScopeProvider.getUseSiteMemberScope(
|
||||
firJavaClass,
|
||||
useSiteSession,
|
||||
scopeSession,
|
||||
memberRequiredPhase = FirResolvePhase.TYPES,
|
||||
)
|
||||
DeclaredMemberScopeKind.STATIC -> JavaScopeProvider.getStaticScope(firJavaClass, useSiteSession, scopeSession) ?: return null
|
||||
}
|
||||
|
||||
val cacheKey = when (kind) {
|
||||
DeclaredMemberScopeKind.NON_STATIC -> JAVA_ENHANCEMENT_FOR_DECLARED_MEMBERS
|
||||
DeclaredMemberScopeKind.STATIC -> JAVA_ENHANCEMENT_FOR_STATIC_DECLARED_MEMBERS
|
||||
}
|
||||
|
||||
return scopeSession.getOrBuild(firJavaClass.symbol, cacheKey) {
|
||||
JavaClassDeclaredMembersEnhancementScope(analysisSession.useSiteSession, firJavaClass, firScope)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCombinedDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtScope {
|
||||
val firDeclaration = classSymbol.firSymbol.fir
|
||||
if (firDeclaration is FirJavaClass) {
|
||||
// Java enhancement scopes as provided by `JavaScopeProvider` are either use-site or static scopes, so we need to compose them
|
||||
// to get the combined scope. A base declared member scope with Java enhancement doesn't exist, unfortunately.
|
||||
return KtCompositeScope.create(listOf(getDeclaredMemberScope(classSymbol), getStaticDeclaredMemberScope(classSymbol)), token)
|
||||
}
|
||||
|
||||
return KtFirDelegatingNamesAwareScope(getCombinedFirKotlinDeclaredMemberScope(classSymbol), builder)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a declared member scope which contains both static and non-static callables, as well as all classifiers. Java classes need to
|
||||
* be handled specially, because [declaredMemberScope] doesn't handle Java enhancement properly.
|
||||
*/
|
||||
private fun getCombinedFirKotlinDeclaredMemberScope(symbolWithMembers: KtSymbolWithMembers): FirContainingNamesAwareScope {
|
||||
val useSiteSession = analysisSession.useSiteSession
|
||||
return when (symbolWithMembers) {
|
||||
is KtFirScriptSymbol -> FirScriptDeclarationsScope(useSiteSession, symbolWithMembers.firSymbol.fir)
|
||||
else -> useSiteSession.declaredMemberScope(symbolWithMembers.getFirForScope(), memberRequiredPhase = null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDelegatedMemberScope(classSymbol: KtSymbolWithMembers): KtScope {
|
||||
val declaredScope = (getDeclaredMemberScope(classSymbol) as? KtFirDelegatingNamesAwareScope)?.firScope ?: return getEmptyScope()
|
||||
|
||||
@@ -276,30 +333,6 @@ internal class KtFirScopeProvider(
|
||||
val syntheticPropertiesScope = getFirSyntheticPropertiesScope(coneType, this) ?: return this
|
||||
return FirTypeScopeWithSyntheticProperties(typeScope = this, syntheticPropertiesScope)
|
||||
}
|
||||
|
||||
private fun buildJavaEnhancementDeclaredMemberScope(
|
||||
useSiteSession: FirSession,
|
||||
symbol: FirRegularClassSymbol,
|
||||
scopeSession: ScopeSession,
|
||||
): JavaClassDeclaredMembersEnhancementScope {
|
||||
return scopeSession.getOrBuild(symbol, JAVA_ENHANCEMENT_FOR_DECLARED_MEMBER) {
|
||||
val firJavaClass = symbol.fir
|
||||
require(firJavaClass is FirJavaClass) {
|
||||
"${firJavaClass.classId} is expected to be FirJavaClass, but ${firJavaClass::class} found"
|
||||
}
|
||||
|
||||
JavaClassDeclaredMembersEnhancementScope(
|
||||
useSiteSession,
|
||||
firJavaClass,
|
||||
JavaScopeProvider.getUseSiteMemberScope(
|
||||
firJavaClass,
|
||||
useSiteSession,
|
||||
scopeSession,
|
||||
memberRequiredPhase = FirResolvePhase.TYPES,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class FirTypeScopeWithSyntheticProperties(
|
||||
@@ -315,4 +348,6 @@ private class FirTypeScopeWithSyntheticProperties(
|
||||
}
|
||||
}
|
||||
|
||||
private val JAVA_ENHANCEMENT_FOR_DECLARED_MEMBER = scopeSessionKey<FirRegularClassSymbol, JavaClassDeclaredMembersEnhancementScope>()
|
||||
private val JAVA_ENHANCEMENT_FOR_DECLARED_MEMBERS = scopeSessionKey<FirRegularClassSymbol, FirContainingNamesAwareScope>()
|
||||
|
||||
private val JAVA_ENHANCEMENT_FOR_STATIC_DECLARED_MEMBERS = scopeSessionKey<FirRegularClassSymbol, FirContainingNamesAwareScope>()
|
||||
|
||||
+2
-10
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.name.SpecialNames
|
||||
internal class JavaClassDeclaredMembersEnhancementScope(
|
||||
private val useSiteSession: FirSession,
|
||||
private val owner: FirJavaClass,
|
||||
private val useSiteMemberEnhancementScope: FirTypeScope
|
||||
private val useSiteMemberEnhancementScope: FirContainingNamesAwareScope
|
||||
) : FirContainingNamesAwareScope() {
|
||||
private fun FirCallableDeclaration.isDeclared(): Boolean {
|
||||
return (this.dispatchReceiverType as? ConeLookupTagBasedType)?.lookupTag == owner.symbol.toLookupTag()
|
||||
@@ -80,12 +80,4 @@ internal class JavaClassDeclaredMembersEnhancementScope(
|
||||
override fun toString(): String {
|
||||
return "Java enhancement declared member scope for ${owner.classId}"
|
||||
}
|
||||
|
||||
private fun FirCallableDeclaration.overriddenMembers(): List<FirCallableDeclaration> {
|
||||
return when (val symbol = this.symbol) {
|
||||
is FirNamedFunctionSymbol -> useSiteMemberEnhancementScope.getDirectOverriddenMembers(symbol)
|
||||
is FirPropertySymbol -> useSiteMemberEnhancementScope.getDirectOverriddenProperties(symbol)
|
||||
else -> emptyList()
|
||||
}.map { it.fir }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+29
@@ -24,6 +24,10 @@ public abstract class KtScopeProvider : KtAnalysisSessionComponent() {
|
||||
|
||||
public abstract fun getDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtScope
|
||||
|
||||
public abstract fun getStaticDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtScope
|
||||
|
||||
public abstract fun getCombinedDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtScope
|
||||
|
||||
public abstract fun getDelegatedMemberScope(classSymbol: KtSymbolWithMembers): KtScope
|
||||
|
||||
public abstract fun getStaticMemberScope(symbol: KtSymbolWithMembers): KtScope
|
||||
@@ -56,9 +60,34 @@ public interface KtScopeProviderMixIn : KtAnalysisSessionMixIn {
|
||||
public fun KtSymbolWithMembers.getMemberScope(): KtScope =
|
||||
withValidityAssertion { analysisSession.scopeProvider.getMemberScope(this) }
|
||||
|
||||
/**
|
||||
* Returns a [KtScope] containing the *non-static* callables and all classifiers explicitly declared in the given [KtSymbolWithMembers].
|
||||
*
|
||||
* @see getStaticDeclaredMemberScope
|
||||
*/
|
||||
public fun KtSymbolWithMembers.getDeclaredMemberScope(): KtScope =
|
||||
withValidityAssertion { analysisSession.scopeProvider.getDeclaredMemberScope(this) }
|
||||
|
||||
/**
|
||||
* Returns a [KtScope] containing the *static* members explicitly declared in the given [KtSymbolWithMembers].
|
||||
*
|
||||
* It is worth noting that, while Java classes may contain declarations of static callables freely, in Kotlin only enum classes define
|
||||
* static callables. Hence, for non-enum Kotlin classes, it is not expected that the static declared member scope will contain any
|
||||
* callables.
|
||||
*
|
||||
* @see getDeclaredMemberScope
|
||||
*/
|
||||
public fun KtSymbolWithMembers.getStaticDeclaredMemberScope(): KtScope =
|
||||
withValidityAssertion { analysisSession.scopeProvider.getStaticDeclaredMemberScope(this) }
|
||||
|
||||
/**
|
||||
* Returns a [KtScope] containing *all* members explicitly declared in the given [KtSymbolWithMembers].
|
||||
*
|
||||
* In contrast to [getDeclaredMemberScope] and [getStaticDeclaredMemberScope], this scope contains both static and non-static members.
|
||||
*/
|
||||
public fun KtSymbolWithMembers.getCombinedDeclaredMemberScope(): KtScope =
|
||||
withValidityAssertion { analysisSession.scopeProvider.getCombinedDeclaredMemberScope(this) }
|
||||
|
||||
public fun KtSymbolWithMembers.getDelegatedMemberScope(): KtScope =
|
||||
withValidityAssertion { analysisSession.scopeProvider.getDelegatedMemberScope(this) }
|
||||
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.declarations.utils.isStatic
|
||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.scopes.FirDelegatingContainingNamesAwareScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
/**
|
||||
* A counterpart to [FirStaticScope] that contains only the *non-static* callables and all classifiers of the [delegate] scope.
|
||||
*/
|
||||
class FirNonStaticCallablesScope(private val delegate: FirContainingNamesAwareScope) : FirDelegatingContainingNamesAwareScope(delegate) {
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
delegate.processFunctionsByName(name) {
|
||||
if (!it.fir.isStatic) {
|
||||
processor(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
delegate.processPropertiesByName(name) {
|
||||
if (!it.fir.isStatic) {
|
||||
processor(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user