[FIR] Add ability to generate members and nested classifiers for existing classes

This commit is contained in:
Dmitriy Novozhilov
2021-09-29 15:54:10 +03:00
committed by TeamCityServer
parent 9bfa6c54b8
commit 26fa772846
17 changed files with 359 additions and 113 deletions
@@ -41,10 +41,13 @@ abstract class AbstractArrayMapOwner<K : Any, V : Any> : Iterable<V> {
class ArrayMapAccessor<K : Any, V : Any, T : V>(
key: KClass<out K>,
id: Int
id: Int,
val default: T? = null
) : AbstractArrayMapOwner.AbstractArrayMapAccessor<K, V, T>(key, id), ReadOnlyProperty<AbstractArrayMapOwner<K, V>, V> {
override fun getValue(thisRef: AbstractArrayMapOwner<K, V>, property: KProperty<*>): T {
return extractValue(thisRef) ?: error("No '$key'($id) in array owner: $thisRef")
return extractValue(thisRef)
?: default
?: error("No '$key'($id) in array owner: $thisRef")
}
}
@@ -62,8 +65,8 @@ abstract class TypeRegistry<K : Any, V : Any> {
private val idCounter = AtomicInteger(0)
fun <T : V, KK : K> generateAccessor(kClass: KClass<KK>): ArrayMapAccessor<K, V, T> {
return ArrayMapAccessor(kClass, getId(kClass))
fun <T : V, KK : K> generateAccessor(kClass: KClass<KK>, default: T? = null): ArrayMapAccessor<K, V, T> {
return ArrayMapAccessor(kClass, getId(kClass), default)
}
fun <T : V, KK : K> generateNullableAccessor(kClass: KClass<KK>): NullableArrayMapAccessor<K, V, T> {
@@ -38,8 +38,8 @@ abstract class FirDeclarationGenerationExtension(session: FirSession) : FirPredi
// Can be called on IMPORTS stage
open fun hasPackage(packageFqName: FqName): Boolean = false
open fun getCallableNamesForGeneratedClass(classSymbol: FirClassSymbol<*>): Set<Name> = emptySet()
open fun getNestedClassifiersNamesForGeneratedClass(classSymbol: FirClassSymbol<*>): Set<Name> = emptySet()
open fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> = emptySet()
open fun getNestedClassifiersNames(classSymbol: FirClassSymbol<*>): Set<Name> = emptySet()
fun interface Factory : FirExtension.Factory<FirDeclarationGenerationExtension>
}
@@ -20,11 +20,13 @@ annotation class PluginServicesInitialization
class FirExtensionService(val session: FirSession) : ComponentArrayOwner<FirExtension, List<FirExtension>>(), FirSessionComponent {
companion object : TypeRegistry<FirExtension, List<FirExtension>>() {
inline fun <reified P : FirExtension, V : List<P>> registeredExtensions(): ArrayMapAccessor<FirExtension, List<FirExtension>, V> {
return generateAccessor(P::class)
@Suppress("UNCHECKED_CAST")
return generateAccessor(P::class, default = emptyList<P>() as V)
}
fun <P : FirExtension, V : List<P>> registeredExtensions(kClass: KClass<P>): ArrayMapAccessor<FirExtension, List<FirExtension>, V> {
return generateAccessor(kClass)
@Suppress("UNCHECKED_CAST")
return generateAccessor(kClass, default = emptyList<P>() as V)
}
}
@@ -12,16 +12,20 @@ import org.jetbrains.kotlin.fir.caches.FirCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.caches.getValue
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.extensions.declarationGenerators
import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
import org.jetbrains.kotlin.fir.resolve.declaredMemberScopeProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.FirCompositeScope
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
@ThreadSafeMutableState
class FirDeclaredMemberScopeProvider(val useSiteSession: FirSession) : FirSessionComponent {
private val declaredMemberCache: FirCache<FirClass, FirClassDeclaredMemberScope, DeclaredMemberScopeContext> =
private val declaredMemberCache: FirCache<FirClass, FirContainingNamesAwareScope, DeclaredMemberScopeContext> =
useSiteSession.firCachesFactory.createCache { klass, context ->
createDeclaredMemberScope(klass, context.useLazyNestedClassifierScope, context.existingNames, context.symbolProvider)
}
@@ -29,12 +33,14 @@ class FirDeclaredMemberScopeProvider(val useSiteSession: FirSession) : FirSessio
private val nestedClassifierCache: FirCache<FirClass, FirNestedClassifierScope?, Nothing?> =
useSiteSession.firCachesFactory.createCache { klass, _ -> createNestedClassifierScope(klass) }
private val extensions by lazy(LazyThreadSafetyMode.PUBLICATION) { useSiteSession.extensionService.declarationGenerators }
fun declaredMemberScope(
klass: FirClass,
useLazyNestedClassifierScope: Boolean,
existingNames: List<Name>?,
symbolProvider: FirSymbolProvider?
): FirClassDeclaredMemberScope {
): FirContainingNamesAwareScope {
return declaredMemberCache.getValue(klass, DeclaredMemberScopeContext(useLazyNestedClassifierScope, existingNames, symbolProvider))
}
@@ -49,11 +55,27 @@ class FirDeclaredMemberScopeProvider(val useSiteSession: FirSession) : FirSessio
useLazyNestedClassifierScope: Boolean,
existingNames: List<Name>?,
symbolProvider: FirSymbolProvider?
): FirClassDeclaredMemberScope {
return if (klass.origin.generated) {
FirGeneratedClassDeclaredMemberScope(useSiteSession, klass)
} else {
FirClassDeclaredMemberScopeImpl(useSiteSession, klass, useLazyNestedClassifierScope, existingNames, symbolProvider)
): FirContainingNamesAwareScope {
return when {
klass.origin.generated -> {
FirGeneratedClassDeclaredMemberScope(useSiteSession, klass, needNestedClassifierScope = true)
}
else -> {
val baseScope = FirClassDeclaredMemberScopeImpl(
useSiteSession,
klass,
useLazyNestedClassifierScope,
existingNames,
symbolProvider
)
if (extensions.any { useSiteSession.predicateBasedProvider.matches(it.predicate, klass) }) {
FirCompositeScope(
listOf(baseScope, FirGeneratedClassDeclaredMemberScope(useSiteSession, klass, needNestedClassifierScope = false))
)
} else {
baseScope
}
}
}
}
@@ -65,17 +87,26 @@ class FirDeclaredMemberScopeProvider(val useSiteSession: FirSession) : FirSessio
return if (klass.origin.generated) {
FirGeneratedClassNestedClassifierScope(klass, useSiteSession)
} else {
FirNestedClassifierScopeImpl(klass, useSiteSession)
val baseScope = FirNestedClassifierScopeImpl(klass, useSiteSession)
if (extensions.any { useSiteSession.predicateBasedProvider.matches(it.predicate, klass) }) {
FirCompositeNestedClassifierScope(
listOf(baseScope, FirGeneratedClassNestedClassifierScope(klass, useSiteSession)),
klass,
useSiteSession
)
} else {
baseScope
}
}.takeUnless { it.isEmpty() }
}
}
fun FirSession.declaredMemberScope(klass: FirClass): FirClassDeclaredMemberScope {
fun FirSession.declaredMemberScope(klass: FirClass): FirContainingNamesAwareScope {
return declaredMemberScopeProvider
.declaredMemberScope(klass, useLazyNestedClassifierScope = false, existingNames = null, symbolProvider = null)
}
fun FirSession.declaredMemberScope(klass: FirClassSymbol<*>): FirClassDeclaredMemberScope {
fun FirSession.declaredMemberScope(klass: FirClassSymbol<*>): FirContainingNamesAwareScope {
return declaredMemberScope(klass.fir)
}
@@ -83,7 +114,7 @@ fun FirSession.declaredMemberScopeWithLazyNestedScope(
klass: FirClass,
existingNames: List<Name>,
symbolProvider: FirSymbolProvider
): FirScope {
): FirContainingNamesAwareScope {
return declaredMemberScopeProvider
.declaredMemberScope(klass, useLazyNestedClassifierScope = true, existingNames = existingNames, symbolProvider = symbolProvider)
}
@@ -16,19 +16,23 @@ import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
import org.jetbrains.kotlin.fir.extensions.declarationGenerators
import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.runIf
class FirGeneratedClassDeclaredMemberScope(
val useSiteSession: FirSession,
val firClass: FirClass
val firClass: FirClass,
needNestedClassifierScope: Boolean
) : FirClassDeclaredMemberScope() {
private val extension: FirDeclarationGenerationExtension = firClass.findGeneratedExtension(useSiteSession)
private val nestedClassifierScope: FirNestedClassifierScope? = useSiteSession.nestedClassifierScope(firClass)
private val extensions: List<FirDeclarationGenerationExtension> = firClass.findGeneratedExtensions(useSiteSession)
private val nestedClassifierScope: FirNestedClassifierScope? = runIf(needNestedClassifierScope) {
useSiteSession.nestedClassifierScope(firClass)
}
private val firCachesFactory = useSiteSession.firCachesFactory
@@ -47,17 +51,17 @@ class FirGeneratedClassDeclaredMemberScope(
}
private val callableNamesCache: FirLazyValue<Set<Name>, Nothing?> = firCachesFactory.createLazyValue {
extension.getCallableNamesForGeneratedClass(firClass.symbol)
extensions.flatMapTo(mutableSetOf()) { it.getCallableNamesForClass(firClass.symbol) }
}
// ------------------------------------------ generators ------------------------------------------
private fun generateMemberFunctions(name: Name): List<FirNamedFunctionSymbol> {
return extension.generateFunctions(CallableId(firClass.classId, name), firClass.symbol)
return extensions.flatMap { it.generateFunctions(CallableId(firClass.classId, name), firClass.symbol) }
}
private fun generateMemberProperties(name: Name): List<FirPropertySymbol> {
return extension.generateProperties(CallableId(firClass.classId, name), firClass.symbol)
return extensions.flatMap { it.generateProperties(CallableId(firClass.classId, name), firClass.symbol) }
}
private fun generateConstructors(): List<FirConstructorSymbol> {
@@ -67,7 +71,7 @@ class FirGeneratedClassDeclaredMemberScope(
} else {
CallableId(classId.asSingleFqName().parent(), classId.shortClassName)
}
return extension.generateConstructors(callableId)
return extensions.flatMap { it.generateConstructors(callableId) }
}
// ------------------------------------------ scope methods ------------------------------------------
@@ -109,7 +113,7 @@ class FirGeneratedClassNestedClassifierScope(
klass: FirClass,
useSiteSession: FirSession
) : FirNestedClassifierScope(klass, useSiteSession) {
private val extension = klass.findGeneratedExtension(useSiteSession)
private val extensions = klass.findGeneratedExtensions(useSiteSession)
private val nestedClassifierCache: FirCache<Name, FirRegularClassSymbol?, Nothing?> =
useSiteSession.firCachesFactory.createCache { name, _ ->
@@ -118,7 +122,7 @@ class FirGeneratedClassNestedClassifierScope(
private val nestedClassifiersNames: FirLazyValue<Set<Name>, Nothing?> =
useSiteSession.firCachesFactory.createLazyValue {
extension.getNestedClassifiersNamesForGeneratedClass(klass.symbol)
extensions.flatMapTo(mutableSetOf()) { it.getNestedClassifiersNames(klass.symbol) }
}
private fun generateNestedClassifier(name: Name): FirRegularClassSymbol? {
@@ -142,13 +146,15 @@ class FirGeneratedClassNestedClassifierScope(
}
private fun FirClass.findGeneratedExtension(useSiteSession: FirSession): FirDeclarationGenerationExtension {
private fun FirClass.findGeneratedExtensions(useSiteSession: FirSession): List<FirDeclarationGenerationExtension> {
val origin = origin
require(origin is FirDeclarationOrigin.Plugin) {
"GeneratedClassDeclaredMemberScope can not be created for non-generated class: ${this.render()}"
val declarationGenerators = useSiteSession.extensionService.declarationGenerators
return if (origin is FirDeclarationOrigin.Plugin) {
declarationGenerators.filter { it.key == origin.key }.also {
require(it.isNotEmpty()) { "Extension for ${origin.key} not found" }
}
} else {
val predicateBasedProvider = useSiteSession.predicateBasedProvider
declarationGenerators.filter { predicateBasedProvider.matches(it.predicate, this) }
}
return useSiteSession.extensionService.declarationGenerators.firstOrNull {
it.key == origin.key
} ?: error("Extension for ${origin.key} not found")
}
@@ -59,6 +59,28 @@ class FirNestedClassifierScopeImpl(klass: FirClass, useSiteSession: FirSession)
override fun getClassifierNames(): Set<Name> = classIndex.keys
}
class FirCompositeNestedClassifierScope(
val scopes: List<FirNestedClassifierScope>,
klass: FirClass,
useSiteSession: FirSession
) : FirNestedClassifierScope(klass, useSiteSession) {
override fun getNestedClassSymbol(name: Name): FirRegularClassSymbol? {
error("Should not be called")
}
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
scopes.forEach { it.processClassifiersByNameWithSubstitution(name, processor) }
}
override fun isEmpty(): Boolean {
return scopes.all { it.isEmpty() }
}
override fun getClassifierNames(): Set<Name> {
return scopes.flatMapTo(mutableSetOf()) { it.getClassifierNames() }
}
}
fun FirTypeParameterRef.toConeType(): ConeKotlinType = symbol.toConeType()
fun FirTypeParameterSymbol.toConeType(): ConeKotlinType = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(this), isNullable = false)
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.scopes
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.name.Name
@@ -37,6 +38,20 @@ class FirCompositeScope(val scopes: Iterable<FirScope>) : FirContainingNamesAwar
}
}
private inline fun <T> processComposite(
process: FirScope.((T) -> Unit) -> Unit,
noinline processor: (T) -> Unit
) {
val unique = mutableSetOf<T>()
for (scope in scopes) {
scope.process {
if (unique.add(it)) {
processor(it)
}
}
}
}
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
return processComposite(FirScope::processFunctionsByName, name, processor)
}
@@ -45,6 +60,10 @@ class FirCompositeScope(val scopes: Iterable<FirScope>) : FirContainingNamesAwar
return processComposite(FirScope::processPropertiesByName, name, processor)
}
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
processComposite(FirScope::processDeclaredConstructors, processor)
}
override fun getCallableNames(): Set<Name> {
return scopes.flatMapTo(hashSetOf()) { it.getContainingCallableNamesIfPresent() }
}