FIR IDE/LC: introduce/use delegated member scope

This commit is contained in:
Jinseong Jeon
2021-10-20 16:20:14 -07:00
committed by Ilya Kirillov
parent 700f8ac287
commit 3f2c86afb8
18 changed files with 271 additions and 20 deletions
@@ -66,11 +66,24 @@ internal class KtFe10ScopeProvider(override val analysisSession: KtFe10AnalysisS
override val owner get() = classSymbol
}
// TODO: need to return declared members only
return object : KtFe10ScopeMember(descriptor.unsubstitutedMemberScope, analysisSession), KtDeclaredMemberScope {
override val owner get() = classSymbol
}
}
override fun getDelegatedMemberScope(classSymbol: KtSymbolWithMembers): KtDelegatedMemberScope = withValidityAssertion {
val descriptor = getDescriptor<ClassDescriptor>(classSymbol)
?: return object : KtFe10EmptyScope(token), KtDelegatedMemberScope {
override val owner get() = classSymbol
}
// TODO: need to return delegated members only
return object : KtFe10ScopeMember(descriptor.unsubstitutedMemberScope, analysisSession), KtDelegatedMemberScope {
override val owner get() = classSymbol
}
}
override fun getStaticMemberScope(symbol: KtSymbolWithMembers): KtScope = withValidityAssertion {
val descriptor = getDescriptor<ClassDescriptor>(symbol) ?: return KtFe10EmptyScope(token)
return KtFe10ScopeMember(descriptor.staticScope, analysisSession)
@@ -147,4 +160,4 @@ internal class KtFe10ScopeProvider(override val analysisSession: KtFe10AnalysisS
return result
}
}
}
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.fir.declarations.utils.delegateFields
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import java.util.*
@@ -54,6 +55,7 @@ internal class KtFirScopeProvider(
private val memberScopeCache = IdentityHashMap<KtSymbolWithMembers, KtMemberScope>()
private val declaredMemberScopeCache = IdentityHashMap<KtSymbolWithMembers, KtDeclaredMemberScope>()
private val delegatedMemberScopeCache = IdentityHashMap<KtSymbolWithMembers, KtDelegatedMemberScope>()
private val fileScopeCache = IdentityHashMap<KtFileSymbol, KtDeclarationScope<KtSymbolWithDeclarations>>()
private val packageMemberScopeCache = IdentityHashMap<KtPackageSymbol, KtPackageScope>()
@@ -101,6 +103,27 @@ internal class KtFirScopeProvider(
}
}
override fun getDelegatedMemberScope(classSymbol: KtSymbolWithMembers): KtDelegatedMemberScope = withValidityAssertion {
val declaredScope = (getDeclaredMemberScope(classSymbol) as? KtFirDeclaredMemberScope)?.firScope
?: return delegatedMemberScopeCache.getOrPut(classSymbol) { KtFirEmptyMemberScope(classSymbol) }
delegatedMemberScopeCache.getOrPut(classSymbol) {
val firScope = classSymbol.withFirForScope { fir ->
val delegateFields = fir.delegateFields
if (delegateFields.isNotEmpty()) {
FirDelegatedMemberScope(
analysisSession.rootModuleSession,
ScopeSession(),
fir,
declaredScope,
delegateFields
)
} else null
} ?: return@getOrPut KtFirEmptyMemberScope(classSymbol)
KtFirDelegatedMemberScope(classSymbol, firScope, token, builder)
}
}
override fun getFileScope(fileSymbol: KtFileSymbol): KtDeclarationScope<KtSymbolWithDeclarations> = withValidityAssertion {
fileScopeCache.getOrPut(fileSymbol) {
check(fileSymbol is KtFirFileSymbol) { "KtFirScopeProvider can only work with KtFirFileSymbol, but ${fileSymbol::class} was provided" }
@@ -0,0 +1,30 @@
/*
* 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.analysis.api.fir.scopes
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.scopes.KtDelegatedMemberScope
import org.jetbrains.kotlin.analysis.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
internal class KtFirDelegatedMemberScope(
override val owner: KtSymbolWithMembers,
override val firScope: FirContainingNamesAwareScope,
token: ValidityToken,
builder: KtSymbolByFirBuilder
) : KtFirDelegatingScope<FirContainingNamesAwareScope>(builder, token),
KtDelegatedMemberScope,
ValidityTokenOwner {
override fun getCallableSymbols(nameFilter: KtScopeNameFilter): Sequence<KtCallableSymbol> {
return super.getCallableSymbols(nameFilter).filter { it.origin == KtSymbolOrigin.DELEGATED }
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.api.fir.scopes
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.scopes.KtDeclaredMemberScope
import org.jetbrains.kotlin.analysis.api.scopes.KtDelegatedMemberScope
import org.jetbrains.kotlin.analysis.api.scopes.KtMemberScope
import org.jetbrains.kotlin.analysis.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
@@ -16,7 +17,9 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtConstructorSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
import org.jetbrains.kotlin.name.Name
internal class KtFirEmptyMemberScope(override val owner: KtSymbolWithMembers) : KtMemberScope, KtDeclaredMemberScope, ValidityTokenOwner {
internal class KtFirEmptyMemberScope(
override val owner: KtSymbolWithMembers
) : KtMemberScope, KtDeclaredMemberScope, KtDelegatedMemberScope, ValidityTokenOwner {
override fun getPossibleCallableNames(): Set<Name> = emptySet()
override fun getPossibleClassifierNames(): Set<Name> = emptySet()
@@ -34,4 +37,4 @@ internal class KtFirEmptyMemberScope(override val owner: KtSymbolWithMembers) :
override val token: ValidityToken
get() = owner.token
}
}
@@ -0,0 +1,11 @@
/*
* 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.analysis.api.fir.scopes
import org.jetbrains.kotlin.analysis.api.fir.FirFrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.base.test.scopes.AbstractDelegateMemberScopeTest
abstract class AbstractFirDelegateMemberScopeTest : AbstractDelegateMemberScopeTest(FirFrontendApiTestConfiguratorService)
@@ -0,0 +1,38 @@
/*
* 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.analysis.api.fir.scopes;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("analysis/analysis-api/testData/scopes/delegatedMemberScope")
@TestDataPath("$PROJECT_ROOT")
public class FirDelegateMemberScopeTestGenerated extends AbstractFirDelegateMemberScopeTest {
@Test
public void testAllFilesPresentInDelegatedMemberScope() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/scopes/delegatedMemberScope"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("analysis/analysis-api/testData/scopes/delegatedMemberScope/simple.kt");
}
@Test
@TestMetadata("withOverridden.kt")
public void testWithOverridden() throws Exception {
runTest("analysis/analysis-api/testData/scopes/delegatedMemberScope/withOverridden.kt");
}
}
@@ -0,0 +1,28 @@
/*
* 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.analysis.api.impl.base.test.scopes
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.base.test.SymbolByFqName
import org.jetbrains.kotlin.analysis.api.impl.base.test.symbols.AbstractSymbolByFqNameTest
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.test.services.TestServices
abstract class AbstractDelegateMemberScopeTest(
configurator: FrontendApiTestConfiguratorService
) : AbstractSymbolByFqNameTest(configurator) {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): List<KtSymbol> {
val symbolData = SymbolByFqName.getSymbolDataFromFile(testDataPath)
val symbols = with(symbolData) { toSymbols() }
val classSymbol = symbols.singleOrNull() as? KtClassOrObjectSymbol
?: error("Should be a single class symbol, but $symbols found")
return classSymbol.getDelegatedMemberScope().getCallableSymbols().toList()
}
}
@@ -14,7 +14,10 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.services.TestServices
abstract class AbstractMemberScopeByFqNameTest(configurator: FrontendApiTestConfiguratorService) : AbstractSymbolByFqNameTest(configurator) {
abstract class AbstractMemberScopeByFqNameTest(
configurator: FrontendApiTestConfiguratorService
) : AbstractSymbolByFqNameTest(configurator) {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): List<KtSymbol> {
val symbolData = SymbolByFqName.getSymbolDataFromFile(testDataPath)
val symbols = with(symbolData) { toSymbols() }
@@ -22,4 +25,4 @@ abstract class AbstractMemberScopeByFqNameTest(configurator: FrontendApiTestConf
?: error("Should be a single class symbol, but $symbols found")
return classSymbol.getMemberScope().getAllSymbols().toList()
}
}
}
@@ -19,11 +19,17 @@ import org.jetbrains.kotlin.psi.KtFile
public abstract class KtScopeProvider : KtAnalysisSessionComponent() {
public abstract fun getMemberScope(classSymbol: KtSymbolWithMembers): KtMemberScope
public abstract fun getStaticMemberScope(symbol: KtSymbolWithMembers): KtScope
public abstract fun getDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtDeclaredMemberScope
public abstract fun getDelegatedMemberScope(classSymbol: KtSymbolWithMembers): KtDelegatedMemberScope
public abstract fun getStaticMemberScope(symbol: KtSymbolWithMembers): KtScope
public abstract fun getFileScope(fileSymbol: KtFileSymbol): KtDeclarationScope<KtSymbolWithDeclarations>
public abstract fun getPackageScope(packageSymbol: KtPackageSymbol): KtPackageScope
public abstract fun getCompositeScope(subScopes: List<KtScope>): KtCompositeScope
public abstract fun getTypeScope(type: KtType): KtScope?
@@ -41,6 +47,9 @@ public interface KtScopeProviderMixIn : KtAnalysisSessionMixIn {
public fun KtSymbolWithMembers.getDeclaredMemberScope(): KtDeclaredMemberScope =
analysisSession.scopeProvider.getDeclaredMemberScope(this)
public fun KtSymbolWithMembers.getDelegatedMemberScope(): KtDelegatedMemberScope =
analysisSession.scopeProvider.getDelegatedMemberScope(this)
public fun KtSymbolWithMembers.getStaticMemberScope(): KtScope =
analysisSession.scopeProvider.getStaticMemberScope(this)
@@ -86,6 +86,10 @@ public interface KtDeclaredMemberScope : KtDeclarationScope<KtSymbolWithMembers>
override val owner: KtSymbolWithMembers
}
public interface KtDelegatedMemberScope : KtDeclarationScope<KtSymbolWithMembers> {
override val owner: KtSymbolWithMembers
}
public interface KtDeclarationScope<out T : KtSymbolWithDeclarations> : KtScope {
public val owner: T
}
@@ -100,4 +104,4 @@ public interface KtPackageScope : KtScope {
}
override fun getConstructors(): Sequence<KtConstructorSymbol> = withValidityAssertion { emptySequence() }
}
}
@@ -0,0 +1,12 @@
// DO_NOT_CHECK_SYMBOL_RESTORE
interface I {
fun foo()
}
class A(
private val p: I
) : I by p
// class: A
@@ -0,0 +1,24 @@
KtFunctionSymbol:
annotatedType: [] kotlin/Unit
annotationClassIds: []
annotations: []
callableIdIfNonLocal: /I.foo
dispatchType: A
hasStableParameterNames: true
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: OPEN
name: foo
origin: DELEGATED
receiverType: null
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: []
visibility: Public
deprecationStatus: null
@@ -0,0 +1,27 @@
// DO_NOT_CHECK_SYMBOL_RESTORE
interface I1 {
fun foo()
}
class I1Impl: I1 {
override fun foo() {}
}
interface I2 {
fun bar()
fun baz()
}
class I2Impl: I2 {
override fun bar() {}
override fun baz() {}
}
open class A : I1 by I1Impl()
class B : I2 by I2Impl(), A() {
override fun baz() {}
}
// class: B
@@ -0,0 +1,24 @@
KtFunctionSymbol:
annotatedType: [] kotlin/Unit
annotationClassIds: []
annotations: []
callableIdIfNonLocal: /I2.bar
dispatchType: B
hasStableParameterNames: true
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: OPEN
name: bar
origin: DELEGATED
receiverType: null
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: []
visibility: Public
deprecationStatus: null
@@ -204,11 +204,8 @@ internal class FirLightClassForSymbol(
}
analyzeWithSymbolAsContext(classOrObjectSymbol) {
// NB: delegated members are not available at _declared_ member scope.
// Thus, use member scope to get "all" callable members, including members from (interface) supertypes,
// and accept fake overrides with delegated origin to create delegate methods.
classOrObjectSymbol.getMemberScope().getCallableSymbols().forEach { functionSymbol ->
if (functionSymbol is KtFunctionSymbol && functionSymbol.origin == KtSymbolOrigin.DELEGATED) {
classOrObjectSymbol.getDelegatedMemberScope().getCallableSymbols().forEach { functionSymbol ->
if (functionSymbol is KtFunctionSymbol) {
createDelegateMethod(functionSymbol)
}
}
@@ -9,10 +9,9 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirField
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.delegateFields
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.isSynthetic
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
@@ -40,17 +39,15 @@ class FirKotlinScopeProvider(
return scopeSession.getOrBuild(klass.symbol, USE_SITE) {
val declaredScope = useSiteSession.declaredMemberScope(klass)
val delegateFields = klass.declarations.filterIsInstance<FirField>().filter { it.isSynthetic }
val decoratedDeclaredMemberScope =
declaredMemberScopeDecorator(klass, declaredScope, useSiteSession, scopeSession).let {
val delegateFields = klass.delegateFields
if (delegateFields.isEmpty())
it
else
FirDelegatedMemberScope(useSiteSession, scopeSession, klass, it, delegateFields)
}
val scopes = lookupSuperTypes(
klass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession, substituteTypes = true
).mapNotNull { useSiteSuperType ->
@@ -34,6 +34,9 @@ val FirClass.superConeTypes: List<ConeClassLikeType> get() = superTypeRefs.mapNo
val FirClass.anonymousInitializers: List<FirAnonymousInitializer>
get() = declarations.filterIsInstance<FirAnonymousInitializer>()
val FirClass.delegateFields: List<FirField>
get() = declarations.filterIsInstance<FirField>().filter { it.isSynthetic }
val FirQualifiedAccess.referredPropertySymbol: FirPropertySymbol?
get() {
val reference = calleeReference as? FirResolvedNamedReference ?: return null
@@ -15,6 +15,9 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostic.compiler.based
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.AbstractFileStructureTest
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.AbstractInnerDeclarationsResolvePhaseTest
import org.jetbrains.kotlin.generators.util.TestGeneratorUtil
import org.jetbrains.kotlin.analysis.api.descriptors.test.components.*
import org.jetbrains.kotlin.analysis.api.descriptors.test.symbols.AbstractKtFe10SymbolByFqNameTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.symbols.AbstractKtFe10SymbolByReferenceTest
import org.jetbrains.kotlin.analysis.api.fir.components.AbstractFirExpectedExpressionTypeTest
import org.jetbrains.kotlin.analysis.api.fir.components.AbstractFirHLExpressionTypeTest
import org.jetbrains.kotlin.analysis.api.fir.components.AbstractFirOverriddenDeclarationProviderTest
@@ -24,9 +27,7 @@ import org.jetbrains.kotlin.analysis.api.fir.scopes.AbstractFirMemberScopeByFqNa
import org.jetbrains.kotlin.analysis.api.fir.symbols.AbstractFirSymbolByFqNameTest
import org.jetbrains.kotlin.analysis.api.fir.symbols.AbstractFirSymbolByPsiTest
import org.jetbrains.kotlin.analysis.api.fir.symbols.AbstractFirSymbolByReferenceTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.components.*
import org.jetbrains.kotlin.analysis.api.descriptors.test.symbols.AbstractKtFe10SymbolByFqNameTest
import org.jetbrains.kotlin.analysis.api.descriptors.test.symbols.AbstractKtFe10SymbolByReferenceTest
import org.jetbrains.kotlin.analysis.api.fir.scopes.AbstractFirDelegateMemberScopeTest
import org.jetbrains.kotlin.spec.utils.GeneralConfiguration
import org.jetbrains.kotlin.spec.utils.tasks.detectDirsWithTestsMapFileOnly
import org.jetbrains.kotlin.generators.generateTestGroupSuiteWithJUnit5
@@ -52,6 +53,10 @@ fun main(args: Array<String>) {
model("scopes/fileScopeTest", extension = "kt")
}
testClass<AbstractFirDelegateMemberScopeTest> {
model("scopes/delegatedMemberScope")
}
testClass<AbstractFirSymbolByPsiTest> {
model("symbols/symbolByPsi")
}