[FIR] Change scheme of generating declarations by plugins

Methods `needToGenerateAdditionalMembersInClass` and
  `needToGenerateNestedClassifiersInClass` are removed, now compiler
  uses `get...Names` and `getTopLevel...` methods to determine which
  extension may generate declaration with specific classId/callableId

This is needed to simplify API of FirDeclarationGenerationExtension and
  provide guarantee that `generate...` method will be called with
  specific classId/callableId only if specific extensions returned name
  for this id from `getName...` functions
This commit is contained in:
Dmitriy Novozhilov
2021-11-15 12:57:26 +03:00
committed by teamcityserver
parent 40d8451698
commit cb0705ec03
25 changed files with 388 additions and 228 deletions
@@ -1,107 +0,0 @@
/*
* Copyright 2010-2021 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.fir.extensions
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
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.declarations.validate
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class FirExtensionDeclarationsSymbolProvider private constructor(
session: FirSession,
cachesFactory: FirCachesFactory,
private val extensions: List<FirDeclarationGenerationExtension>
) : FirSymbolProvider(session), FirSessionComponent {
companion object {
fun create(session: FirSession): FirExtensionDeclarationsSymbolProvider? {
val extensions = session.extensionService.declarationGenerators
if (extensions.isEmpty()) return null
return FirExtensionDeclarationsSymbolProvider(session, session.firCachesFactory, extensions)
}
}
// ------------------------------------------ caches ------------------------------------------
private val classCache: FirCache<ClassId, FirClassLikeSymbol<*>?, Nothing?> = cachesFactory.createCache { classId, _ ->
generateClassLikeDeclaration(classId)
}
private val functionCache: FirCache<CallableId, List<FirNamedFunctionSymbol>, Nothing?> = cachesFactory.createCache { callableId, _ ->
generateTopLevelFunctions(callableId)
}
private val propertyCache: FirCache<CallableId, List<FirPropertySymbol>, Nothing?> = cachesFactory.createCache { callableId, _ ->
generateTopLevelProperties(callableId)
}
private val packageCache: FirCache<FqName, Boolean, Nothing?> = cachesFactory.createCache { packageFqName, _ ->
hasPackage(packageFqName)
}
// ------------------------------------------ generators ------------------------------------------
private fun generateClassLikeDeclaration(classId: ClassId): FirClassLikeSymbol<*>? {
val generatedClasses = extensions.mapNotNull { it.generateClassLikeDeclaration(classId) }.onEach { it.fir.validate() }
return when (generatedClasses.size) {
0 -> null
1 -> generatedClasses.first()
else -> error("Multiple plugins generated classes with same classId $classId\n${generatedClasses.joinToString("\n") { it.fir.render() }}")
}
}
private fun generateTopLevelFunctions(callableId: CallableId): List<FirNamedFunctionSymbol> {
return extensions.flatMap { it.generateFunctions(callableId, owner = null) }.onEach { it.fir.validate() }
}
private fun generateTopLevelProperties(callableId: CallableId): List<FirPropertySymbol> {
return extensions.flatMap { it.generateProperties(callableId, owner = null) }.onEach { it.fir.validate() }
}
private fun hasPackage(packageFqName: FqName): Boolean {
return extensions.any { it.hasPackage(packageFqName) }
}
// ------------------------------------------ provider methods ------------------------------------------
override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? {
return classCache.getValue(classId)
}
@FirSymbolProviderInternals
override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
val callableId = CallableId(packageFqName, name)
destination += functionCache.getValue(callableId)
destination += propertyCache.getValue(callableId)
}
@FirSymbolProviderInternals
override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) {
destination += functionCache.getValue(CallableId(packageFqName, name))
}
@FirSymbolProviderInternals
override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name) {
destination += propertyCache.getValue(CallableId(packageFqName, name))
}
override fun getPackage(fqName: FqName): FqName? {
return fqName.takeIf { packageCache.getValue(fqName, null) }
}
}
val FirSession.generatedDeclarationsSymbolProvider: FirExtensionDeclarationsSymbolProvider? by FirSession.nullableSessionComponentAccessor()
@@ -13,7 +13,11 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer
@RequiresOptIn(message = "Should be used just only in resolve processor")
annotation class AdapterForResolveProcessor
sealed class FirResolveProcessor(val session: FirSession, val scopeSession: ScopeSession)
sealed class FirResolveProcessor(val session: FirSession, val scopeSession: ScopeSession) {
open fun beforePhase() {}
open fun afterPhase() {}
}
abstract class FirGlobalResolveProcessor(session: FirSession, scopeSession: ScopeSession) : FirResolveProcessor(session, scopeSession) {
abstract fun process(files: Collection<FirFile>)
@@ -22,6 +22,7 @@ class FirTotalResolveProcessor(session: FirSession, enablePluginPhases: Boolean
fun process(files: List<FirFile>) {
for (processor in processors) {
processor.beforePhase()
when (processor) {
is FirTransformerBasedResolveProcessor -> {
for (file in files) {
@@ -32,6 +33,7 @@ class FirTotalResolveProcessor(session: FirSession, enablePluginPhases: Boolean
processor.process(files)
}
}
processor.afterPhase()
}
}
}
@@ -22,11 +22,25 @@ import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.extensions.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.fqName
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
import org.jetbrains.kotlin.fir.resolve.transformers.*
import org.jetbrains.kotlin.name.FqName
class FirPluginAnnotationsResolveProcessor(session: FirSession, scopeSession: ScopeSession) : FirTransformerBasedResolveProcessor(session, scopeSession) {
class FirPluginAnnotationsResolveProcessor(
session: FirSession,
scopeSession: ScopeSession
) : FirTransformerBasedResolveProcessor(session, scopeSession) {
override val transformer = FirPluginAnnotationsResolveTransformer(session, scopeSession)
@OptIn(FirSymbolProviderInternals::class)
override fun beforePhase() {
session.generatedDeclarationsSymbolProvider?.disable()
}
@OptIn(FirSymbolProviderInternals::class)
override fun afterPhase() {
session.generatedDeclarationsSymbolProvider?.enable()
}
}
class FirPluginAnnotationsResolveTransformer(