AA: apply java type enhancement to declaredMemberScope.

* added getDeclaredMemberScope to JavaScopeProvider.
This commit is contained in:
Jiaxiang Chen
2022-12-05 19:09:35 -08:00
committed by Ilya Kirillov
parent f620eb920f
commit 7ce2f64c18
12 changed files with 547 additions and 2 deletions
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirEnumEntrySymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirFileSymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType
import org.jetbrains.kotlin.analysis.api.fir.utils.firSymbol
import org.jetbrains.kotlin.analysis.api.impl.base.scopes.KtCompositeScope
import org.jetbrains.kotlin.analysis.api.impl.base.scopes.KtEmptyScope
import org.jetbrains.kotlin.analysis.api.scopes.KtScope
@@ -28,14 +29,20 @@ import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
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.declarations.utils.isCompanion
import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression
import org.jetbrains.kotlin.fir.java.JavaScopeProvider
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.analysis.api.fir.scopes.JavaClassDeclaredMembersEnhancementScope
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticPropertiesScope
import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.resolve.scopeSessionKey
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.*
@@ -101,9 +108,12 @@ internal class KtFirScopeProvider(
override fun getDeclaredMemberScope(classSymbol: KtSymbolWithMembers): KtScope {
val firScope = classSymbol.withFirForScope {
analysisSession.useSiteSession.declaredMemberScope(it)
val useSiteSession = analysisSession.useSiteSession
when (val regularClass = classSymbol.firSymbol.fir) {
is FirJavaClass -> buildJavaEnhancementDeclaredMemberScope(useSiteSession, regularClass.symbol, getScopeSession())
else -> useSiteSession.declaredMemberScope(it)
}
} ?: return getEmptyScope()
return KtFirDelegatingScope(firScope, builder)
}
@@ -229,6 +239,20 @@ internal class KtFirScopeProvider(
requiredPhase = FirResolvePhase.STATUS,
)
}
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)
)
}
}
}
private class EnumEntryContainingNamesAwareScope(private val originalScope: FirContainingNamesAwareScope) : FirContainingNamesAwareScope() {
@@ -260,3 +284,5 @@ private class EnumEntryContainingNamesAwareScope(private val originalScope: FirC
// enum entries does not have constructors
}
}
private val JAVA_ENHANCEMENT_FOR_DECLARED_MEMBER = scopeSessionKey<FirRegularClassSymbol, JavaClassDeclaredMembersEnhancementScope>()
@@ -0,0 +1,93 @@
/*
* 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.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.nestedClassifierScope
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
internal class JavaClassDeclaredMembersEnhancementScope(
private val useSiteSession: FirSession,
private val owner: FirJavaClass,
private val useSiteMemberEnhancementScope: FirTypeScope
) : FirContainingNamesAwareScope() {
private fun FirCallableDeclaration.isDeclared(): Boolean {
return (this.dispatchReceiverType as? ConeLookupTagBasedType)?.lookupTag == owner.symbol.toLookupTag()
&& this.origin != FirDeclarationOrigin.SubstitutionOverride
&& this.origin != FirDeclarationOrigin.IntersectionOverride
}
private val callableNames = run {
(useSiteMemberEnhancementScope.collectAllProperties() + useSiteMemberEnhancementScope.collectAllFunctions()).filter {
it.fir.isDeclared()
}.map {
it.name
}.toSet()
}
private val nestedClassifierScope: FirContainingNamesAwareScope? =
useSiteSession.nestedClassifierScope(owner)
override fun getCallableNames(): Set<Name> {
return callableNames
}
override fun getClassifierNames(): Set<Name> {
return nestedClassifierScope?.getClassifierNames().orEmpty()
}
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
if (name == SpecialNames.INIT) return
useSiteMemberEnhancementScope.processFunctionsByName(name) { symbol ->
if (symbol.fir.isDeclared()) {
processor(symbol)
}
}
}
override fun processClassifiersByNameWithSubstitution(
name: Name,
processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit
) {
nestedClassifierScope?.processClassifiersByNameWithSubstitution(name, processor)
}
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
owner.declarations.filterIsInstance<FirConstructor>().forEach { constructor ->
useSiteMemberEnhancementScope.processDeclaredConstructors {
processor(constructor.symbol)
}
}
}
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
useSiteMemberEnhancementScope.processPropertiesByName(name) { symbol ->
if (symbol.fir.isDeclared()) {
processor(symbol)
}
}
}
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 }
}
}
@@ -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.test.cases.generated.cases.scopes;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.analysis.api.fir.test.configurators.AnalysisApiFirTestConfiguratorFactory;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfiguratorFactoryData;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisSessionMode;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiMode;
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.scopes.AbstractDeclaredMemberScopeTest;
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 org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("analysis/analysis-api/testData/scopes/declaredMemberScope")
@TestDataPath("$PROJECT_ROOT")
public class FirIdeNormalAnalysisSourceModuleDeclaredMemberScopeTestGenerated extends AbstractDeclaredMemberScopeTest {
@NotNull
@Override
public AnalysisApiTestConfigurator getConfigurator() {
return AnalysisApiFirTestConfiguratorFactory.INSTANCE.createConfigurator(
new AnalysisApiTestConfiguratorFactoryData(
FrontendKind.Fir,
TestModuleKind.Source,
AnalysisSessionMode.Normal,
AnalysisApiMode.Ide
)
);
}
@Test
public void testAllFilesPresentInDeclaredMemberScope() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/scopes/declaredMemberScope"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("javaDeclaredEnhancementScope.kt")
public void testJavaDeclaredEnhancementScope() throws Exception {
runTest("analysis/analysis-api/testData/scopes/declaredMemberScope/javaDeclaredEnhancementScope.kt");
}
@Test
@TestMetadata("javaDeclaredInheritList.kt")
public void testJavaDeclaredInheritList() throws Exception {
runTest("analysis/analysis-api/testData/scopes/declaredMemberScope/javaDeclaredInheritList.kt");
}
}
@@ -0,0 +1,24 @@
/*
* 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.impl.base.test.cases.scopes
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.impl.base.test.SymbolByFqName
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.AbstractSymbolByFqNameTest
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.SymbolsData
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.services.TestServices
abstract class AbstractDeclaredMemberScopeTest : AbstractSymbolByFqNameTest() {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): SymbolsData {
val symbolData = SymbolByFqName.getSymbolDataFromFile(testDataPath)
val symbols = with(symbolData) { toSymbols() }
val classSymbol = symbols.singleOrNull() as? KtSymbolWithMembers
?: error("Should be a single class symbol, but $symbols found")
return SymbolsData(classSymbol.getDeclaredMemberScope().getAllSymbols().toList())
}
}
@@ -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.standalone.fir.test.cases.generated.cases.scopes;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.analysis.api.standalone.fir.test.AnalysisApiFirStandaloneModeTestConfiguratorFactory;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfiguratorFactoryData;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisSessionMode;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiMode;
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.scopes.AbstractDeclaredMemberScopeTest;
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 org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("analysis/analysis-api/testData/scopes/declaredMemberScope")
@TestDataPath("$PROJECT_ROOT")
public class FirStandaloneNormalAnalysisSourceModuleDeclaredMemberScopeTestGenerated extends AbstractDeclaredMemberScopeTest {
@NotNull
@Override
public AnalysisApiTestConfigurator getConfigurator() {
return AnalysisApiFirStandaloneModeTestConfiguratorFactory.INSTANCE.createConfigurator(
new AnalysisApiTestConfiguratorFactoryData(
FrontendKind.Fir,
TestModuleKind.Source,
AnalysisSessionMode.Normal,
AnalysisApiMode.Standalone
)
);
}
@Test
public void testAllFilesPresentInDeclaredMemberScope() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/scopes/declaredMemberScope"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("javaDeclaredEnhancementScope.kt")
public void testJavaDeclaredEnhancementScope() throws Exception {
runTest("analysis/analysis-api/testData/scopes/declaredMemberScope/javaDeclaredEnhancementScope.kt");
}
@Test
@TestMetadata("javaDeclaredInheritList.kt")
public void testJavaDeclaredInheritList() throws Exception {
runTest("analysis/analysis-api/testData/scopes/declaredMemberScope/javaDeclaredInheritList.kt");
}
}
@@ -0,0 +1,11 @@
// class: JavaClass
// FILE: main.kt
// FILE: JavaClass.java
public class JavaClass {
public int field = 1;
public String field2 = "S";
public String foo() {
return "foo";
}
}
@@ -0,0 +1,7 @@
open var field: kotlin.Int
open var field2: kotlin.String!
open fun foo(): kotlin.String!
constructor()
@@ -0,0 +1,102 @@
KtJavaFieldSymbol:
annotationsList: []
callableIdIfNonLocal: /JavaClass.field
contextReceivers: []
isExtension: false
isStatic: false
isVal: false
modality: OPEN
name: field
origin: JAVA
receiverParameter: null
returnType: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
symbolKind: CLASS_MEMBER
typeParameters: []
visibility: Public
getDispatchReceiver(): KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: JavaClass
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
KtJavaFieldSymbol:
annotationsList: []
callableIdIfNonLocal: /JavaClass.field2
contextReceivers: []
isExtension: false
isStatic: false
isVal: false
modality: OPEN
name: field2
origin: JAVA
receiverParameter: null
returnType: KtFlexibleType:
annotationsList: []
type: kotlin/String!
symbolKind: CLASS_MEMBER
typeParameters: []
visibility: Public
getDispatchReceiver(): KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: JavaClass
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: /JavaClass.foo
contextReceivers: []
contractEffects: []
hasStableParameterNames: false
isBuiltinFunctionInvoke: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: OPEN
name: foo
origin: JAVA
receiverParameter: null
returnType: KtFlexibleType:
annotationsList: []
type: kotlin/String!
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: []
visibility: Public
getDispatchReceiver(): KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: JavaClass
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
KtConstructorSymbol:
annotationsList: []
callableIdIfNonLocal: null
containingClassIdIfNonLocal: JavaClass
contextReceivers: []
hasStableParameterNames: false
isExtension: false
isPrimary: true
origin: JAVA
receiverParameter: null
returnType: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: JavaClass
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: []
visibility: Public
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
@@ -0,0 +1,18 @@
// RUNTIME
// class: JavaClass
// FILE: main.kt
// FILE: JavaClass.java
import java.util.ArrayList;
public class JavaClass extends ArrayList<String> {
JavaClass() {
}
public String remove(int index) {
return "";
}
public int add(String s) {
return 1;
}
}
@@ -0,0 +1,5 @@
open fun add(s: kotlin.String!): kotlin.Int
open operator fun removeAt(index: kotlin.Int): kotlin.String!
constructor()
@@ -0,0 +1,132 @@
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: /JavaClass.add
contextReceivers: []
contractEffects: []
hasStableParameterNames: false
isBuiltinFunctionInvoke: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: OPEN
name: add
origin: JAVA
receiverParameter: null
returnType: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: [
KtValueParameterSymbol:
annotationsList: []
callableIdIfNonLocal: null
contextReceivers: []
generatedPrimaryConstructorProperty: null
hasDefaultValue: false
isCrossinline: false
isExtension: false
isImplicitLambdaParameter: false
isNoinline: false
isVararg: false
name: s
origin: JAVA
receiverParameter: null
returnType: KtFlexibleType:
annotationsList: []
type: kotlin/String!
symbolKind: LOCAL
typeParameters: []
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
]
visibility: Public
getDispatchReceiver(): KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: JavaClass
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: /JavaClass.removeAt
contextReceivers: []
contractEffects: []
hasStableParameterNames: false
isBuiltinFunctionInvoke: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: true
isOverride: false
isStatic: false
isSuspend: false
modality: OPEN
name: removeAt
origin: JAVA
receiverParameter: null
returnType: KtFlexibleType:
annotationsList: []
type: kotlin/String!
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: [
KtValueParameterSymbol:
annotationsList: []
callableIdIfNonLocal: null
contextReceivers: []
generatedPrimaryConstructorProperty: null
hasDefaultValue: false
isCrossinline: false
isExtension: false
isImplicitLambdaParameter: false
isNoinline: false
isVararg: false
name: index
origin: JAVA
receiverParameter: null
returnType: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
symbolKind: LOCAL
typeParameters: []
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
]
visibility: Public
getDispatchReceiver(): KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: JavaClass
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
KtConstructorSymbol:
annotationsList: []
callableIdIfNonLocal: null
containingClassIdIfNonLocal: JavaClass
contextReceivers: []
hasStableParameterNames: false
isExtension: false
isPrimary: false
origin: JAVA
receiverParameter: null
returnType: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: JavaClass
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: []
visibility: PackageVisibility
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
@@ -117,6 +117,13 @@ private fun AnalysisApiTestGroup.generateAnalysisApiNonComponentsTests() {
test(AbstractDelegateMemberScopeTest::class) {
model("delegatedMemberScope")
}
test(
AbstractDeclaredMemberScopeTest::class,
filter = frontendIs(FrontendKind.Fir),
) {
model("declaredMemberScope")
}
}
group("symbols", filter = analysisSessionModeIs(AnalysisSessionMode.Normal)) {