[Analysis API] Add API for obtaining scope with synthetic properties ^KTIJ-22359 Fixed
diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10ScopeProvider.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10ScopeProvider.kt index 7d8383d..10e7d81 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10ScopeProvider.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10ScopeProvider.kt
@@ -72,7 +72,7 @@ return KtFe10ScopeMember(DeclaredMemberScope(descriptor), descriptor.constructors, analysisContext) } - override fun getDelegatedMemberScope(classSymbol: KtSymbolWithMembers): KtScope { + override fun getDelegatedMemberScope(classSymbol: KtSymbolWithMembers): KtScope { val descriptor = getDescriptor<ClassDescriptor>(classSymbol) ?: return getEmptyScope() @@ -191,6 +191,11 @@ TODO() } + override fun getSyntheticJavaPropertiesScope(type: KtType): KtTypeScope { + require(type is KtFe10Type) + TODO() + } + override fun getScopeContextForPosition(originalFile: KtFile, positionInFakeFile: KtElement): KtScopeContext { val elementToAnalyze = positionInFakeFile.containingNonLocalDeclaration() ?: originalFile val bindingContext = analysisContext.analyze(elementToAnalyze)
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt index b679308..3738854 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt
@@ -6,7 +6,6 @@ package org.jetbrains.kotlin.analysis.api.fir.components import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.components.KtImplicitReceiver import org.jetbrains.kotlin.analysis.api.components.KtScopeContext import org.jetbrains.kotlin.analysis.api.components.KtScopeProvider @@ -19,7 +18,6 @@ import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirNamedClassOrObjectSymbol import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType import org.jetbrains.kotlin.analysis.api.impl.base.scopes.KtCompositeScope -import org.jetbrains.kotlin.analysis.api.impl.base.scopes.KtCompositeTypeScope import org.jetbrains.kotlin.analysis.api.impl.base.scopes.KtEmptyScope import org.jetbrains.kotlin.analysis.api.scopes.KtScope import org.jetbrains.kotlin.analysis.api.scopes.KtTypeScope @@ -38,11 +36,8 @@ import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticPropertiesScope import org.jetbrains.kotlin.fir.resolve.scope import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor -import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator -import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope -import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.* -import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.name.FqName @@ -165,23 +160,16 @@ return KtCompositeScope(subScopes, token) } - @OptIn(KtAnalysisApiInternals::class) - override fun getTypeScope(type: KtType): KtTypeScope? { + override fun getTypeScope(type: KtType): KtTypeScope? = getFirTypeScope(type)?.let { convertToKtTypeScope(it) } + + override fun getSyntheticJavaPropertiesScope(type: KtType): KtTypeScope? { check(type is KtFirType) { "KtFirScopeProvider can only work with KtFirType, but ${type::class} was provided" } - val firSession = firResolveSession.useSiteFirSession - val firTypeScope = type.coneType.scope( - firSession, - scopeSession, - FakeOverrideTypeCalculator.Forced, - requiredPhase = FirResolvePhase.STATUS, - ) ?: return null - return KtCompositeTypeScope( - listOfNotNull( - convertToKtTypeScope(firTypeScope), - FirSyntheticPropertiesScope.createIfSyntheticNamesProviderIsDefined(firSession, type.coneType, firTypeScope)?.let { convertToKtTypeScope(it) } - ), - token - ) + val firTypeScope = getFirTypeScope(type) ?: return null + return FirSyntheticPropertiesScope.createIfSyntheticNamesProviderIsDefined( + firResolveSession.useSiteFirSession, + type.coneType, + firTypeScope + )?.let { convertToKtTypeScope(it) } } override fun getScopeContextForPosition( @@ -246,6 +234,16 @@ else -> TODO(firScope::class.toString()) } } + + private fun getFirTypeScope(type: KtType): FirTypeScope? { + check(type is KtFirType) { "KtFirScopeProvider can only work with KtFirType, but ${type::class} was provided" } + return type.coneType.scope( + firResolveSession.useSiteFirSession, + scopeSession, + FakeOverrideTypeCalculator.Forced, + requiredPhase = FirResolvePhase.STATUS, + ) + } } private class EnumEntryContainingNamesAwareScope(private val originalScope: FirContainingNamesAwareScope) : FirContainingNamesAwareScope() {
diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtScopeProvider.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtScopeProvider.kt index aa2fb3a..fa87e38 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtScopeProvider.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtScopeProvider.kt
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers import org.jetbrains.kotlin.analysis.api.types.KtType +import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile @@ -37,6 +38,8 @@ public abstract fun getTypeScope(type: KtType): KtTypeScope? + public abstract fun getSyntheticJavaPropertiesScope(type: KtType): KtTypeScope? + public abstract fun getScopeContextForPosition( originalFile: KtFile, positionInFakeFile: KtElement @@ -44,6 +47,10 @@ } public interface KtScopeProviderMixIn : KtAnalysisSessionMixIn { + /** + * Creates [KtScope] containing members of [KtDeclaration]. + * Returned [KtScope] doesn't include synthetic Java properties. To get such properties use [getSyntheticJavaPropertiesScope]. + */ public fun KtSymbolWithMembers.getMemberScope(): KtScope = withValidityAssertion { analysisSession.scopeProvider.getMemberScope(this) } @@ -81,6 +88,7 @@ * Inside the `LIST_KT_ELEMENT.getKtType().getTypeScope()` would contain the `get(i: Int): String` method with substituted type `T = String` * * @return type scope for the given type if given `KtType` is not error type, `null` otherwise. + * Returned [KtTypeScope] doesn't include synthetic Java properties. To get such properties use [getSyntheticJavaPropertiesScope]. * * @see KtTypeScope * @see KtTypeProviderMixIn.getKtType @@ -88,6 +96,16 @@ public fun KtType.getTypeScope(): KtTypeScope? = withValidityAssertion { analysisSession.scopeProvider.getTypeScope(this) } + /** + * Returns a [KtTypeScope] with synthetic Java properties created for a given [KtType]. + */ + public fun KtType.getSyntheticJavaPropertiesScope(): KtTypeScope? = + withValidityAssertion { analysisSession.scopeProvider.getSyntheticJavaPropertiesScope(this) } + + /** + * Scopes in returned [KtScopeContext] don't include synthetic Java properties. + * To get such properties use [getSyntheticJavaPropertiesScope]. + */ public fun KtFile.getScopeContextForPosition(positionInFakeFile: KtElement): KtScopeContext = withValidityAssertion { analysisSession.scopeProvider.getScopeContextForPosition(this, positionInFakeFile) }