[FIR] Extract java related effective visibility calculation to platform component
This commit is contained in:
@@ -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))
|
||||
}
|
||||
+31
-13
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user