From 4ee03a3a0c07f16026ff55c6e2055d219c9de74b Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Fri, 26 Jan 2024 12:41:53 +0200 Subject: [PATCH] [FIR] Allow accessing protected members via local inheritors ^KT-65058 Fixed --- .../FirInlineBodyResolvedQualifierChecker.kt | 4 ++- .../FirInlineDeclarationChecker.kt | 25 ++++++++++++++----- .../tests/callingProtectedFromInline.fir.kt | 12 --------- .../tests/callingProtectedFromInline.kt | 1 + 4 files changed, 23 insertions(+), 19 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/callingProtectedFromInline.fir.kt diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineBodyResolvedQualifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineBodyResolvedQualifierChecker.kt index adc276bc393..2d20d64bcf5 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineBodyResolvedQualifierChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineBodyResolvedQualifierChecker.kt @@ -19,7 +19,9 @@ object FirInlineBodyResolvedQualifierChecker : FirResolvedQualifierChecker(MppCh val accessedClass = expression.symbol ?: return val source = expression.source ?: return if (accessedClass.isCompanion) { - inlineFunctionBodyContext.checkAccessedDeclaration(source, accessedClass, accessedClass.visibility, context, reporter) + inlineFunctionBodyContext.checkAccessedDeclaration( + source, expression, accessedClass, accessedClass.visibility, context, reporter, + ) } } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt index 85c955447eb..cf12bd76403 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor +import org.jetbrains.kotlin.types.model.typeConstructor import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled @@ -65,6 +66,7 @@ object FirInlineDeclarationChecker : FirFunctionChecker(MppCheckerKind.Common) { internal fun checkAccessedDeclaration( source: KtSourceElement, + accessExpression: FirStatement, accessedSymbol: FirBasedSymbol<*>, declarationVisibility: Visibility, context: CheckerContext, @@ -76,12 +78,10 @@ object FirInlineDeclarationChecker : FirFunctionChecker(MppCheckerKind.Common) { else -> shouldNotBeCalled() } - val accessedDeclarationEffectiveVisibility = recordedEffectiveVisibility.let { - if (it == EffectiveVisibility.Local) { - EffectiveVisibility.Public - } else { - it - } + val accessedDeclarationEffectiveVisibility = when { + recordedEffectiveVisibility.isReachableDueToLocalDispatchReceiver(accessExpression, context) -> EffectiveVisibility.Public + recordedEffectiveVisibility == EffectiveVisibility.Local -> EffectiveVisibility.Public + else -> recordedEffectiveVisibility } val isCalledFunPublicOrPublishedApi = accessedDeclarationEffectiveVisibility.publicApi val isInlineFunPublicOrPublishedApi = inlineFunEffectiveVisibility.publicApi @@ -106,6 +106,18 @@ object FirInlineDeclarationChecker : FirFunctionChecker(MppCheckerKind.Common) { ) } + private fun EffectiveVisibility.isReachableDueToLocalDispatchReceiver(access: FirStatement, context: CheckerContext): Boolean { + val receiverType = access.localDispatchReceiver(context) ?: return false + val receiverProtected = EffectiveVisibility.Protected(receiverType.typeConstructor(context.session.typeContext)) + val relation = receiverProtected.relation(this, context.session.typeContext) + return relation == EffectiveVisibility.Permissiveness.SAME || relation == EffectiveVisibility.Permissiveness.LESS + } + + private fun FirStatement.localDispatchReceiver(context: CheckerContext): ConeKotlinType? = + (this as? FirQualifiedAccessExpression)?.dispatchReceiver?.resolvedType?.takeIf { + (it.toSymbol(context.session) as? FirClassLikeSymbol<*>)?.effectiveVisibility == EffectiveVisibility.Local + } + internal data class AccessedDeclarationVisibilityData( val isInlineFunPublicOrPublishedApi: Boolean, val isCalledFunPublicOrPublishedApi: Boolean, @@ -239,6 +251,7 @@ object FirInlineDeclarationChecker : FirFunctionChecker(MppCheckerKind.Common) { } val (isInlineFunPublicOrPublishedApi, isCalledFunPublicOrPublishedApi, calledFunEffectiveVisibility) = checkAccessedDeclaration( source, + accessExpression, calledDeclaration, calledDeclaration.visibility, context, diff --git a/compiler/testData/diagnostics/tests/callingProtectedFromInline.fir.kt b/compiler/testData/diagnostics/tests/callingProtectedFromInline.fir.kt deleted file mode 100644 index 2df665baa6b..00000000000 --- a/compiler/testData/diagnostics/tests/callingProtectedFromInline.fir.kt +++ /dev/null @@ -1,12 +0,0 @@ -// ISSUE: KT-65058 - -open class A { - protected fun foo() { - } -} - -inline fun bar() = object : A() { - fun baz() { - foo() - } -} diff --git a/compiler/testData/diagnostics/tests/callingProtectedFromInline.kt b/compiler/testData/diagnostics/tests/callingProtectedFromInline.kt index dd426a7b549..bfe9a97c751 100644 --- a/compiler/testData/diagnostics/tests/callingProtectedFromInline.kt +++ b/compiler/testData/diagnostics/tests/callingProtectedFromInline.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // ISSUE: KT-65058 open class A {