FIR: use lookup tag instead of class id in visibility checker

This commit is contained in:
Mikhail Glukhikh
2021-08-30 17:17:42 +03:00
committed by TeamCityServer
parent 08e498f1f2
commit a14a00809f
2 changed files with 45 additions and 56 deletions
@@ -29,9 +29,9 @@ object FirJavaVisibilityChecker : FirVisibilityChecker() {
if (symbol.packageFqName() == useSiteFile.packageFqName) { if (symbol.packageFqName() == useSiteFile.packageFqName) {
true true
} else { } else {
val ownerId = symbol.getOwnerId() val ownerLookupTag = symbol.getOwnerLookupTag()
ownerId != null && canSeeProtectedMemberOf( ownerLookupTag != null && canSeeProtectedMemberOf(
containingDeclarations, dispatchReceiver, ownerId, session, containingDeclarations, dispatchReceiver, ownerLookupTag, session,
isVariableOrNamedFunction = symbol is FirVariableSymbol || symbol is FirNamedFunctionSymbol isVariableOrNamedFunction = symbol is FirVariableSymbol || symbol is FirNamedFunctionSymbol
) )
} }
@@ -16,11 +16,13 @@ import org.jetbrains.kotlin.fir.resolve.calls.Candidate
import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.AbstractTypeChecker
abstract class FirModuleVisibilityChecker : FirSessionComponent { abstract class FirModuleVisibilityChecker : FirSessionComponent {
abstract fun <T> isInFriendModule(declaration: T): Boolean where T : FirMemberDeclaration, T : FirDeclaration abstract fun <T> isInFriendModule(declaration: T): Boolean where T : FirMemberDeclaration, T : FirDeclaration
@@ -81,10 +83,10 @@ abstract class FirVisibilityChecker : FirSessionComponent {
declaration.moduleData == session.moduleData || session.moduleVisibilityChecker?.isInFriendModule(declaration) == true declaration.moduleData == session.moduleData || session.moduleVisibilityChecker?.isInFriendModule(declaration) == true
} }
Visibilities.Private, Visibilities.PrivateToThis -> { Visibilities.Private, Visibilities.PrivateToThis -> {
val ownerId = symbol.getOwnerId() val ownerLookupTag = symbol.getOwnerLookupTag()
if (declaration.moduleData == session.moduleData) { if (declaration.moduleData == session.moduleData) {
when { when {
ownerId == null -> { ownerLookupTag == null -> {
val candidateFile = when (symbol) { val candidateFile = when (symbol) {
is FirSyntheticFunctionSymbol -> { is FirSyntheticFunctionSymbol -> {
// SAM case // SAM case
@@ -104,7 +106,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
} }
else -> { else -> {
// Member: visible inside parent class, including all its member classes // Member: visible inside parent class, including all its member classes
canSeePrivateMemberOf(containingDeclarations, ownerId, session) canSeePrivateMemberOf(containingDeclarations, ownerLookupTag, session)
} }
} }
} else { } else {
@@ -113,7 +115,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
} }
Visibilities.Protected -> { Visibilities.Protected -> {
val ownerId = symbol.getOwnerId() val ownerId = symbol.getOwnerLookupTag()
ownerId != null && canSeeProtectedMemberOf( ownerId != null && canSeeProtectedMemberOf(
containingDeclarations, dispatchReceiver, ownerId, session, containingDeclarations, dispatchReceiver, ownerId, session,
isVariableOrNamedFunction = symbol is FirVariableSymbol || symbol is FirNamedFunctionSymbol isVariableOrNamedFunction = symbol is FirVariableSymbol || symbol is FirNamedFunctionSymbol
@@ -142,17 +144,17 @@ abstract class FirVisibilityChecker : FirSessionComponent {
private fun canSeePrivateMemberOf( private fun canSeePrivateMemberOf(
containingDeclarationOfUseSite: List<FirDeclaration>, containingDeclarationOfUseSite: List<FirDeclaration>,
ownerId: ClassId, ownerLookupTag: ConeClassLikeLookupTag,
session: FirSession session: FirSession
): Boolean { ): Boolean {
ownerId.ownerIfCompanion(session)?.let { companionOwnerClassId -> ownerLookupTag.ownerIfCompanion(session)?.let { companionOwnerLookupTag ->
return canSeePrivateMemberOf(containingDeclarationOfUseSite, companionOwnerClassId, session) return canSeePrivateMemberOf(containingDeclarationOfUseSite, companionOwnerLookupTag, session)
} }
for (declaration in containingDeclarationOfUseSite) { for (declaration in containingDeclarationOfUseSite) {
if (declaration !is FirClass) continue if (declaration !is FirClass) continue
val boundSymbol = declaration.symbol val boundSymbol = declaration.symbol
if (boundSymbol.classId.isSame(ownerId)) { if (boundSymbol.classId.isSame(ownerLookupTag.classId)) {
return true return true
} }
} }
@@ -164,26 +166,30 @@ abstract class FirVisibilityChecker : FirSessionComponent {
private fun ClassId.isSame(other: ClassId): Boolean = private fun ClassId.isSame(other: ClassId): Boolean =
packageFqName == other.packageFqName && relativeClassName == other.relativeClassName packageFqName == other.packageFqName && relativeClassName == other.relativeClassName
private fun ClassId.ownerIfCompanion(session: FirSession): ClassId? { private fun ConeClassLikeLookupTag.ownerIfCompanion(session: FirSession): ConeClassLikeLookupTag? {
if (outerClassId == null || isLocal) return null if (classId.isLocal) return null
val ownerSymbol = session.symbolProvider.getClassLikeSymbolByFqName(this) as? FirRegularClassSymbol val outerClassId = classId.outerClassId ?: return null
val ownerSymbol = toSymbol(session) as? FirRegularClassSymbol
return outerClassId.takeIf { ownerSymbol?.fir?.isCompanion == true } if (ownerSymbol?.fir?.isCompanion == true) {
return ConeClassLikeLookupTagImpl(outerClassId)
}
return null
} }
private fun canSeeProtectedMemberOf( private fun canSeeProtectedMemberOf(
containingUseSiteClass: FirClass, containingUseSiteClass: FirClass,
dispatchReceiver: ReceiverValue?, dispatchReceiver: ReceiverValue?,
ownerId: ClassId, ownerLookupTag: ConeClassLikeLookupTag,
session: FirSession, session: FirSession,
isVariableOrNamedFunction: Boolean isVariableOrNamedFunction: Boolean
): Boolean { ): Boolean {
dispatchReceiver?.ownerIfCompanion(session)?.let { companionOwnerClassId -> dispatchReceiver?.ownerIfCompanion(session)?.let { companionOwnerLookupTag ->
if (containingUseSiteClass.isSubClass(companionOwnerClassId, session)) return true if (containingUseSiteClass.isSubClass(companionOwnerLookupTag, session)) return true
} }
return when { return when {
!containingUseSiteClass.isSubClass(ownerId, session) -> false !containingUseSiteClass.isSubClass(ownerLookupTag, session) -> false
isVariableOrNamedFunction -> doesReceiverFitForProtectedVisibility(dispatchReceiver, containingUseSiteClass, session) isVariableOrNamedFunction -> doesReceiverFitForProtectedVisibility(dispatchReceiver, containingUseSiteClass, session)
else -> true else -> true
} }
@@ -203,40 +209,25 @@ abstract class FirVisibilityChecker : FirSessionComponent {
dispatchReceiverType = explicitReceiver.dispatchReceiver.typeRef.coneType dispatchReceiverType = explicitReceiver.dispatchReceiver.typeRef.coneType
} }
} }
return dispatchReceiverType.fullyExpandedType(session).isSubtypeOfClass(containingUseSiteClass.classId, session) val typeCheckerState = session.typeContext.newTypeCheckerState(
errorTypesEqualToAnything = false,
stubTypesEqualToAnything = false
)
return AbstractTypeChecker.isSubtypeOf(
typeCheckerState, dispatchReceiverType.fullyExpandedType(session), containingUseSiteClass.defaultType()
)
} }
private fun ConeKotlinType.isSubtypeOfClass(ownerId: ClassId, session: FirSession): Boolean { private fun FirClass.isSubClass(ownerLookupTag: ConeClassLikeLookupTag, session: FirSession): Boolean {
return when (this) { if (classId.isSame(ownerLookupTag.classId)) return true
is ConeClassLikeType -> {
val dispatchReceiverClass = lookupTag.toSymbol(session)?.fir as? FirClass
dispatchReceiverClass?.isSubClass(ownerId, session) == true
}
is ConeTypeParameterType -> {
this.lookupTag.typeParameterSymbol.fir.bounds.any {
it.coneType.isSubtypeOfClass(ownerId, session)
}
}
is ConeFlexibleType -> {
lowerBound.isSubtypeOfClass(ownerId, session)
}
is ConeDefinitelyNotNullType -> {
original.isSubtypeOfClass(ownerId, session)
}
else -> false
}
}
private fun FirClass.isSubClass(ownerId: ClassId, session: FirSession): Boolean {
if (classId.isSame(ownerId)) return true
return lookupSuperTypes(this, lookupInterfaces = true, deep = true, session).any { superType -> return lookupSuperTypes(this, lookupInterfaces = true, deep = true, session).any { superType ->
(superType as? ConeClassLikeType)?.fullyExpandedType(session)?.lookupTag?.classId?.isSame(ownerId) == true (superType as? ConeClassLikeType)?.fullyExpandedType(session)?.lookupTag?.classId?.isSame(ownerLookupTag.classId) == true
} }
} }
private fun ReceiverValue?.ownerIfCompanion(session: FirSession): ClassId? = private fun ReceiverValue?.ownerIfCompanion(session: FirSession): ConeClassLikeLookupTag? =
(this?.type as? ConeClassLikeType)?.lookupTag?.classId?.ownerIfCompanion(session) (this?.type as? ConeClassLikeType)?.lookupTag?.ownerIfCompanion(session)
// monitorEnter/monitorExit are the only functions which are accessed "illegally" (see kotlin/util/Synchronized.kt). // monitorEnter/monitorExit are the only functions which are accessed "illegally" (see kotlin/util/Synchronized.kt).
// Since they are intrinsified in the codegen, FIR should treat it as visible. // Since they are intrinsified in the codegen, FIR should treat it as visible.
@@ -251,16 +242,16 @@ abstract class FirVisibilityChecker : FirSessionComponent {
protected fun canSeeProtectedMemberOf( protected fun canSeeProtectedMemberOf(
containingDeclarationOfUseSite: List<FirDeclaration>, containingDeclarationOfUseSite: List<FirDeclaration>,
dispatchReceiver: ReceiverValue?, dispatchReceiver: ReceiverValue?,
ownerId: ClassId, ownerLookupTag: ConeClassLikeLookupTag,
session: FirSession, session: FirSession,
isVariableOrNamedFunction: Boolean isVariableOrNamedFunction: Boolean
): Boolean { ): Boolean {
if (canSeePrivateMemberOf(containingDeclarationOfUseSite, ownerId, session)) return true if (canSeePrivateMemberOf(containingDeclarationOfUseSite, ownerLookupTag, session)) return true
for (containingDeclaration in containingDeclarationOfUseSite) { for (containingDeclaration in containingDeclarationOfUseSite) {
if (containingDeclaration !is FirClass) continue if (containingDeclaration !is FirClass) continue
val boundSymbol = containingDeclaration.symbol val boundSymbol = containingDeclaration.symbol
if (canSeeProtectedMemberOf(boundSymbol.fir, dispatchReceiver, ownerId, session, isVariableOrNamedFunction)) return true if (canSeeProtectedMemberOf(boundSymbol.fir, dispatchReceiver, ownerLookupTag, session, isVariableOrNamedFunction)) return true
} }
return false return false
@@ -278,19 +269,17 @@ abstract class FirVisibilityChecker : FirSessionComponent {
val FirSession.moduleVisibilityChecker: FirModuleVisibilityChecker? by FirSession.nullableSessionComponentAccessor() val FirSession.moduleVisibilityChecker: FirModuleVisibilityChecker? by FirSession.nullableSessionComponentAccessor()
val FirSession.visibilityChecker: FirVisibilityChecker by FirSession.sessionComponentAccessor() val FirSession.visibilityChecker: FirVisibilityChecker by FirSession.sessionComponentAccessor()
fun FirBasedSymbol<*>.getOwnerId(): ClassId? { fun FirBasedSymbol<*>.getOwnerLookupTag(): ConeClassLikeLookupTag? {
return when (this) { return when (this) {
is FirClassLikeSymbol<*> -> { is FirClassLikeSymbol<*> -> {
val ownerId = classId.outerClassId
if (classId.isLocal) { if (classId.isLocal) {
ownerId?.asLocal() ?: classId (fir as? FirRegularClass)?.containingClassForLocal()
} else { } else {
ownerId val ownerId = classId.outerClassId
ownerId?.let { ConeClassLikeLookupTagImpl(it) }
} }
} }
is FirCallableSymbol<*> -> containingClass()?.classId is FirCallableSymbol<*> -> containingClass()
else -> error("Unsupported owner search for ${fir.javaClass}: ${fir.render()}") else -> error("Unsupported owner search for ${fir.javaClass}: ${fir.render()}")
} }
} }
private fun ClassId.asLocal(): ClassId = ClassId(packageFqName, relativeClassName, true)