[FIR] Check conflicting overloads via scopes

Scopes may return private symbols from
supertypes, they should not clash with
symbols from the current class.

For example, see:
`FirLightTreeBlackBoxCodegenWithIrFakeOverrideGeneratorTestGenerated.FakeOverride#testPrivateFakeOverrides1`

Lombok shouldn't generate functions if the
user has defined explicit ones.

In K1 generated functions are not really
added to the declared members scope.

^KT-61243 Fixed
This commit is contained in:
Nikolay Lunyak
2023-09-20 16:52:32 +03:00
committed by Space Team
parent 973248f432
commit 4e58715760
24 changed files with 278 additions and 129 deletions
@@ -18,6 +18,8 @@ import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
import org.jetbrains.kotlin.fir.java.declarations.buildJavaMethod
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.scopes.collectAllFunctions
import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
@@ -37,26 +39,30 @@ class GetterGenerator(session: FirSession) : FirDeclarationGenerationExtension(s
private val lombokService: LombokService
get() = session.lombokService
private val cache: FirCache<FirClassSymbol<*>, Map<Name, FirJavaMethod>?, Nothing?> =
session.firCachesFactory.createCache(::createGetters)
private val cache: FirCache<Pair<FirClassSymbol<*>, FirClassDeclaredMemberScope?>, Map<Name, FirJavaMethod>?, Nothing?> =
session.firCachesFactory.createCache(uncurry(::createGetters))
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>, context: MemberGenerationContext): Set<Name> {
if (!classSymbol.isSuitableJavaClass()) return emptySet()
return cache.getValue(classSymbol)?.keys ?: emptySet()
return cache.getValue(classSymbol to context.declaredScope)?.keys ?: emptySet()
}
override fun generateFunctions(callableId: CallableId, context: MemberGenerationContext?): List<FirNamedFunctionSymbol> {
val owner = context?.owner
if (owner == null || !owner.isSuitableJavaClass()) return emptyList()
val getter = cache.getValue(owner)?.get(callableId.callableName) ?: return emptyList()
val getter = cache.getValue(owner to context.declaredScope)?.get(callableId.callableName) ?: return emptyList()
return listOf(getter.symbol)
}
private fun createGetters(classSymbol: FirClassSymbol<*>): Map<Name, FirJavaMethod>? {
private fun createGetters(classSymbol: FirClassSymbol<*>, declaredScope: FirClassDeclaredMemberScope?): Map<Name, FirJavaMethod>? {
val fieldsWithGetter = computeFieldsWithGetter(classSymbol) ?: return null
val globalAccessors = lombokService.getAccessors(classSymbol)
val explicitlyDeclaredFunctions = declaredScope?.collectAllFunctions()?.associateBy { it.name }.orEmpty()
return fieldsWithGetter.mapNotNull { (field, getterInfo) ->
val getterName = computeGetterName(field, getterInfo, globalAccessors) ?: return@mapNotNull null
if (explicitlyDeclaredFunctions[getterName]?.valueParameterSymbols?.isEmpty() == true) {
return@mapNotNull null
}
val function = buildJavaMethod {
moduleData = field.moduleData
returnTypeRef = field.returnTypeRef
@@ -20,6 +20,8 @@ import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
import org.jetbrains.kotlin.fir.java.declarations.buildJavaMethod
import org.jetbrains.kotlin.fir.java.declarations.buildJavaValueParameter
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.scopes.collectAllFunctions
import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
@@ -40,18 +42,18 @@ class SetterGenerator(session: FirSession) : FirDeclarationGenerationExtension(s
private val lombokService: LombokService
get() = session.lombokService
private val cache: FirCache<FirClassSymbol<*>, Map<Name, FirJavaMethod>?, Nothing?> =
session.firCachesFactory.createCache(::createSetters)
private val cache: FirCache<Pair<FirClassSymbol<*>, FirClassDeclaredMemberScope?>, Map<Name, FirJavaMethod>?, Nothing?> =
session.firCachesFactory.createCache(uncurry(::createSetters))
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>, context: MemberGenerationContext): Set<Name> {
if (!classSymbol.isSuitableForSetters()) return emptySet()
return cache.getValue(classSymbol)?.keys ?: emptySet()
return cache.getValue(classSymbol to context.declaredScope)?.keys ?: emptySet()
}
override fun generateFunctions(callableId: CallableId, context: MemberGenerationContext?): List<FirNamedFunctionSymbol> {
val owner = context?.owner
if (owner == null || !owner.isSuitableForSetters()) return emptyList()
val getter = cache.getValue(owner)?.get(callableId.callableName) ?: return emptyList()
val getter = cache.getValue(owner to context.declaredScope)?.get(callableId.callableName) ?: return emptyList()
return listOf(getter.symbol)
}
@@ -59,12 +61,17 @@ class SetterGenerator(session: FirSession) : FirDeclarationGenerationExtension(s
return isSuitableJavaClass() && classKind != ClassKind.ENUM_CLASS
}
private fun createSetters(classSymbol: FirClassSymbol<*>): Map<Name, FirJavaMethod>? {
private fun createSetters(classSymbol: FirClassSymbol<*>, declaredScope: FirClassDeclaredMemberScope?): Map<Name, FirJavaMethod>? {
val fieldsWithSetter = computeFieldsWithSetters(classSymbol) ?: return null
val globalAccessors = lombokService.getAccessors(classSymbol)
val explicitlyDeclaredFunctions = declaredScope?.collectAllFunctions()?.associateBy { it.name }.orEmpty()
return fieldsWithSetter.mapNotNull { (field, setterInfo) ->
val accessors = lombokService.getAccessorsIfAnnotated(field.symbol) ?: globalAccessors
val setterName = computeSetterName(field, setterInfo, accessors) ?: return@mapNotNull null
val existing = explicitlyDeclaredFunctions[setterName]
if (existing != null && existing.valueParameterSymbols.size == 1) {
return@mapNotNull null
}
val function = buildJavaMethod {
moduleData = field.moduleData
returnTypeRef = if (accessors.chain) {
@@ -81,3 +81,5 @@ private fun sameSignature(a: FirFunction, b: FirFunction): Boolean {
bVararg && aSize >= (bSize - 1) ||
aSize == bSize
}
internal inline fun <A, B, C> uncurry(crossinline f: (A, B) -> C): (Pair<A, B>) -> C = { (a, b) -> f(a, b) }