[FIR] Fix visibility issues with private members within inner and anonymous scopes ^KT-49992 Fixed

This commit is contained in:
Ivan Kochurkin
2021-12-01 16:57:27 +03:00
committed by Space
parent 800d594a4f
commit f68c8f8f01
11 changed files with 390 additions and 35 deletions
@@ -6,17 +6,17 @@
package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
@@ -140,6 +140,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
): Boolean {
val symbol = declaration.symbol
val provider = session.firProvider
return when (declaration.visibility) {
Visibilities.Internal -> {
declaration.moduleData == session.moduleData || session.moduleVisibilityChecker?.isInFriendModule(declaration) == true
@@ -168,7 +169,13 @@ abstract class FirVisibilityChecker : FirSessionComponent {
}
else -> {
// Member: visible inside parent class, including all its member classes
canSeePrivateMemberOf(containingDeclarations, ownerLookupTag, session)
canSeePrivateMemberOf(
containingDeclarations,
ownerLookupTag,
dispatchReceiver,
isVariableOrNamedFunction = symbol.isVariableOrNamedFunction(),
session
)
}
}
} else {
@@ -180,7 +187,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
val ownerId = symbol.getOwnerLookupTag()
ownerId != null && canSeeProtectedMemberOf(
containingDeclarations, dispatchReceiver, ownerId, session,
isVariableOrNamedFunction = symbol is FirVariableSymbol || symbol is FirNamedFunctionSymbol || symbol is FirPropertyAccessorSymbol,
isVariableOrNamedFunction = symbol.isVariableOrNamedFunction(),
symbol.fir is FirSyntheticPropertyAccessor,
supertypeSupplier
)
@@ -213,21 +220,76 @@ abstract class FirVisibilityChecker : FirSessionComponent {
private fun canSeePrivateMemberOf(
containingDeclarationOfUseSite: List<FirDeclaration>,
ownerLookupTag: ConeClassLikeLookupTag,
dispatchReceiver: ReceiverValue?,
isVariableOrNamedFunction: Boolean,
session: FirSession
): Boolean {
ownerLookupTag.ownerIfCompanion(session)?.let { companionOwnerLookupTag ->
return canSeePrivateMemberOf(containingDeclarationOfUseSite, companionOwnerLookupTag, session)
return canSeePrivateMemberOf(
containingDeclarationOfUseSite,
companionOwnerLookupTag,
dispatchReceiver,
isVariableOrNamedFunction,
session
)
}
for (declaration in containingDeclarationOfUseSite) {
if (declaration !is FirClass) continue
val boundSymbol = declaration.symbol
if (boundSymbol.classId.isSame(ownerLookupTag.classId)) {
return true
fun matchWithContainingDeclarations(): Boolean {
for (declaration in containingDeclarationOfUseSite) {
if (declaration !is FirClass) continue
val boundSymbol = declaration.symbol
if (boundSymbol.classId.isSame(ownerLookupTag.classId)) {
return true
}
}
return false
}
return false
return if (isVariableOrNamedFunction && dispatchReceiver?.type is ConeClassLikeType) {
if (dispatchReceiver is ImplicitDispatchReceiverValue) {
val dispatchReceiverOwnerClassId = dispatchReceiver.ownerIfCompanion(session)?.classId ?: dispatchReceiver.type.classId
var isMemberFound = false
for (declaration in containingDeclarationOfUseSite) {
if (declaration !is FirClass) continue
val boundSymbol = declaration.symbol
var isSameClasses = false
if (!isMemberFound) {
isSameClasses = boundSymbol.classId.isSame(ownerLookupTag.classId)
if (isSameClasses) {
isMemberFound = true
}
}
if (isMemberFound) {
if (!isSameClasses && !(
declaration.isInner ||
(declaration.containingNonLocalClass(session) as? FirRegularClass)?.classKind == ClassKind.OBJECT)
) {
// It should not be ordinary classes between use site and declaration
return false
}
if (boundSymbol.classId.isSame(dispatchReceiverOwnerClassId!!)) {
return true
}
}
}
isMemberFound
} else {
val receiverExpression = dispatchReceiver.receiverExpression
if (receiverExpression is FirThisReceiverExpression &&
receiverExpression.source != null &&
(containingDeclarationOfUseSite.lastOrNull() as? FirFunction)?.symbol?.isExtension != true
) {
// Processing of explicit no extension `this`
val dispatchReceiverOwnerClassId = dispatchReceiver.ownerIfCompanion(session)?.classId ?: dispatchReceiver.type.classId
dispatchReceiverOwnerClassId?.isSame(ownerLookupTag.classId) == true
} else {
matchWithContainingDeclarations()
}
}
} else {
matchWithContainingDeclarations()
}
}
// 'local' isn't taken into account here
@@ -350,7 +412,14 @@ abstract class FirVisibilityChecker : FirSessionComponent {
isSyntheticProperty: Boolean,
supertypeSupplier: SupertypeSupplier
): Boolean {
if (canSeePrivateMemberOf(containingDeclarationOfUseSite, ownerLookupTag, session)) return true
if (canSeePrivateMemberOf(
containingDeclarationOfUseSite,
ownerLookupTag,
dispatchReceiver,
isVariableOrNamedFunction,
session
)
) return true
for (containingDeclaration in containingDeclarationOfUseSite) {
if (containingDeclaration is FirClass) {
@@ -405,3 +474,7 @@ fun FirBasedSymbol<*>.getOwnerLookupTag(): ConeClassLikeLookupTag? {
else -> error("Unsupported owner search for ${fir.javaClass}: ${fir.render()}")
}
}
fun FirBasedSymbol<*>.isVariableOrNamedFunction(): Boolean {
return this is FirVariableSymbol || this is FirNamedFunctionSymbol || this is FirPropertyAccessorSymbol
}