[AA] Allow inner classes in non-static declared member scopes

- An inner class `Inner` in a class `Outer` is accessible as
  `Outer().Inner()` and should thus be part of the non-static declared
  member scope.
- Related issue containing a discussion about inner classes in use-site
  scopes: KT-62023.

^KT-61800
This commit is contained in:
Marco Pennekamp
2023-09-20 14:04:15 +02:00
committed by Space Team
parent 239cfa6d29
commit 9fa0dfe4bc
6 changed files with 71 additions and 44 deletions
@@ -13,12 +13,7 @@ import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
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.KtFunctionSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtPackageSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossiblyNamedSymbol
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.name.Name
@@ -109,6 +104,9 @@ internal open class KtFe10ScopeNonStaticMember(
constructors: Collection<ConstructorDescriptor>,
analysisContext: Fe10AnalysisContext
) : KtFe10ScopeMember(scope, constructors, analysisContext) {
override fun getClassifierSymbols(nameFilter: KtScopeNameFilter): Sequence<KtClassifierSymbol> =
super.getClassifierSymbols(nameFilter).filter { it is KtNamedClassOrObjectSymbol && it.isInner }
override fun getCallableSymbols(nameFilter: KtScopeNameFilter): Sequence<KtCallableSymbol> = withValidityAssertion {
super.getCallableSymbols(nameFilter).filter { symbol ->
when (symbol) {
@@ -105,7 +105,7 @@ internal class KtFirScopeProvider(
): FirContainingNamesAwareScope {
val combinedScope = getCombinedFirKotlinDeclaredMemberScope(classSymbol)
return when (kind) {
DeclaredMemberScopeKind.NON_STATIC -> FirNonStaticCallablesOnlyScope(combinedScope)
DeclaredMemberScopeKind.NON_STATIC -> FirNonStaticMembersScope(combinedScope)
DeclaredMemberScopeKind.STATIC -> FirStaticScope(combinedScope)
}
}
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.name.Name
/**
* A base implementation for [FirNonStaticCallablesOnlyScope] and [FirDeclaredMembersOnlyScope], which both filter callables based on some
* A base implementation for [FirNonStaticMembersScope] and [FirDeclaredMembersOnlyScope], which both filter callables based on some
* condition.
*/
internal abstract class FirCallableFilteringScope(private val baseScope: FirContainingNamesAwareScope) : FirContainingNamesAwareScope() {
@@ -1,32 +0,0 @@
/*
* 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.analysis.api.fir.scopes
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.name.Name
/**
* Excludes static callables and all classifiers.
*/
internal class FirNonStaticCallablesOnlyScope(
private val delegate: FirContainingNamesAwareScope,
) : FirCallableFilteringScope(delegate) {
override fun isTargetCallable(callable: FirCallableSymbol<*>): Boolean = !callable.fir.isStatic
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
delegate.processDeclaredConstructors(processor)
}
override fun getClassifierNames(): Set<Name> = emptySet()
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
}
}
@@ -0,0 +1,60 @@
/*
* 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.analysis.api.fir.scopes
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.name.Name
/**
* [FirNonStaticMembersScope] includes non-static callables and inner classes.
*
* Inner classes are included because they are accessible from a value of the outer class. For example:
*
* ```
* class Outer {
* inner class Inner
* }
*
* fun foo() {
* val outer = Outer()
* outer.Inner()
* }
* ```
*
* While Kotlin always expects a constructor call when accessing `outer.Inner`, it nonetheless requires inner classes to be contained in
* non-static scopes.
*/
internal class FirNonStaticMembersScope(
private val delegate: FirContainingNamesAwareScope,
) : FirCallableFilteringScope(delegate) {
override fun isTargetCallable(callable: FirCallableSymbol<*>): Boolean = !callable.fir.isStatic
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
delegate.processDeclaredConstructors(processor)
}
override fun getClassifierNames(): Set<Name> = delegate.getClassifierNames()
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
processInnerClassesByName(name, processor)
}
private fun processInnerClassesByName(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
delegate.processClassifiersByNameWithSubstitution(name) { classifier, substitutor ->
val firDeclaration = classifier.fir
if (firDeclaration is FirMemberDeclaration && firDeclaration.isInner) {
processor(classifier, substitutor)
}
}
}
}
@@ -157,11 +157,12 @@ public interface KtScopeProviderMixIn : KtAnalysisSessionMixIn {
withValidityAssertion { analysisSession.scopeProvider.getCombinedMemberScope(this) }
/**
* Returns a [KtScope] containing the *non-static* callables (functions, properties, and constructors) explicitly declared in the given
* [KtSymbolWithMembers].
* Returns a [KtScope] containing the *non-static* callables (functions, properties, and constructors) and inner classes explicitly
* declared in the given [KtSymbolWithMembers].
*
* The declared member scope does not contain classifiers (including the companion object). To retrieve the classifiers declared in this
* [KtSymbolWithMembers], please use the *static* declared member scope provided by [getStaticDeclaredMemberScope].
* The declared member scope does not contain classifiers (including the companion object) except for inner classes. To retrieve the
* classifiers declared in this [KtSymbolWithMembers], please use the *static* declared member scope provided by
* [getStaticDeclaredMemberScope].
*
* @see getStaticDeclaredMemberScope
*/