[FIR] Extract java related effective visibility calculation to platform component

This commit is contained in:
Dmitriy Novozhilov
2020-08-28 13:28:02 +03:00
parent ed4c6a38b6
commit 3379d9b619
10 changed files with 75 additions and 198 deletions
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.registerCheckersComponent
import org.jetbrains.kotlin.fir.java.deserialization.KotlinDeserializedJvmSymbolsProvider
import org.jetbrains.kotlin.fir.resolve.calls.jvm.registerJvmCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.*
@@ -38,8 +37,7 @@ class FirJavaModuleBasedSession private constructor(
registerCommonComponents()
registerResolveComponents()
registerCheckersComponent()
registerJvmCallConflictResolverFactory()
registerJavaVisibilityChecker()
registerJavaSpecificComponents()
val kotlinScopeProvider = KotlinScopeProvider(::wrapScopeWithJvmMapped)
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.java
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.registerJvmEffectiveVisibilityResolver
import org.jetbrains.kotlin.fir.resolve.calls.jvm.registerJvmCallConflictResolverFactory
fun FirSession.registerJavaSpecificComponents() {
registerJavaVisibilityChecker()
registerJvmCallConflictResolverFactory()
registerJvmEffectiveVisibilityResolver()
}
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
class FirJvmEffectiveVisibilityResolver(session: FirSession) : FirEffectiveVisibilityResolverImpl(session) {
override fun computeEffectiveVisibility(visibility: Visibility, containerSymbol: FirClassLikeSymbol<*>?): FirEffectiveVisibility {
return when (visibility) {
JavaVisibilities.PackageVisibility -> FirEffectiveVisibilityImpl.PackagePrivate
else -> super.computeEffectiveVisibility(visibility, containerSymbol)
}
}
}
fun FirSession.registerJvmEffectiveVisibilityResolver() {
register(FirEffectiveVisibilityResolver::class, FirJvmEffectiveVisibilityResolver(this))
}
@@ -12,18 +12,10 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class FirEffectiveVisibilityResolverImpl(private val session: FirSession) : FirEffectiveVisibilityResolver {
val cache = mutableMapOf<FirSourceElement, FirEffectiveVisibility>()
open class FirEffectiveVisibilityResolverImpl(private val session: FirSession) : FirEffectiveVisibilityResolver() {
private val cache = mutableMapOf<FirSourceElement, FirEffectiveVisibility>()
private fun FirElement.remember(effectiveVisibility: FirEffectiveVisibility): FirEffectiveVisibility {
val source = source
if (source != null) {
cache[source] = effectiveVisibility
}
return effectiveVisibility
}
override fun resolveFor(
final override fun resolveFor(
declaration: FirMemberDeclaration,
containingDeclarations: List<FirDeclaration>?,
scopeSession: ScopeSession
@@ -47,11 +39,37 @@ class FirEffectiveVisibilityResolverImpl(private val session: FirSession) : FirE
}
}
var selfEffectiveVisibility = visibility.firEffectiveVisibility(session, parentSymbol)
var selfEffectiveVisibility = computeEffectiveVisibility(visibility, parentSymbol)
selfEffectiveVisibility = parentEffectiveVisibility.lowerBound(selfEffectiveVisibility)
return declaration.remember(selfEffectiveVisibility)
}
protected open fun computeEffectiveVisibility(visibility: Visibility, containerSymbol: FirClassLikeSymbol<*>?): FirEffectiveVisibility {
return visibility.normalize().forVisibility(containerSymbol)
}
protected fun Visibility.forVisibility(
containerSymbol: FirClassLikeSymbol<*>?
): FirEffectiveVisibility =
when (this) {
Visibilities.Private, Visibilities.PrivateToThis, Visibilities.InvisibleFake -> FirEffectiveVisibilityImpl.Private
Visibilities.Protected -> FirEffectiveVisibilityImpl.Protected(containerSymbol, session)
Visibilities.Internal -> FirEffectiveVisibilityImpl.Internal
Visibilities.Public -> FirEffectiveVisibilityImpl.Public
Visibilities.Local -> FirEffectiveVisibilityImpl.Local
Visibilities.Unknown -> FirEffectiveVisibilityImpl.Private
// NB: visibility must be already normalized here, so e.g. no JavaVisibilities are possible at this point
else -> error("Visibility $name is not allowed in forVisibility")
}
private fun FirElement.remember(effectiveVisibility: FirEffectiveVisibility): FirEffectiveVisibility {
val source = source
if (source != null) {
cache[source] = effectiveVisibility
}
return effectiveVisibility
}
private fun FirMemberDeclaration.getParentInfo(
containingDeclarations: List<FirDeclaration>?,
scopeSession: ScopeSession
@@ -132,4 +150,4 @@ class FirEffectiveVisibilityResolverImpl(private val session: FirSession) : FirE
return null
}
}
}
@@ -1,170 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.descriptors.RelationToType
import org.jetbrains.kotlin.fir.FirEffectiveVisibility.Permissiveness
import org.jetbrains.kotlin.fir.FirEffectiveVisibilityImpl.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.declaredMemberScopeProvider
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeKotlinTypeProjection
import org.jetbrains.kotlin.load.java.JavaVisibilities
fun firEffectiveVisibility(
session: FirSession,
visibility: Visibility,
declaration: FirMemberDeclaration?
) =
visibility.forVisibility(session, declaration)
fun FirRegularClass.firEffectiveVisibility(session: FirSession, checkPublishedApi: Boolean = false) =
firEffectiveVisibility(session, emptySet(), checkPublishedApi)
fun Visibility.firEffectiveVisibility(session: FirSession, declaration: FirMemberDeclaration?): FirEffectiveVisibility =
firEffectiveVisibility(session, normalize(), declaration)
fun Visibility.firEffectiveVisibility(session: FirSession, containerSymbol: FirClassLikeSymbol<*>?): FirEffectiveVisibility = when (this) {
JavaVisibilities.PACKAGE_VISIBILITY -> forVisibility(session, containerSymbol)
else -> normalize().forVisibility(session, containerSymbol)
}
fun ConeKotlinType.leastPermissiveDescriptor(session: FirSession, base: FirEffectiveVisibility): DeclarationWithRelation? =
dependentDeclarations(session).leastPermissive(session, base)
private fun lowerBound(vararg elements: FirEffectiveVisibility): FirEffectiveVisibility {
if (elements.size < 2) {
throw IllegalArgumentException("Number of elements must be greater than 1")
}
var result = elements[0]
for (el in elements) {
result = result.lowerBound(el)
}
return result
}
private fun FirMemberDeclaration.containingClass(session: FirSession): FirRegularClass? {
val classId = when (this) {
is FirRegularClass -> symbol.classId.outerClassId
is FirCallableMemberDeclaration<*> -> symbol.callableId.classId
else -> null
} ?: return null
if (classId.isLocal) return null
return (session.firSymbolProvider.getClassLikeSymbolByFqName(classId)?.fir as? FirRegularClass)
?: (session.declaredMemberScopeProvider.getClassByClassId(classId) as? FirRegularClass)
}
private fun FirClassLikeSymbol<*>.containingClass(session: FirSession): FirRegularClass? {
val classId = when (this) {
is FirRegularClassSymbol -> classId.outerClassId
is FirCallableSymbol<*> -> callableId.classId
else -> null
} ?: return null
if (classId.isLocal) return null
return (session.firSymbolProvider.getClassLikeSymbolByFqName(classId)?.fir as? FirRegularClass)
?: (session.declaredMemberScopeProvider.getClassByClassId(classId) as? FirRegularClass)
}
private fun Visibility.forVisibility(session: FirSession, declaration: FirMemberDeclaration?) =
forVisibility(session, declaration?.containingClass(session)?.symbol)
private fun Visibility.forVisibility(
session: FirSession, containerSymbol: FirClassLikeSymbol<*>?
): FirEffectiveVisibility =
when (this) {
Visibilities.Private, Visibilities.PrivateToThis, Visibilities.InvisibleFake -> Private
Visibilities.Protected -> Protected(containerSymbol, session)
Visibilities.Internal -> Internal
Visibilities.Public -> Public
Visibilities.Local -> Local
// NB: visibility must be already normalized here, so e.g. no JavaVisibilities are possible at this point
// TODO: else -> throw AssertionError("Visibility $name is not allowed in forVisibility")
JavaVisibilities.PACKAGE_VISIBILITY -> PackagePrivate
else -> Private
}
class DeclarationWithRelation internal constructor(val declaration: FirMemberDeclaration, private val relation: RelationToType) {
fun firEffectiveVisibility(session: FirSession) =
declaration.visibility.firEffectiveVisibility(session, declaration)
override fun toString(): String {
val name = when (declaration) {
is FirRegularClass -> declaration.name
is FirSimpleFunction -> declaration.name
is FirVariable<*> -> declaration.name
else -> "<anonymous>"
}
return "$relation $name"
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is DeclarationWithRelation) return false
if (declaration != other.declaration) return false
if (relation != other.relation) return false
return true
}
override fun hashCode(): Int {
var result = declaration.hashCode()
result = 31 * result + relation.hashCode()
return result
}
}
private fun FirMemberDeclaration.dependentDeclarations(session: FirSession, ownRelation: RelationToType): Set<DeclarationWithRelation> =
setOf(DeclarationWithRelation(this, ownRelation)) +
(this.containingClass(session)?.dependentDeclarations(session, ownRelation.containerRelation()) ?: emptySet())
private fun FirRegularClass.firEffectiveVisibility(
session: FirSession, classes: Set<FirRegularClass>, checkPublishedApi: Boolean
): FirEffectiveVisibility =
if (this in classes) Public
else with(this.containingClass(session)) {
lowerBound(
visibility.firEffectiveVisibility(session, this@firEffectiveVisibility),
this?.firEffectiveVisibility(session, classes + this@firEffectiveVisibility, checkPublishedApi) ?: Public
)
}
// Should collect all dependent classifier descriptors, to get verbose diagnostic
private fun ConeKotlinType.dependentDeclarations(session: FirSession) =
dependentDeclarations(session, emptySet(), RelationToType.CONSTRUCTOR)
private fun ConeKotlinType.dependentDeclarations(
session: FirSession, types: Set<ConeKotlinType>, ownRelation: RelationToType
): Set<DeclarationWithRelation> {
if (this in types) return emptySet()
val classLikeType = this as? ConeClassLikeType ?: return emptySet()
val lookupTag = classLikeType.lookupTag
val classSymbol = lookupTag.toSymbol(session) ?: return emptySet()
val ownDependent = (classSymbol.fir as? FirMemberDeclaration)?.dependentDeclarations(session, ownRelation) ?: emptySet()
val argumentDependent = classLikeType.typeArguments.mapNotNull {
(it as? ConeKotlinTypeProjection)?.type?.dependentDeclarations(session, types + this, RelationToType.ARGUMENT)
}.flatten()
return ownDependent + argumentDependent
}
private fun Set<DeclarationWithRelation>.leastPermissive(session: FirSession, base: FirEffectiveVisibility): DeclarationWithRelation? {
for (declarationWithRelation in this) {
val currentVisibility = declarationWithRelation.firEffectiveVisibility(session)
when (currentVisibility.relation(base)) {
Permissiveness.LESS, Permissiveness.UNKNOWN -> {
return declarationWithRelation
}
else -> {
}
}
}
return null
}
@@ -19,5 +19,4 @@ abstract class FirModuleBasedSession(
fun FirSession.registerResolveComponents() {
register(FirQualifierResolver::class, FirQualifierResolverImpl(this))
register(FirTypeResolver::class, FirTypeResolverImpl(this))
register(FirEffectiveVisibilityResolver::class, FirEffectiveVisibilityResolverImpl(this))
}
}
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -18,11 +18,9 @@ import org.jetbrains.kotlin.fir.resolve.inference.*
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -9,10 +9,10 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.resolve.ScopeSession
interface FirEffectiveVisibilityResolver : FirSessionComponent {
fun resolveFor(
abstract class FirEffectiveVisibilityResolver : FirSessionComponent {
abstract fun resolveFor(
declaration: FirMemberDeclaration,
containingDeclarations: List<FirDeclaration>?,
scopeSession: ScopeSession
): FirEffectiveVisibility
}
}
@@ -15,8 +15,7 @@ import org.jetbrains.kotlin.fir.extensions.BunchOfRegisteredExtensions
import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.extensions.registerExtensions
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.fir.java.registerJavaVisibilityChecker
import org.jetbrains.kotlin.fir.resolve.calls.jvm.registerJvmCallConflictResolverFactory
import org.jetbrains.kotlin.fir.java.registerJavaSpecificComponents
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
@@ -95,8 +94,7 @@ internal class FirIdeSourcesSession private constructor(
}
) as FirSymbolProvider
)
registerJvmCallConflictResolverFactory()
registerJavaVisibilityChecker()
registerJavaSpecificComponents()
extensionService.registerExtensions(BunchOfRegisteredExtensions.empty())
}
}