[FIR] Store generated declarations in the session component
Also extract generated declarations for classes from declaration site session, not use site ^KT-57821 Fixed
This commit is contained in:
committed by
Space Team
parent
c6f5cf3e62
commit
2087a7c899
@@ -71,6 +71,7 @@ fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersion
|
|||||||
|
|
||||||
register(FirSubstitutionOverrideStorage::class, FirSubstitutionOverrideStorage(this))
|
register(FirSubstitutionOverrideStorage::class, FirSubstitutionOverrideStorage(this))
|
||||||
register(FirIntersectionOverrideStorage::class, FirIntersectionOverrideStorage(this))
|
register(FirIntersectionOverrideStorage::class, FirIntersectionOverrideStorage(this))
|
||||||
|
register(FirGeneratedMemberDeclarationsStorage::class, FirGeneratedMemberDeclarationsStorage(this))
|
||||||
register(FirSamConstructorStorage::class, FirSamConstructorStorage(this))
|
register(FirSamConstructorStorage::class, FirSamConstructorStorage(this))
|
||||||
register(FirOverrideService::class, FirOverrideService(this))
|
register(FirOverrideService::class, FirOverrideService(this))
|
||||||
register(FirDynamicMembersStorage::class, FirDynamicMembersStorage(this))
|
register(FirDynamicMembersStorage::class, FirDynamicMembersStorage(this))
|
||||||
|
|||||||
+8
-7
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.fir.caches.FirCache
|
|||||||
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
||||||
import org.jetbrains.kotlin.fir.caches.getValue
|
import org.jetbrains.kotlin.fir.caches.getValue
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||||
import org.jetbrains.kotlin.fir.extensions.MemberGenerationContext
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirNameAwareCompositeScope
|
import org.jetbrains.kotlin.fir.scopes.FirNameAwareCompositeScope
|
||||||
@@ -58,8 +57,9 @@ class FirDeclaredMemberScopeProvider(val useSiteSession: FirSession) : FirSessio
|
|||||||
origin.generated -> {
|
origin.generated -> {
|
||||||
FirGeneratedClassDeclaredMemberScope.create(
|
FirGeneratedClassDeclaredMemberScope.create(
|
||||||
useSiteSession,
|
useSiteSession,
|
||||||
MemberGenerationContext(klass.symbol, declaredScope = null),
|
klass.symbol,
|
||||||
needNestedClassifierScope = true
|
regularDeclaredScope = null,
|
||||||
|
scopeForGeneratedClass = true
|
||||||
) ?: FirTypeScope.Empty
|
) ?: FirTypeScope.Empty
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@@ -73,8 +73,9 @@ class FirDeclaredMemberScopeProvider(val useSiteSession: FirSession) : FirSessio
|
|||||||
val generatedScope = runIf(origin.fromSource || origin.generated) {
|
val generatedScope = runIf(origin.fromSource || origin.generated) {
|
||||||
FirGeneratedClassDeclaredMemberScope.create(
|
FirGeneratedClassDeclaredMemberScope.create(
|
||||||
useSiteSession,
|
useSiteSession,
|
||||||
MemberGenerationContext(klass.symbol, baseScope),
|
klass.symbol,
|
||||||
needNestedClassifierScope = false
|
regularDeclaredScope = baseScope,
|
||||||
|
scopeForGeneratedClass = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (generatedScope != null) {
|
if (generatedScope != null) {
|
||||||
@@ -93,11 +94,11 @@ class FirDeclaredMemberScopeProvider(val useSiteSession: FirSession) : FirSessio
|
|||||||
private fun createNestedClassifierScope(klass: FirClass): FirNestedClassifierScope? {
|
private fun createNestedClassifierScope(klass: FirClass): FirNestedClassifierScope? {
|
||||||
val origin = klass.origin
|
val origin = klass.origin
|
||||||
return if (origin.generated) {
|
return if (origin.generated) {
|
||||||
FirGeneratedClassNestedClassifierScope.create(useSiteSession, klass, baseScope = null)
|
FirGeneratedClassNestedClassifierScope.create(useSiteSession, klass.symbol, regularNestedClassifierScope = null)
|
||||||
} else {
|
} else {
|
||||||
val baseScope = FirNestedClassifierScopeImpl(klass, useSiteSession)
|
val baseScope = FirNestedClassifierScopeImpl(klass, useSiteSession)
|
||||||
val generatedScope = runIf(origin.fromSource) {
|
val generatedScope = runIf(origin.fromSource) {
|
||||||
FirGeneratedClassNestedClassifierScope.create(useSiteSession, klass, baseScope)
|
FirGeneratedClassNestedClassifierScope.create(useSiteSession, klass.symbol, regularNestedClassifierScope = baseScope)
|
||||||
}
|
}
|
||||||
if (generatedScope != null) {
|
if (generatedScope != null) {
|
||||||
FirCompositeNestedClassifierScope(
|
FirCompositeNestedClassifierScope(
|
||||||
|
|||||||
+197
-148
@@ -6,13 +6,9 @@
|
|||||||
package org.jetbrains.kotlin.fir.scopes.impl
|
package org.jetbrains.kotlin.fir.scopes.impl
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.caches.FirCache
|
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||||
import org.jetbrains.kotlin.fir.caches.FirLazyValue
|
import org.jetbrains.kotlin.fir.caches.*
|
||||||
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.declarations.FirClass
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.classId
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.validate
|
import org.jetbrains.kotlin.fir.declarations.validate
|
||||||
import org.jetbrains.kotlin.fir.extensions.*
|
import org.jetbrains.kotlin.fir.extensions.*
|
||||||
import org.jetbrains.kotlin.fir.ownerGenerator
|
import org.jetbrains.kotlin.fir.ownerGenerator
|
||||||
@@ -20,90 +16,52 @@ import org.jetbrains.kotlin.fir.render
|
|||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.name.CallableId
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.flatGroupBy
|
import org.jetbrains.kotlin.utils.addToStdlib.flatGroupBy
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||||
|
|
||||||
class FirGeneratedClassDeclaredMemberScope private constructor(
|
class FirGeneratedClassDeclaredMemberScope private constructor(
|
||||||
val useSiteSession: FirSession,
|
classId: ClassId,
|
||||||
private val generationContext: MemberGenerationContext,
|
private val storage: FirGeneratedMemberDeclarationsStorage.CallableStorage,
|
||||||
needNestedClassifierScope: Boolean,
|
private val nestedClassifierScope: FirNestedClassifierScope?
|
||||||
val extensionsByCallableName: Map<Name, List<FirDeclarationGenerationExtension>>,
|
) : FirClassDeclaredMemberScope(classId) {
|
||||||
val allCallableNames: Set<Name>
|
|
||||||
) : FirClassDeclaredMemberScope(generationContext.owner.classId) {
|
|
||||||
companion object {
|
companion object {
|
||||||
fun create(
|
fun create(
|
||||||
session: FirSession,
|
useSiteSession: FirSession,
|
||||||
generationContext: MemberGenerationContext,
|
classSymbol: FirClassSymbol<*>,
|
||||||
needNestedClassifierScope: Boolean
|
regularDeclaredScope: FirClassDeclaredMemberScope?,
|
||||||
|
scopeForGeneratedClass: Boolean
|
||||||
): FirGeneratedClassDeclaredMemberScope? {
|
): FirGeneratedClassDeclaredMemberScope? {
|
||||||
val extensionsByCallableName = session.groupExtensionsByName(
|
/*
|
||||||
generationContext.owner.fir,
|
* Extensions can modify source classes of the same session in which they are enabled
|
||||||
nameExtractor = { getCallableNamesForClass(it, generationContext) },
|
* This implies the contract that if declaration-site session and use-site session
|
||||||
nameTransformer = { it }
|
* differs for some class, generated declarations should be provided by extensions
|
||||||
)
|
* of declaration-site session
|
||||||
val allCallableNames = extensionsByCallableName.keys
|
*/
|
||||||
if (allCallableNames.isEmpty()) return null
|
val storage = classSymbol.moduleData
|
||||||
|
.session
|
||||||
|
.generatedDeclarationsStorage
|
||||||
|
.getCallableStorage(classSymbol, regularDeclaredScope, scopeForGeneratedClass)
|
||||||
|
?: return null
|
||||||
|
|
||||||
|
val nestedClassifierScope = runIf(scopeForGeneratedClass) {
|
||||||
|
useSiteSession.nestedClassifierScope(classSymbol.fir)
|
||||||
|
}
|
||||||
|
|
||||||
return FirGeneratedClassDeclaredMemberScope(
|
return FirGeneratedClassDeclaredMemberScope(
|
||||||
session,
|
classSymbol.classId,
|
||||||
generationContext,
|
storage,
|
||||||
needNestedClassifierScope,
|
nestedClassifierScope
|
||||||
extensionsByCallableName,
|
|
||||||
allCallableNames
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val firClass: FirClass
|
|
||||||
get() = generationContext.owner.fir
|
|
||||||
|
|
||||||
private val nestedClassifierScope: FirNestedClassifierScope? = runIf(needNestedClassifierScope) {
|
|
||||||
useSiteSession.nestedClassifierScope(firClass)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val firCachesFactory = useSiteSession.firCachesFactory
|
|
||||||
|
|
||||||
// ------------------------------------------ caches ------------------------------------------
|
|
||||||
|
|
||||||
private val functionCache: FirCache<Name, List<FirNamedFunctionSymbol>, Nothing?> = firCachesFactory.createCache { callableId, _ ->
|
|
||||||
generateMemberFunctions(callableId)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val propertyCache: FirCache<Name, List<FirPropertySymbol>, Nothing?> = firCachesFactory.createCache { callableId, _ ->
|
|
||||||
generateMemberProperties(callableId)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val constructorCache: FirLazyValue<List<FirConstructorSymbol>> = firCachesFactory.createLazyValue {
|
|
||||||
generateConstructors()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------ generators ------------------------------------------
|
|
||||||
|
|
||||||
private fun generateMemberFunctions(name: Name): List<FirNamedFunctionSymbol> {
|
|
||||||
if (name == SpecialNames.INIT) return emptyList()
|
|
||||||
return extensionsByCallableName[name].orEmpty()
|
|
||||||
.flatMap { it.generateFunctions(CallableId(firClass.classId, name), generationContext) }
|
|
||||||
.onEach { it.fir.validate() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun generateMemberProperties(name: Name): List<FirPropertySymbol> {
|
|
||||||
if (name == SpecialNames.INIT) return emptyList()
|
|
||||||
return extensionsByCallableName[name].orEmpty()
|
|
||||||
.flatMap { it.generateProperties(CallableId(firClass.classId, name), generationContext) }
|
|
||||||
.onEach { it.fir.validate() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun generateConstructors(): List<FirConstructorSymbol> {
|
|
||||||
return extensionsByCallableName[SpecialNames.INIT].orEmpty()
|
|
||||||
.flatMap { it.generateConstructors(generationContext) }
|
|
||||||
.onEach { it.fir.validate() }
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------ scope methods ------------------------------------------
|
// ------------------------------------------ scope methods ------------------------------------------
|
||||||
|
|
||||||
override fun getCallableNames(): Set<Name> {
|
override fun getCallableNames(): Set<Name> {
|
||||||
return allCallableNames
|
return storage.allCallableNames
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getClassifierNames(): Set<Name> {
|
override fun getClassifierNames(): Set<Name> {
|
||||||
@@ -116,115 +74,206 @@ class FirGeneratedClassDeclaredMemberScope private constructor(
|
|||||||
|
|
||||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||||
if (name !in getCallableNames()) return
|
if (name !in getCallableNames()) return
|
||||||
for (functionSymbol in functionCache.getValue(name)) {
|
for (functionSymbol in storage.functionCache.getValue(name)) {
|
||||||
processor(functionSymbol)
|
processor(functionSymbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||||
if (name !in getCallableNames()) return
|
if (name !in getCallableNames()) return
|
||||||
for (propertySymbol in propertyCache.getValue(name)) {
|
for (propertySymbol in storage.propertyCache.getValue(name)) {
|
||||||
processor(propertySymbol)
|
processor(propertySymbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
|
override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
|
||||||
for (constructorSymbol in constructorCache.getValue()) {
|
for (constructorSymbol in storage.constructorCache.getValue()) {
|
||||||
processor(constructorSymbol)
|
processor(constructorSymbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal inline fun <T, V> FirSession.groupExtensionsByName(
|
|
||||||
klass: FirClass,
|
|
||||||
nameExtractor: FirDeclarationGenerationExtension.(FirClassSymbol<*>) -> Set<T>,
|
|
||||||
nameTransformer: (T) -> V
|
|
||||||
): Map<V, List<FirDeclarationGenerationExtension>> {
|
|
||||||
val extensions = getExtensionsForClass(klass)
|
|
||||||
val symbol = klass.symbol
|
|
||||||
return extensions.flatGroupBy(
|
|
||||||
keySelector = { extension -> extension.nameExtractor(symbol) },
|
|
||||||
keyTransformer = nameTransformer,
|
|
||||||
valueTransformer = { it }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun FirSession.getExtensionsForClass(klass: FirClass): List<FirDeclarationGenerationExtension> {
|
|
||||||
val extensions = extensionService.declarationGenerators
|
|
||||||
return if (klass.origin.generated) {
|
|
||||||
listOf(klass.ownerGenerator!!)
|
|
||||||
} else {
|
|
||||||
extensions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FirGeneratedClassNestedClassifierScope private constructor(
|
class FirGeneratedClassNestedClassifierScope private constructor(
|
||||||
useSiteSession: FirSession,
|
useSiteSession: FirSession,
|
||||||
klass: FirClass,
|
klass: FirClass,
|
||||||
private val extensionsByName: Map<Name, List<FirDeclarationGenerationExtension>>,
|
private val storage: FirGeneratedMemberDeclarationsStorage.ClassifierStorage
|
||||||
private val context: NestedClassGenerationContext
|
|
||||||
) : FirNestedClassifierScope(klass, useSiteSession) {
|
) : FirNestedClassifierScope(klass, useSiteSession) {
|
||||||
companion object {
|
companion object {
|
||||||
@OptIn(FirExtensionApiInternals::class)
|
|
||||||
fun create(
|
fun create(
|
||||||
useSiteSession: FirSession,
|
useSiteSession: FirSession,
|
||||||
klass: FirClass,
|
classSymbol: FirClassSymbol<*>,
|
||||||
baseScope: FirNestedClassifierScope?
|
regularNestedClassifierScope: FirNestedClassifierScope?,
|
||||||
): FirGeneratedClassNestedClassifierScope? {
|
): FirGeneratedClassNestedClassifierScope? {
|
||||||
val symbol = klass.symbol
|
/*
|
||||||
val context = NestedClassGenerationContext(klass.symbol, baseScope)
|
* Extensions can modify source classes of the same session in which they are enabled
|
||||||
val extensionsByName = useSiteSession.getExtensionsForClass(klass).flatGroupBy {
|
* This implies the contract that if declaration-site session and use-site session
|
||||||
it.nestedClassifierNamesCache.getValue(symbol, context)
|
* differs for some class, generated declarations should be provided by extensions
|
||||||
}
|
* of declaration-site session
|
||||||
if (extensionsByName.isEmpty()) return null
|
*/
|
||||||
return FirGeneratedClassNestedClassifierScope(useSiteSession, klass, extensionsByName, context)
|
val storage = classSymbol.moduleData
|
||||||
}
|
.session
|
||||||
}
|
.generatedDeclarationsStorage
|
||||||
|
.getClassifierStorage(classSymbol, regularNestedClassifierScope)
|
||||||
|
?: return null
|
||||||
|
|
||||||
private val nestedClassifierCache: FirCache<Name, FirRegularClassSymbol?, Nothing?> =
|
return FirGeneratedClassNestedClassifierScope(useSiteSession, classSymbol.fir, storage,)
|
||||||
useSiteSession.firCachesFactory.createCache { name, _ ->
|
|
||||||
generateNestedClassifier(name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateNestedClassifier(name: Name): FirRegularClassSymbol? {
|
|
||||||
if (klass is FirRegularClass) {
|
|
||||||
val companion = klass.companionObjectSymbol
|
|
||||||
if (companion != null && companion.origin.generated && companion.classId.shortClassName == name) {
|
|
||||||
return companion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val extensions = extensionsByName[name] ?: return null
|
|
||||||
|
|
||||||
val generatedClasses = extensions.mapNotNull { extension ->
|
|
||||||
extension.generateNestedClassLikeDeclaration(klass.symbol, name, context)?.also { symbol ->
|
|
||||||
symbol.fir.ownerGenerator = extension
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val generatedClass = when (generatedClasses.size) {
|
|
||||||
0 -> return null
|
|
||||||
1 -> generatedClasses.first()
|
|
||||||
else -> error(
|
|
||||||
"""
|
|
||||||
Multiple plugins generated nested class with same name $name for class ${klass.classId}:
|
|
||||||
${generatedClasses.joinToString("\n") { it.fir.render() }}
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
require(generatedClass is FirRegularClassSymbol) { "Only regular class are allowed as nested classes" }
|
|
||||||
return generatedClass
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNestedClassSymbol(name: Name): FirRegularClassSymbol? {
|
override fun getNestedClassSymbol(name: Name): FirRegularClassSymbol? {
|
||||||
return nestedClassifierCache.getValue(name)
|
return storage.classifiersCache.getValue(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isEmpty(): Boolean {
|
override fun isEmpty(): Boolean {
|
||||||
return extensionsByName.isEmpty()
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getClassifierNames(): Set<Name> {
|
override fun getClassifierNames(): Set<Name> {
|
||||||
return extensionsByName.keys
|
return storage.allClassifierNames
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FirGeneratedMemberDeclarationsStorage(private val session: FirSession) : FirSessionComponent {
|
||||||
|
private val cachesFactory = session.firCachesFactory
|
||||||
|
|
||||||
|
internal fun getCallableStorage(
|
||||||
|
classSymbol: FirClassSymbol<*>,
|
||||||
|
regularDeclaredScope: FirClassDeclaredMemberScope?,
|
||||||
|
scopeForGeneratedClass: Boolean
|
||||||
|
): CallableStorage? {
|
||||||
|
val generationContext = MemberGenerationContext(classSymbol, regularDeclaredScope)
|
||||||
|
val extensionsByCallableName = groupExtensionsByName(classSymbol) { getCallableNamesForClass(it, generationContext) }
|
||||||
|
if (extensionsByCallableName.isEmpty() && !scopeForGeneratedClass) return null
|
||||||
|
return callableStorageByClass.getValue(classSymbol, StorageContext(generationContext, extensionsByCallableName))
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun getClassifierStorage(
|
||||||
|
classSymbol: FirClassSymbol<*>,
|
||||||
|
regularNestedClassifierScope: FirNestedClassifierScope?
|
||||||
|
): ClassifierStorage? {
|
||||||
|
val generationContext = NestedClassGenerationContext(classSymbol, regularNestedClassifierScope)
|
||||||
|
val extensionsByClassifierName = groupExtensionsByName(classSymbol) { getNestedClassifiersNames(it, generationContext) }
|
||||||
|
if (extensionsByClassifierName.isEmpty()) return null
|
||||||
|
return classifierStorageByClass.getValue(classSymbol, StorageContext(generationContext, extensionsByClassifierName))
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class StorageContext<C>(
|
||||||
|
val generationContext: C,
|
||||||
|
val extensionsByName: Map<Name, List<FirDeclarationGenerationExtension>>
|
||||||
|
)
|
||||||
|
|
||||||
|
private val callableStorageByClass: FirCache<FirClassSymbol<*>, CallableStorage, StorageContext<MemberGenerationContext>> =
|
||||||
|
cachesFactory.createCache { _, (context, extensionsMap) ->
|
||||||
|
CallableStorage(cachesFactory, context, extensionsMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val classifierStorageByClass: FirCache<FirClassSymbol<*>, ClassifierStorage, StorageContext<NestedClassGenerationContext>> =
|
||||||
|
cachesFactory.createCache { classSymbol, (context, extensionsMap) ->
|
||||||
|
ClassifierStorage(cachesFactory, classSymbol, context, extensionsMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CallableStorage(
|
||||||
|
cachesFactory: FirCachesFactory,
|
||||||
|
private val generationContext: MemberGenerationContext,
|
||||||
|
private val extensionsByCallableName: Map<Name, List<FirDeclarationGenerationExtension>>
|
||||||
|
) {
|
||||||
|
val functionCache: FirCache<Name, List<FirNamedFunctionSymbol>, Nothing?> =
|
||||||
|
cachesFactory.createCache { name -> generateMemberFunctions(name) }
|
||||||
|
|
||||||
|
val propertyCache: FirCache<Name, List<FirPropertySymbol>, Nothing?> =
|
||||||
|
cachesFactory.createCache { name -> generateMemberProperties(name) }
|
||||||
|
|
||||||
|
val constructorCache: FirLazyValue<List<FirConstructorSymbol>> =
|
||||||
|
cachesFactory.createLazyValue { generateConstructors() }
|
||||||
|
|
||||||
|
val allCallableNames: Set<Name>
|
||||||
|
get() = extensionsByCallableName.keys
|
||||||
|
|
||||||
|
private val classSymbol: FirClassSymbol<*>
|
||||||
|
get() = generationContext.owner
|
||||||
|
|
||||||
|
private fun generateMemberFunctions(name: Name): List<FirNamedFunctionSymbol> {
|
||||||
|
if (name == SpecialNames.INIT) return emptyList()
|
||||||
|
return extensionsByCallableName[name].orEmpty()
|
||||||
|
.flatMap { it.generateFunctions(CallableId(classSymbol.classId, name), generationContext) }
|
||||||
|
.onEach { it.fir.validate() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateMemberProperties(name: Name): List<FirPropertySymbol> {
|
||||||
|
if (name == SpecialNames.INIT) return emptyList()
|
||||||
|
return extensionsByCallableName[name].orEmpty()
|
||||||
|
.flatMap { it.generateProperties(CallableId(classSymbol.classId, name), generationContext) }
|
||||||
|
.onEach { it.fir.validate() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateConstructors(): List<FirConstructorSymbol> {
|
||||||
|
return extensionsByCallableName[SpecialNames.INIT].orEmpty()
|
||||||
|
.flatMap { it.generateConstructors(generationContext) }
|
||||||
|
.onEach { it.fir.validate() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ClassifierStorage(
|
||||||
|
cachesFactory: FirCachesFactory,
|
||||||
|
private val classSymbol: FirClassSymbol<*>,
|
||||||
|
private val generationContext: NestedClassGenerationContext,
|
||||||
|
private val extensionsByClassifierName: Map<Name, List<FirDeclarationGenerationExtension>>
|
||||||
|
) {
|
||||||
|
val classifiersCache: FirCache<Name, FirRegularClassSymbol?, Nothing?> =
|
||||||
|
cachesFactory.createCache { name -> generateNestedClassifier(name) }
|
||||||
|
|
||||||
|
val allClassifierNames: Set<Name>
|
||||||
|
get() = extensionsByClassifierName.keys
|
||||||
|
|
||||||
|
private fun generateNestedClassifier(name: Name): FirRegularClassSymbol? {
|
||||||
|
if (classSymbol is FirRegularClassSymbol) {
|
||||||
|
val companion = classSymbol.companionObjectSymbol
|
||||||
|
if (companion != null && companion.origin.generated && companion.classId.shortClassName == name) {
|
||||||
|
return companion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val extensions = extensionsByClassifierName[name] ?: return null
|
||||||
|
|
||||||
|
val generatedClasses = extensions.mapNotNull { extension ->
|
||||||
|
extension.generateNestedClassLikeDeclaration(classSymbol, name, generationContext)?.also { symbol ->
|
||||||
|
symbol.fir.ownerGenerator = extension
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val generatedClass = when (generatedClasses.size) {
|
||||||
|
0 -> return null
|
||||||
|
1 -> generatedClasses.first()
|
||||||
|
else -> error(
|
||||||
|
"""
|
||||||
|
Multiple plugins generated nested class with same name $name for class ${classSymbol.classId}:
|
||||||
|
${generatedClasses.joinToString("\n") { it.fir.render() }}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
require(generatedClass is FirRegularClassSymbol) { "Only regular class are allowed as nested classes" }
|
||||||
|
return generatedClass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun groupExtensionsByName(
|
||||||
|
classSymbol: FirClassSymbol<*>,
|
||||||
|
nameExtractor: FirDeclarationGenerationExtension.(FirClassSymbol<*>) -> Set<Name>,
|
||||||
|
): Map<Name, List<FirDeclarationGenerationExtension>> {
|
||||||
|
val extensions = getExtensionsForClass(classSymbol)
|
||||||
|
return extensions.flatGroupBy { it.nameExtractor(classSymbol) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getExtensionsForClass(classSymbol: FirClassSymbol<*>): List<FirDeclarationGenerationExtension> {
|
||||||
|
require(session === classSymbol.moduleData.session) {
|
||||||
|
"Class $classSymbol is declared in ${classSymbol.moduleData.session}, but generated storage for it taken from $session"
|
||||||
|
}
|
||||||
|
return if (classSymbol.origin.generated) {
|
||||||
|
listOf(classSymbol.fir.ownerGenerator!!)
|
||||||
|
} else {
|
||||||
|
session.extensionService.declarationGenerators
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val FirSession.generatedDeclarationsStorage: FirGeneratedMemberDeclarationsStorage by FirSession.sessionComponentAccessor()
|
||||||
|
|||||||
+8
@@ -69,4 +69,12 @@ class K2KotlinxSerializationIT : KGPBaseTest() {
|
|||||||
build(":compileTestKotlinJs")
|
build(":compileTestKotlinJs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DisplayName("Compile MPP project to JS kotlinx.serialization and K2")
|
||||||
|
@GradleTest
|
||||||
|
fun `test kotlinx serialization mpp to JS`(gradleVersion: GradleVersion) {
|
||||||
|
project("kotlinxSerializationMppK2", gradleVersion) {
|
||||||
|
build(":compileKotlinJs")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fun someSerializerCall() {
|
||||||
|
ValidateViolation.serializer()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user