[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) }