[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:
Marco Pennekamp
2023-09-13 20:58:40 +02:00
committed by Space Team
parent 8b5f87f15f
commit 71017298d9
6 changed files with 181 additions and 55 deletions
@@ -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>()
@@ -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 }
}
}
}