[FIR] Allow accessing protected members via local inheritors

^KT-65058 Fixed
This commit is contained in:
Nikolay Lunyak
2024-01-26 12:41:53 +02:00
committed by Space Team
parent b6e913cde7
commit 4ee03a3a0c
4 changed files with 23 additions and 19 deletions
@@ -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,
)
}
}
}
@@ -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,
@@ -1,12 +0,0 @@
// ISSUE: KT-65058
open class A {
protected fun foo() {
}
}
<!NOTHING_TO_INLINE!>inline<!> fun bar() = object : A() {
fun baz() {
<!PROTECTED_CALL_FROM_PUBLIC_INLINE_ERROR!>foo<!>()
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// ISSUE: KT-65058
open class A {