[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.*
import org.jetbrains.kotlin.fir.analysis.registerCheckersComponent import org.jetbrains.kotlin.fir.analysis.registerCheckersComponent
import org.jetbrains.kotlin.fir.java.deserialization.KotlinDeserializedJvmSymbolsProvider 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.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.* import org.jetbrains.kotlin.fir.resolve.providers.impl.*
@@ -38,8 +37,7 @@ class FirJavaModuleBasedSession private constructor(
registerCommonComponents() registerCommonComponents()
registerResolveComponents() registerResolveComponents()
registerCheckersComponent() registerCheckersComponent()
registerJvmCallConflictResolverFactory() registerJavaSpecificComponents()
registerJavaVisibilityChecker()
val kotlinScopeProvider = KotlinScopeProvider(::wrapScopeWithJvmMapped) 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.name.ClassId
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class FirEffectiveVisibilityResolverImpl(private val session: FirSession) : FirEffectiveVisibilityResolver { open class FirEffectiveVisibilityResolverImpl(private val session: FirSession) : FirEffectiveVisibilityResolver() {
val cache = mutableMapOf<FirSourceElement, FirEffectiveVisibility>() private val cache = mutableMapOf<FirSourceElement, FirEffectiveVisibility>()
private fun FirElement.remember(effectiveVisibility: FirEffectiveVisibility): FirEffectiveVisibility { final override fun resolveFor(
val source = source
if (source != null) {
cache[source] = effectiveVisibility
}
return effectiveVisibility
}
override fun resolveFor(
declaration: FirMemberDeclaration, declaration: FirMemberDeclaration,
containingDeclarations: List<FirDeclaration>?, containingDeclarations: List<FirDeclaration>?,
scopeSession: ScopeSession 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) selfEffectiveVisibility = parentEffectiveVisibility.lowerBound(selfEffectiveVisibility)
return declaration.remember(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( private fun FirMemberDeclaration.getParentInfo(
containingDeclarations: List<FirDeclaration>?, containingDeclarations: List<FirDeclaration>?,
scopeSession: ScopeSession scopeSession: ScopeSession
@@ -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() { fun FirSession.registerResolveComponents() {
register(FirQualifierResolver::class, FirQualifierResolverImpl(this)) register(FirQualifierResolver::class, FirQualifierResolverImpl(this))
register(FirTypeResolver::class, FirTypeResolverImpl(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.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType 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.ClassId
import org.jetbrains.kotlin.name.FqName 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.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol 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.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.load.java.JavaVisibilities
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.name.Name import org.jetbrains.kotlin.name.Name
@@ -9,8 +9,8 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
interface FirEffectiveVisibilityResolver : FirSessionComponent { abstract class FirEffectiveVisibilityResolver : FirSessionComponent {
fun resolveFor( abstract fun resolveFor(
declaration: FirMemberDeclaration, declaration: FirMemberDeclaration,
containingDeclarations: List<FirDeclaration>?, containingDeclarations: List<FirDeclaration>?,
scopeSession: ScopeSession scopeSession: ScopeSession
@@ -15,8 +15,7 @@ import org.jetbrains.kotlin.fir.extensions.BunchOfRegisteredExtensions
import org.jetbrains.kotlin.fir.extensions.extensionService import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.extensions.registerExtensions import org.jetbrains.kotlin.fir.extensions.registerExtensions
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.fir.java.registerJavaVisibilityChecker import org.jetbrains.kotlin.fir.java.registerJavaSpecificComponents
import org.jetbrains.kotlin.fir.resolve.calls.jvm.registerJvmCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
@@ -95,8 +94,7 @@ internal class FirIdeSourcesSession private constructor(
} }
) as FirSymbolProvider ) as FirSymbolProvider
) )
registerJvmCallConflictResolverFactory() registerJavaSpecificComponents()
registerJavaVisibilityChecker()
extensionService.registerExtensions(BunchOfRegisteredExtensions.empty()) extensionService.registerExtensions(BunchOfRegisteredExtensions.empty())
} }
} }