From 3d560cd92cefa68862e7d04a2db5c5f2d22862b2 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 5 Jan 2024 10:29:37 +0100 Subject: [PATCH] K2: use correct scope for overrides calculation in ObjCName checker To call retrieveDirectOverriddenOf, one must use directly the owner scope of a callable symbol we consider, and not a scope of some derived class. #KT-64276 Fixed --- .../FirNativeObjCNameOverridesChecker.kt | 18 +++++++++++++----- .../kotlin/fir/scopes/FirTypeScope.kt | 16 ++++++++++++++++ .../diagnostics/nativeTests/objCName.fir.kt | 2 +- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameOverridesChecker.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameOverridesChecker.kt index 076b5299bdf..72fecbf69cd 100644 --- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameOverridesChecker.kt +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameOverridesChecker.kt @@ -15,9 +15,14 @@ import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCNameChecke import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass import org.jetbrains.kotlin.fir.isIntersectionOverride import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol -import org.jetbrains.kotlin.fir.scopes.* +import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.scopes.FirTypeScope +import org.jetbrains.kotlin.fir.scopes.processAllFunctions +import org.jetbrains.kotlin.fir.scopes.processAllProperties +import org.jetbrains.kotlin.fir.scopes.retrieveDirectOverriddenOf import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol object FirNativeObjCNameOverridesChecker : FirClassChecker() { @@ -44,7 +49,7 @@ object FirNativeObjCNameOverridesChecker : FirClassChecker() { ) { val overriddenSymbols = firTypeScope.retrieveDirectOverriddenOf(memberSymbol) if (overriddenSymbols.isEmpty()) return - val objCNames = overriddenSymbols.map { it.getFirstBaseSymbol(firTypeScope).getObjCNames(context.session) } + val objCNames = overriddenSymbols.map { it.getFirstBaseSymbol(context).getObjCNames(context.session) } if (!objCNames.allNamesEquals()) { val containingDeclarations = overriddenSymbols.mapNotNull { it.containingClassLookupTag()?.toFirRegularClassSymbol(context.session) @@ -59,9 +64,12 @@ object FirNativeObjCNameOverridesChecker : FirClassChecker() { } } - private fun FirCallableSymbol<*>.getFirstBaseSymbol(firTypeScope: FirTypeScope): FirCallableSymbol<*> { - val overriddenMemberSymbols = firTypeScope.retrieveDirectOverriddenOf(this) - return if (overriddenMemberSymbols.isEmpty()) this else overriddenMemberSymbols.first().getFirstBaseSymbol(firTypeScope) + private fun FirCallableSymbol<*>.getFirstBaseSymbol(context: CheckerContext): FirCallableSymbol<*> { + val session = context.session + val ownScope = containingClassLookupTag()?.toSymbol(session)?.fullyExpandedClass(session)?.unsubstitutedScope(context) + ?: return this + val overriddenMemberSymbols = ownScope.retrieveDirectOverriddenOf(this) + return if (overriddenMemberSymbols.isEmpty()) this else overriddenMemberSymbols.first().getFirstBaseSymbol(context) } private fun List>.allNamesEquals(): Boolean { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirTypeScope.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirTypeScope.kt index db458d063dc..8c48df88ca2 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirTypeScope.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirTypeScope.kt @@ -281,6 +281,22 @@ fun FirTypeScope.getDirectOverriddenProperties( return overriddenProperties.toList() } +/** + * Provides a list of callables which are directly overridden by the given symbol + * + * Please be very accurate with using this function. + * It can be convenient if the only thing you need is to get directly overridden symbols and nothing more, + * but even in this case please check that you are using a correct scope. + * E.g. if you want to get overridden symbols of some Foo.bar, + * the scope in use must be built from the Foo-based type or Foo class itself. + * + * If you need to traverse some complex overridden hierarchy, + * please consider using processDirectOverriddenFunctions(Properties)WithBaseScope instead. + * + * @param memberSymbol A callable symbol to find its directly overridden symbols + * @receiver Must be an owner scope of the callable symbol to work properly + * @return A list of callable symbols which are directly overridden by the given symbol + */ fun FirTypeScope.retrieveDirectOverriddenOf(memberSymbol: FirCallableSymbol<*>): List> { return when (memberSymbol) { is FirNamedFunctionSymbol -> { diff --git a/compiler/testData/diagnostics/nativeTests/objCName.fir.kt b/compiler/testData/diagnostics/nativeTests/objCName.fir.kt index e9bffaa3b89..87381044352 100644 --- a/compiler/testData/diagnostics/nativeTests/objCName.fir.kt +++ b/compiler/testData/diagnostics/nativeTests/objCName.fir.kt @@ -195,7 +195,7 @@ interface DerivedI1 : I1 { override fun foo() } -abstract class KT64276 : Base(), DerivedI1 {} +abstract class KT64276 : Base(), DerivedI1 {} private const val exact = false private const val objcName = "nonLiteralArgsObjC"