Cleanup code in EffectiveVisibility.kt and extract descriptors related part to separate file
This commit is contained in:
@@ -160,6 +160,22 @@ object AbstractTypeChecker {
|
|||||||
return AbstractTypeChecker.isSubtypeOf(context.newBaseTypeCheckerContext(true, stubTypesEqualToAnything), subType, superType)
|
return AbstractTypeChecker.isSubtypeOf(context.newBaseTypeCheckerContext(true, stubTypesEqualToAnything), subType, superType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isSubtypeOfClass(
|
||||||
|
context: AbstractTypeCheckerContext,
|
||||||
|
typeConstructor: TypeConstructorMarker,
|
||||||
|
superConstructor: TypeConstructorMarker
|
||||||
|
): Boolean {
|
||||||
|
if (typeConstructor == superConstructor) return true
|
||||||
|
with(context) {
|
||||||
|
for (superType in typeConstructor.supertypes()) {
|
||||||
|
if (isSubtypeOfClass(context, superType.typeConstructor(), superConstructor)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
fun equalTypes(
|
fun equalTypes(
|
||||||
context: TypeCheckerProviderContext,
|
context: TypeCheckerProviderContext,
|
||||||
a: KotlinTypeMarker,
|
a: KotlinTypeMarker,
|
||||||
|
|||||||
@@ -16,23 +16,12 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.descriptors
|
package org.jetbrains.kotlin.descriptors
|
||||||
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.descriptors.EffectiveVisibility.Permissiveness
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.descriptors.EffectiveVisibility.*
|
|
||||||
import org.jetbrains.kotlin.descriptors.RelationToType.*
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi
|
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
|
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
|
||||||
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext
|
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||||
import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContextImpl
|
|
||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
|
||||||
import org.jetbrains.kotlin.types.model.TypeSystemCommonSuperTypesContext
|
|
||||||
import org.jetbrains.kotlin.types.model.TypeSystemContext
|
|
||||||
import org.jetbrains.kotlin.types.model.typeConstructor
|
|
||||||
|
|
||||||
sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = false, val privateApi: Boolean = false) {
|
sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = false, val privateApi: Boolean = false) {
|
||||||
|
|
||||||
override fun toString() = name
|
override fun toString() = name
|
||||||
|
|
||||||
// Public
|
// Public
|
||||||
@@ -49,31 +38,31 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
|
|||||||
|
|
||||||
|
|
||||||
object Private : EffectiveVisibility("private", privateApi = true) {
|
object Private : EffectiveVisibility("private", privateApi = true) {
|
||||||
override fun relation(other: EffectiveVisibility) =
|
override fun relation(other: EffectiveVisibility): Permissiveness =
|
||||||
if (this == other || Local == other) Permissiveness.SAME else Permissiveness.LESS
|
if (this == other || Local == other) Permissiveness.SAME else Permissiveness.LESS
|
||||||
|
|
||||||
override fun toVisibility() = Visibilities.PRIVATE
|
override fun toVisibility(): Visibility = Visibilities.PRIVATE
|
||||||
}
|
}
|
||||||
|
|
||||||
// Effectively same as Private
|
// Effectively same as Private
|
||||||
object Local : EffectiveVisibility("local") {
|
object Local : EffectiveVisibility("local") {
|
||||||
override fun relation(other: EffectiveVisibility) =
|
override fun relation(other: EffectiveVisibility): Permissiveness =
|
||||||
if (this == other || Private == other) Permissiveness.SAME else Permissiveness.LESS
|
if (this == other || Private == other) Permissiveness.SAME else Permissiveness.LESS
|
||||||
|
|
||||||
override fun toVisibility() = Visibilities.LOCAL
|
override fun toVisibility(): Visibility = Visibilities.LOCAL
|
||||||
}
|
}
|
||||||
|
|
||||||
object Public : EffectiveVisibility("public", publicApi = true) {
|
object Public : EffectiveVisibility("public", publicApi = true) {
|
||||||
override fun relation(other: EffectiveVisibility) =
|
override fun relation(other: EffectiveVisibility): Permissiveness =
|
||||||
if (this == other) Permissiveness.SAME else Permissiveness.MORE
|
if (this == other) Permissiveness.SAME else Permissiveness.MORE
|
||||||
|
|
||||||
override fun toVisibility() = Visibilities.PUBLIC
|
override fun toVisibility(): Visibility = Visibilities.PUBLIC
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class InternalOrPackage protected constructor(internal: Boolean) : EffectiveVisibility(
|
abstract class InternalOrPackage protected constructor(internal: Boolean) : EffectiveVisibility(
|
||||||
if (internal) "internal" else "public/*package*/"
|
if (internal) "internal" else "public/*package*/"
|
||||||
) {
|
) {
|
||||||
override fun relation(other: EffectiveVisibility) = when (other) {
|
override fun relation(other: EffectiveVisibility): Permissiveness = when (other) {
|
||||||
Public -> Permissiveness.LESS
|
Public -> Permissiveness.LESS
|
||||||
Private, Local, InternalProtectedBound, is InternalProtected -> Permissiveness.MORE
|
Private, Local, InternalProtectedBound, is InternalProtected -> Permissiveness.MORE
|
||||||
is InternalOrPackage -> Permissiveness.SAME
|
is InternalOrPackage -> Permissiveness.SAME
|
||||||
@@ -83,35 +72,35 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
|
|||||||
override fun lowerBound(other: EffectiveVisibility) = when (other) {
|
override fun lowerBound(other: EffectiveVisibility) = when (other) {
|
||||||
Public -> this
|
Public -> this
|
||||||
Private, Local, InternalProtectedBound, is InternalOrPackage, is InternalProtected -> other
|
Private, Local, InternalProtectedBound, is InternalOrPackage, is InternalProtected -> other
|
||||||
is Protected -> InternalProtected(other.containerType, other.typeContext)
|
is Protected -> InternalProtected(other.containerTypeConstructor, other.typeContext)
|
||||||
ProtectedBound -> InternalProtectedBound
|
ProtectedBound -> InternalProtectedBound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Internal : InternalOrPackage(true) {
|
object Internal : InternalOrPackage(true) {
|
||||||
override fun toVisibility() = Visibilities.INTERNAL
|
override fun toVisibility(): Visibility = Visibilities.INTERNAL
|
||||||
}
|
}
|
||||||
|
|
||||||
object PackagePrivate : InternalOrPackage(false) {
|
object PackagePrivate : InternalOrPackage(false) {
|
||||||
override fun toVisibility() = Visibilities.PRIVATE
|
override fun toVisibility(): Visibility = Visibilities.PRIVATE
|
||||||
}
|
}
|
||||||
|
|
||||||
class Protected(
|
class Protected(
|
||||||
val containerType: KotlinTypeMarker?,
|
val containerTypeConstructor: TypeConstructorMarker?,
|
||||||
val typeContext: AbstractTypeCheckerContext
|
val typeContext: AbstractTypeCheckerContext
|
||||||
) : EffectiveVisibility("protected", publicApi = true) {
|
) : EffectiveVisibility("protected", publicApi = true) {
|
||||||
|
|
||||||
override fun equals(other: Any?) = (other is Protected && containerType == other.containerType)
|
override fun equals(other: Any?) = (other is Protected && containerTypeConstructor == other.containerTypeConstructor)
|
||||||
|
|
||||||
override fun hashCode() = containerType?.hashCode() ?: 0
|
override fun hashCode() = containerTypeConstructor?.hashCode() ?: 0
|
||||||
|
|
||||||
override fun toString() = "${super.toString()} (in ${containerType?.typeConstructor(typeContext) ?: '?'})"
|
override fun toString() = "${super.toString()} (in ${containerTypeConstructor ?: '?'})"
|
||||||
|
|
||||||
override fun relation(other: EffectiveVisibility) = when (other) {
|
override fun relation(other: EffectiveVisibility): Permissiveness = when (other) {
|
||||||
Public -> Permissiveness.LESS
|
Public -> Permissiveness.LESS
|
||||||
Private, Local, ProtectedBound, InternalProtectedBound -> Permissiveness.MORE
|
Private, Local, ProtectedBound, InternalProtectedBound -> Permissiveness.MORE
|
||||||
is Protected -> containerRelation(containerType, other.containerType, typeContext)
|
is Protected -> containerRelation(containerTypeConstructor, other.containerTypeConstructor, typeContext)
|
||||||
is InternalProtected -> when (containerRelation(containerType, other.containerType, typeContext)) {
|
is InternalProtected -> when (containerRelation(containerTypeConstructor, other.containerTypeConstructor, typeContext)) {
|
||||||
// Protected never can be less permissive than internal & protected
|
// Protected never can be less permissive than internal & protected
|
||||||
Permissiveness.SAME, Permissiveness.MORE -> Permissiveness.MORE
|
Permissiveness.SAME, Permissiveness.MORE -> Permissiveness.MORE
|
||||||
Permissiveness.UNKNOWN, Permissiveness.LESS -> Permissiveness.UNKNOWN
|
Permissiveness.UNKNOWN, Permissiveness.LESS -> Permissiveness.UNKNOWN
|
||||||
@@ -131,15 +120,15 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
|
|||||||
Permissiveness.LESS -> other
|
Permissiveness.LESS -> other
|
||||||
else -> InternalProtectedBound
|
else -> InternalProtectedBound
|
||||||
}
|
}
|
||||||
is InternalOrPackage -> InternalProtected(containerType, typeContext)
|
is InternalOrPackage -> InternalProtected(containerTypeConstructor, typeContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toVisibility() = Visibilities.PROTECTED
|
override fun toVisibility(): Visibility = Visibilities.PROTECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lower bound for all protected visibilities
|
// Lower bound for all protected visibilities
|
||||||
object ProtectedBound : EffectiveVisibility("protected (in different classes)", publicApi = true) {
|
object ProtectedBound : EffectiveVisibility("protected (in different classes)", publicApi = true) {
|
||||||
override fun relation(other: EffectiveVisibility) = when (other) {
|
override fun relation(other: EffectiveVisibility): Permissiveness = when (other) {
|
||||||
Public, is Protected -> Permissiveness.LESS
|
Public, is Protected -> Permissiveness.LESS
|
||||||
Private, Local, InternalProtectedBound -> Permissiveness.MORE
|
Private, Local, InternalProtectedBound -> Permissiveness.MORE
|
||||||
ProtectedBound -> Permissiveness.SAME
|
ProtectedBound -> Permissiveness.SAME
|
||||||
@@ -152,26 +141,26 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
|
|||||||
is InternalOrPackage, is InternalProtected -> InternalProtectedBound
|
is InternalOrPackage, is InternalProtected -> InternalProtectedBound
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toVisibility() = Visibilities.PROTECTED
|
override fun toVisibility(): Visibility = Visibilities.PROTECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lower bound for internal and protected(C)
|
// Lower bound for internal and protected(C)
|
||||||
class InternalProtected(
|
class InternalProtected(
|
||||||
val containerType: KotlinTypeMarker?,
|
val containerTypeConstructor: TypeConstructorMarker?,
|
||||||
val typeContext: AbstractTypeCheckerContext,
|
val typeContext: AbstractTypeCheckerContext,
|
||||||
) : EffectiveVisibility("internal & protected") {
|
) : EffectiveVisibility("internal & protected") {
|
||||||
|
|
||||||
override fun equals(other: Any?) = (other is InternalProtected && containerType == other.containerType)
|
override fun equals(other: Any?) = (other is InternalProtected && containerTypeConstructor == other.containerTypeConstructor)
|
||||||
|
|
||||||
override fun hashCode() = containerType?.hashCode() ?: 0
|
override fun hashCode() = containerTypeConstructor?.hashCode() ?: 0
|
||||||
|
|
||||||
override fun toString() = "${super.toString()} (in ${containerType?.typeConstructor(typeContext) ?: '?'})"
|
override fun toString() = "${super.toString()} (in ${containerTypeConstructor ?: '?'})"
|
||||||
|
|
||||||
override fun relation(other: EffectiveVisibility) = when (other) {
|
override fun relation(other: EffectiveVisibility): Permissiveness = when (other) {
|
||||||
Public, is InternalOrPackage -> Permissiveness.LESS
|
Public, is InternalOrPackage -> Permissiveness.LESS
|
||||||
Private, Local, InternalProtectedBound -> Permissiveness.MORE
|
Private, Local, InternalProtectedBound -> Permissiveness.MORE
|
||||||
is InternalProtected -> containerRelation(containerType, other.containerType, typeContext)
|
is InternalProtected -> containerRelation(containerTypeConstructor, other.containerTypeConstructor, typeContext)
|
||||||
is Protected -> when (containerRelation(containerType, other.containerType, typeContext)) {
|
is Protected -> when (containerRelation(containerTypeConstructor, other.containerTypeConstructor, typeContext)) {
|
||||||
// Internal & protected never can be more permissive than just protected
|
// Internal & protected never can be more permissive than just protected
|
||||||
Permissiveness.SAME, Permissiveness.LESS -> Permissiveness.LESS
|
Permissiveness.SAME, Permissiveness.LESS -> Permissiveness.LESS
|
||||||
Permissiveness.UNKNOWN, Permissiveness.MORE -> Permissiveness.UNKNOWN
|
Permissiveness.UNKNOWN, Permissiveness.MORE -> Permissiveness.UNKNOWN
|
||||||
@@ -190,18 +179,18 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
|
|||||||
ProtectedBound -> InternalProtectedBound
|
ProtectedBound -> InternalProtectedBound
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toVisibility() = Visibilities.PRIVATE
|
override fun toVisibility(): Visibility = Visibilities.PRIVATE
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lower bound for internal and protected lower bound
|
// Lower bound for internal and protected lower bound
|
||||||
object InternalProtectedBound : EffectiveVisibility("internal & protected (in different classes)") {
|
object InternalProtectedBound : EffectiveVisibility("internal & protected (in different classes)") {
|
||||||
override fun relation(other: EffectiveVisibility) = when (other) {
|
override fun relation(other: EffectiveVisibility): Permissiveness = when (other) {
|
||||||
Public, is Protected, is InternalProtected, ProtectedBound, is InternalOrPackage -> Permissiveness.LESS
|
Public, is Protected, is InternalProtected, ProtectedBound, is InternalOrPackage -> Permissiveness.LESS
|
||||||
Private, Local -> Permissiveness.MORE
|
Private, Local -> Permissiveness.MORE
|
||||||
InternalProtectedBound -> Permissiveness.SAME
|
InternalProtectedBound -> Permissiveness.SAME
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toVisibility() = Visibilities.PRIVATE
|
override fun toVisibility(): Visibility = Visibilities.PRIVATE
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Permissiveness {
|
enum class Permissiveness {
|
||||||
@@ -215,51 +204,13 @@ sealed class EffectiveVisibility(val name: String, val publicApi: Boolean = fals
|
|||||||
|
|
||||||
abstract fun toVisibility(): Visibility
|
abstract fun toVisibility(): Visibility
|
||||||
|
|
||||||
open internal fun lowerBound(other: EffectiveVisibility) = when (relation(other)) {
|
internal open fun lowerBound(other: EffectiveVisibility) = when (relation(other)) {
|
||||||
Permissiveness.SAME, Permissiveness.LESS -> this
|
Permissiveness.SAME, Permissiveness.LESS -> this
|
||||||
Permissiveness.MORE -> other
|
Permissiveness.MORE -> other
|
||||||
Permissiveness.UNKNOWN -> Private
|
Permissiveness.UNKNOWN -> Private
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun containerRelation(
|
|
||||||
first: KotlinTypeMarker?,
|
|
||||||
second: KotlinTypeMarker?,
|
|
||||||
typeContext: AbstractTypeCheckerContext
|
|
||||||
): Permissiveness {
|
|
||||||
return when {
|
|
||||||
first == null || second == null -> Permissiveness.UNKNOWN
|
|
||||||
first == second -> Permissiveness.SAME
|
|
||||||
AbstractTypeChecker.isSubtypeOf(typeContext, first, second) -> Permissiveness.LESS
|
|
||||||
AbstractTypeChecker.isSubtypeOf(typeContext, second, first) -> Permissiveness.MORE
|
|
||||||
else -> Permissiveness.UNKNOWN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun lowerBound(first: EffectiveVisibility, second: EffectiveVisibility) =
|
|
||||||
first.lowerBound(second)
|
|
||||||
|
|
||||||
private fun lowerBound(first: EffectiveVisibility, args: List<EffectiveVisibility>) =
|
|
||||||
args.fold(first, { x, y -> x.lowerBound(y) })
|
|
||||||
|
|
||||||
private fun lowerBound(args: List<EffectiveVisibility>) =
|
|
||||||
if (args.isEmpty()) Public else lowerBound(args.first(), args.subList(1, args.size))
|
|
||||||
|
|
||||||
private fun Visibility.forVisibility(descriptor: DeclarationDescriptor, checkPublishedApi: Boolean = false): EffectiveVisibility =
|
|
||||||
when (this) {
|
|
||||||
Visibilities.PRIVATE, Visibilities.PRIVATE_TO_THIS, Visibilities.INVISIBLE_FAKE -> Private
|
|
||||||
Visibilities.PROTECTED -> Protected((descriptor.containingDeclaration as? ClassDescriptor)?.defaultType, ClassicTypeCheckerContext(errorTypeEqualsToAnything = false))
|
|
||||||
Visibilities.INTERNAL -> if (!checkPublishedApi ||
|
|
||||||
!descriptor.isPublishedApi()) Internal else Public
|
|
||||||
Visibilities.PUBLIC -> Public
|
|
||||||
Visibilities.LOCAL -> Local
|
|
||||||
// NB: visibility must be already normalized here, so e.g. no JavaVisibilities are possible at this point
|
|
||||||
else -> throw AssertionError("Visibility $name is not allowed in forVisibility")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun effectiveVisibility(visibility: Visibility, descriptor: DeclarationDescriptor, checkPublishedApi: Boolean = false) =
|
|
||||||
visibility.forVisibility(descriptor, checkPublishedApi)
|
|
||||||
|
|
||||||
enum class RelationToType(val description: String) {
|
enum class RelationToType(val description: String) {
|
||||||
CONSTRUCTOR(""),
|
CONSTRUCTOR(""),
|
||||||
CONTAINER(" containing declaration"),
|
CONTAINER(" containing declaration"),
|
||||||
@@ -274,53 +225,17 @@ enum class RelationToType(val description: String) {
|
|||||||
override fun toString() = description
|
override fun toString() = description
|
||||||
}
|
}
|
||||||
|
|
||||||
data class DescriptorWithRelation(val descriptor: ClassifierDescriptor, private val relation: RelationToType) {
|
internal fun containerRelation(
|
||||||
fun effectiveVisibility() =
|
first: TypeConstructorMarker?,
|
||||||
(descriptor as? ClassDescriptor)?.visibility?.effectiveVisibility(descriptor, false) ?: Public
|
second: TypeConstructorMarker?,
|
||||||
|
typeContext: AbstractTypeCheckerContext
|
||||||
override fun toString() = "$relation ${descriptor.name}"
|
): Permissiveness {
|
||||||
}
|
return when {
|
||||||
|
first == null || second == null -> Permissiveness.UNKNOWN
|
||||||
private fun ClassifierDescriptor.dependentDescriptors(ownRelation: RelationToType): Set<DescriptorWithRelation> =
|
first == second -> Permissiveness.SAME
|
||||||
setOf(DescriptorWithRelation(this, ownRelation)) +
|
AbstractTypeChecker.isSubtypeOfClass(typeContext, first, second) -> Permissiveness.LESS
|
||||||
((this.containingDeclaration as? ClassifierDescriptor)?.dependentDescriptors(ownRelation.containerRelation()) ?: emptySet())
|
AbstractTypeChecker.isSubtypeOfClass(typeContext, second, first) -> Permissiveness.MORE
|
||||||
|
else -> Permissiveness.UNKNOWN
|
||||||
fun ClassDescriptor.effectiveVisibility(checkPublishedApi: Boolean = false) = effectiveVisibility(emptySet(), checkPublishedApi)
|
|
||||||
|
|
||||||
private fun ClassDescriptor.effectiveVisibility(classes: Set<ClassDescriptor>, checkPublishedApi: Boolean): EffectiveVisibility =
|
|
||||||
if (this in classes) Public
|
|
||||||
else with(this.containingDeclaration as? ClassDescriptor) {
|
|
||||||
lowerBound(visibility.effectiveVisibility(this@effectiveVisibility, checkPublishedApi), this?.effectiveVisibility(classes + this@effectiveVisibility, checkPublishedApi) ?: Public)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should collect all dependent classifier descriptors, to get verbose diagnostic
|
|
||||||
private fun KotlinType.dependentDescriptors() = dependentDescriptors(emptySet(), CONSTRUCTOR)
|
|
||||||
|
|
||||||
private fun KotlinType.dependentDescriptors(types: Set<KotlinType>, ownRelation: RelationToType): Set<DescriptorWithRelation> {
|
|
||||||
if (this in types) return emptySet()
|
|
||||||
val ownDependent = constructor.declarationDescriptor?.dependentDescriptors(ownRelation) ?: emptySet()
|
|
||||||
val argumentDependent = arguments.map { it.type.dependentDescriptors(types + this, ARGUMENT) }.flatten()
|
|
||||||
return ownDependent + argumentDependent
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Set<DescriptorWithRelation>.leastPermissive(base: EffectiveVisibility): DescriptorWithRelation? {
|
|
||||||
for (descriptorWithRelation in this) {
|
|
||||||
val currentVisibility = descriptorWithRelation.effectiveVisibility()
|
|
||||||
when (currentVisibility.relation(base)) {
|
|
||||||
Permissiveness.LESS, Permissiveness.UNKNOWN -> {
|
|
||||||
return descriptorWithRelation
|
|
||||||
}
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KotlinType.leastPermissiveDescriptor(base: EffectiveVisibility) = dependentDescriptors().leastPermissive(base)
|
|
||||||
|
|
||||||
fun DeclarationDescriptorWithVisibility.effectiveVisibility(
|
|
||||||
visibility: Visibility = this.visibility, checkPublishedApi: Boolean = false
|
|
||||||
): EffectiveVisibility =
|
|
||||||
lowerBound(visibility.effectiveVisibility(this, checkPublishedApi),
|
|
||||||
(this.containingDeclaration as? ClassDescriptor)?.effectiveVisibility(checkPublishedApi) ?: Public)
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerContext
|
||||||
|
|
||||||
|
fun effectiveVisibility(visibility: Visibility, descriptor: DeclarationDescriptor, checkPublishedApi: Boolean = false) =
|
||||||
|
visibility.forVisibility(descriptor, checkPublishedApi)
|
||||||
|
|
||||||
|
private fun Visibility.forVisibility(descriptor: DeclarationDescriptor, checkPublishedApi: Boolean = false): EffectiveVisibility =
|
||||||
|
when (this) {
|
||||||
|
Visibilities.PRIVATE, Visibilities.PRIVATE_TO_THIS, Visibilities.INVISIBLE_FAKE -> EffectiveVisibility.Private
|
||||||
|
Visibilities.PROTECTED -> EffectiveVisibility.Protected(
|
||||||
|
(descriptor.containingDeclaration as? ClassDescriptor)?.defaultType?.constructor,
|
||||||
|
ClassicTypeCheckerContext(errorTypeEqualsToAnything = false)
|
||||||
|
)
|
||||||
|
Visibilities.INTERNAL -> if (!checkPublishedApi ||
|
||||||
|
!descriptor.isPublishedApi()
|
||||||
|
) EffectiveVisibility.Internal else EffectiveVisibility.Public
|
||||||
|
Visibilities.PUBLIC -> EffectiveVisibility.Public
|
||||||
|
Visibilities.LOCAL -> EffectiveVisibility.Local
|
||||||
|
// NB: visibility must be already normalized here, so e.g. no JavaVisibilities are possible at this point
|
||||||
|
else -> throw AssertionError("Visibility $name is not allowed in forVisibility")
|
||||||
|
}
|
||||||
|
|
||||||
|
data class DescriptorWithRelation(val descriptor: ClassifierDescriptor, private val relation: RelationToType) {
|
||||||
|
fun effectiveVisibility() =
|
||||||
|
(descriptor as? ClassDescriptor)?.visibility?.effectiveVisibility(descriptor, false) ?: EffectiveVisibility.Public
|
||||||
|
|
||||||
|
override fun toString() = "$relation ${descriptor.name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ClassifierDescriptor.dependentDescriptors(ownRelation: RelationToType): Set<DescriptorWithRelation> =
|
||||||
|
setOf(DescriptorWithRelation(this, ownRelation)) +
|
||||||
|
((this.containingDeclaration as? ClassifierDescriptor)?.dependentDescriptors(ownRelation.containerRelation()) ?: emptySet())
|
||||||
|
|
||||||
|
fun ClassDescriptor.effectiveVisibility(checkPublishedApi: Boolean = false) = effectiveVisibility(emptySet(), checkPublishedApi)
|
||||||
|
|
||||||
|
private fun ClassDescriptor.effectiveVisibility(classes: Set<ClassDescriptor>, checkPublishedApi: Boolean): EffectiveVisibility =
|
||||||
|
if (this in classes) EffectiveVisibility.Public
|
||||||
|
else with(this.containingDeclaration as? ClassDescriptor) {
|
||||||
|
lowerBound(
|
||||||
|
visibility.effectiveVisibility(this@effectiveVisibility, checkPublishedApi),
|
||||||
|
this?.effectiveVisibility(classes + this@effectiveVisibility, checkPublishedApi) ?: EffectiveVisibility.Public
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should collect all dependent classifier descriptors, to get verbose diagnostic
|
||||||
|
private fun KotlinType.dependentDescriptors() = dependentDescriptors(emptySet(), RelationToType.CONSTRUCTOR)
|
||||||
|
|
||||||
|
private fun KotlinType.dependentDescriptors(types: Set<KotlinType>, ownRelation: RelationToType): Set<DescriptorWithRelation> {
|
||||||
|
if (this in types) return emptySet()
|
||||||
|
val ownDependent = constructor.declarationDescriptor?.dependentDescriptors(ownRelation) ?: emptySet()
|
||||||
|
val argumentDependent = arguments.map { it.type.dependentDescriptors(types + this, RelationToType.ARGUMENT) }.flatten()
|
||||||
|
return ownDependent + argumentDependent
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Set<DescriptorWithRelation>.leastPermissive(base: EffectiveVisibility): DescriptorWithRelation? {
|
||||||
|
for (descriptorWithRelation in this) {
|
||||||
|
val currentVisibility = descriptorWithRelation.effectiveVisibility()
|
||||||
|
when (currentVisibility.relation(base)) {
|
||||||
|
EffectiveVisibility.Permissiveness.LESS, EffectiveVisibility.Permissiveness.UNKNOWN -> {
|
||||||
|
return descriptorWithRelation
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KotlinType.leastPermissiveDescriptor(base: EffectiveVisibility) = dependentDescriptors().leastPermissive(base)
|
||||||
|
|
||||||
|
fun DeclarationDescriptorWithVisibility.effectiveVisibility(
|
||||||
|
visibility: Visibility = this.visibility, checkPublishedApi: Boolean = false
|
||||||
|
): EffectiveVisibility =
|
||||||
|
lowerBound(
|
||||||
|
visibility.effectiveVisibility(this, checkPublishedApi),
|
||||||
|
(this.containingDeclaration as? ClassDescriptor)?.effectiveVisibility(checkPublishedApi) ?: EffectiveVisibility.Public
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun lowerBound(first: EffectiveVisibility, second: EffectiveVisibility): EffectiveVisibility = first.lowerBound(second)
|
||||||
Reference in New Issue
Block a user