Introduce ClassDescriptor.getSealedSubclasses
#KT-12795 In Progress
This commit is contained in:
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.types.TypeUtils;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class MutableClassDescriptor extends ClassDescriptorBase implements ClassDescriptor {
|
public class MutableClassDescriptor extends ClassDescriptorBase {
|
||||||
private final ClassKind kind;
|
private final ClassKind kind;
|
||||||
private final boolean isInner;
|
private final boolean isInner;
|
||||||
|
|
||||||
@@ -71,6 +71,7 @@ public class MutableClassDescriptor extends ClassDescriptorBase implements Class
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setModality(@NotNull Modality modality) {
|
public void setModality(@NotNull Modality modality) {
|
||||||
|
assert modality != Modality.SEALED : "Implement getSealedSubclasses() for this class: " + getClass();
|
||||||
this.modality = modality;
|
this.modality = modality;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +181,12 @@ public class MutableClassDescriptor extends ClassDescriptorBase implements Class
|
|||||||
return MemberScope.Empty.INSTANCE;
|
return MemberScope.Empty.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Collection<ClassDescriptor> getSealedSubclasses() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return DeclarationDescriptorImpl.toString(this);
|
return DeclarationDescriptorImpl.toString(this);
|
||||||
|
|||||||
@@ -17,11 +17,9 @@
|
|||||||
package org.jetbrains.kotlin.cfg
|
package org.jetbrains.kotlin.cfg
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.tree.TokenSet
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -36,11 +34,9 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry
|
|||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
||||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
|
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
|
||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
import org.jetbrains.kotlin.resolve.descriptorUtil.computeSealedSubclasses
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.isFlexible
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
interface WhenMissingCase {
|
interface WhenMissingCase {
|
||||||
@@ -150,11 +146,12 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
|||||||
|
|
||||||
protected fun getMissingClassCases(
|
protected fun getMissingClassCases(
|
||||||
whenExpression: KtWhenExpression,
|
whenExpression: KtWhenExpression,
|
||||||
memberDescriptors: Set<ClassDescriptor>,
|
subclasses: Set<ClassDescriptor>,
|
||||||
context: BindingContext
|
context: BindingContext
|
||||||
): List<WhenMissingCase> {
|
): List<WhenMissingCase> {
|
||||||
// when on empty enum / sealed is considered non-exhaustive, see test whenOnEmptySealed
|
// when on empty enum / sealed is considered non-exhaustive, see test whenOnEmptySealed
|
||||||
if (memberDescriptors.isEmpty()) return listOf(UnknownMissingCase)
|
if (subclasses.isEmpty()) return listOf(UnknownMissingCase)
|
||||||
|
|
||||||
val checkedDescriptors = LinkedHashSet<ClassDescriptor>()
|
val checkedDescriptors = LinkedHashSet<ClassDescriptor>()
|
||||||
for (whenEntry in whenExpression.entries) {
|
for (whenEntry in whenExpression.entries) {
|
||||||
for (condition in whenEntry.conditions) {
|
for (condition in whenEntry.conditions) {
|
||||||
@@ -182,7 +179,7 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
|||||||
// Checks are important only for nested subclasses of the sealed class
|
// Checks are important only for nested subclasses of the sealed class
|
||||||
// In additional, check without "is" is important only for objects
|
// In additional, check without "is" is important only for objects
|
||||||
if (checkedDescriptor == null ||
|
if (checkedDescriptor == null ||
|
||||||
!memberDescriptors.contains(checkedDescriptor) ||
|
!subclasses.contains(checkedDescriptor) ||
|
||||||
(condition is KtWhenConditionWithExpression &&
|
(condition is KtWhenConditionWithExpression &&
|
||||||
!DescriptorUtils.isObject(checkedDescriptor) &&
|
!DescriptorUtils.isObject(checkedDescriptor) &&
|
||||||
!DescriptorUtils.isEnumEntry(checkedDescriptor))) {
|
!DescriptorUtils.isEnumEntry(checkedDescriptor))) {
|
||||||
@@ -190,7 +187,7 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
|||||||
}
|
}
|
||||||
if (negated) {
|
if (negated) {
|
||||||
if (checkedDescriptors.contains(checkedDescriptor)) return listOf() // all members are already there
|
if (checkedDescriptors.contains(checkedDescriptor)) return listOf() // all members are already there
|
||||||
checkedDescriptors.addAll(memberDescriptors)
|
checkedDescriptors.addAll(subclasses)
|
||||||
checkedDescriptors.remove(checkedDescriptor)
|
checkedDescriptors.remove(checkedDescriptor)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -198,7 +195,7 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (memberDescriptors - checkedDescriptors).toList().map { ClassMissingCase(it) }
|
return (subclasses - checkedDescriptors).toList().map { ClassMissingCase(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,41 +231,15 @@ internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChe
|
|||||||
assert(DescriptorUtils.isSealedClass(subjectDescriptor)) {
|
assert(DescriptorUtils.isSealedClass(subjectDescriptor)) {
|
||||||
"isWhenOnSealedClassExhaustive should be called with a sealed class descriptor: $subjectDescriptor"
|
"isWhenOnSealedClassExhaustive should be called with a sealed class descriptor: $subjectDescriptor"
|
||||||
}
|
}
|
||||||
val memberClassDescriptors = getNestedSubclasses(subjectDescriptor!!)
|
val subclasses = subjectDescriptor!!.sealedSubclasses
|
||||||
// When on a sealed class without derived members is considered non-exhaustive (see test WhenOnEmptySealed)
|
// When on a sealed class without derived members is considered non-exhaustive (see test WhenOnEmptySealed)
|
||||||
return getMissingClassCases(expression, memberClassDescriptors, context) +
|
return getMissingClassCases(expression, subclasses.toSet(), context) +
|
||||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isApplicable(subjectType: KotlinType): Boolean {
|
override fun isApplicable(subjectType: KotlinType): Boolean {
|
||||||
return DescriptorUtils.isSealedClass(TypeUtils.getClassDescriptor(subjectType))
|
return DescriptorUtils.isSealedClass(TypeUtils.getClassDescriptor(subjectType))
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun getNestedSubclasses(baseDescriptor: ClassDescriptor): Set<ClassDescriptor> {
|
|
||||||
val memberClassDescriptors = LinkedHashSet<ClassDescriptor>()
|
|
||||||
collectNestedSubclasses(baseDescriptor, baseDescriptor, memberClassDescriptors)
|
|
||||||
return memberClassDescriptors
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectNestedSubclasses(
|
|
||||||
baseDescriptor: ClassDescriptor,
|
|
||||||
currentDescriptor: ClassDescriptor,
|
|
||||||
subclasses: MutableSet<ClassDescriptor>
|
|
||||||
) {
|
|
||||||
fun collectSubclasses(scope: MemberScope, collectNested: Boolean) {
|
|
||||||
for (descriptor in scope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS)) {
|
|
||||||
if (descriptor is ClassDescriptor) {
|
|
||||||
if (DescriptorUtils.isDirectSubclass(descriptor, baseDescriptor)) subclasses.add(descriptor)
|
|
||||||
|
|
||||||
if (collectNested) collectNestedSubclasses(baseDescriptor, descriptor, subclasses)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (currentDescriptor == baseDescriptor && DescriptorUtils.isTopLevelDeclaration(currentDescriptor)) {
|
|
||||||
collectSubclasses((currentDescriptor.containingDeclaration as PackageFragmentDescriptor).getMemberScope(), collectNested = false)
|
|
||||||
}
|
|
||||||
collectSubclasses(currentDescriptor.unsubstitutedInnerClassesScope, collectNested = true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+5
@@ -83,6 +83,11 @@ class SyntheticClassOrObjectDescriptor(
|
|||||||
override fun getDeclaredTypeParameters() = emptyList<TypeParameterDescriptor>()
|
override fun getDeclaredTypeParameters() = emptyList<TypeParameterDescriptor>()
|
||||||
override fun getStaticScope() = MemberScope.Empty
|
override fun getStaticScope() = MemberScope.Empty
|
||||||
override fun getUnsubstitutedMemberScope() = unsubstitutedMemberScope
|
override fun getUnsubstitutedMemberScope() = unsubstitutedMemberScope
|
||||||
|
override fun getSealedSubclasses() = emptyList<ClassDescriptor>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
assert(modality != Modality.SEALED) { "Implement getSealedSubclasses() for this class: $javaClass" }
|
||||||
|
}
|
||||||
|
|
||||||
override fun getDeclaredCallableMembers(): List<CallableMemberDescriptor> =
|
override fun getDeclaredCallableMembers(): List<CallableMemberDescriptor> =
|
||||||
DescriptorUtils.getAllDescriptors(unsubstitutedMemberScope).filterIsInstance<CallableMemberDescriptor>().filter {
|
DescriptorUtils.getAllDescriptors(unsubstitutedMemberScope).filterIsInstance<CallableMemberDescriptor>().filter {
|
||||||
|
|||||||
+17
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.psi.*;
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
|
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
|
||||||
import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor;
|
import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor;
|
||||||
import org.jetbrains.kotlin.resolve.*;
|
import org.jetbrains.kotlin.resolve.*;
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
|
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
|
||||||
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext;
|
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext;
|
||||||
import org.jetbrains.kotlin.resolve.lazy.LazyEntity;
|
import org.jetbrains.kotlin.resolve.lazy.LazyEntity;
|
||||||
@@ -112,6 +113,8 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
|
|||||||
|
|
||||||
private final NotNullLazyValue<LexicalScope> scopeForInitializerResolution;
|
private final NotNullLazyValue<LexicalScope> scopeForInitializerResolution;
|
||||||
|
|
||||||
|
private final NotNullLazyValue<Collection<ClassDescriptor>> sealedSubclasses;
|
||||||
|
|
||||||
public LazyClassDescriptor(
|
public LazyClassDescriptor(
|
||||||
@NotNull final LazyClassContext c,
|
@NotNull final LazyClassContext c,
|
||||||
@NotNull DeclarationDescriptor containingDeclaration,
|
@NotNull DeclarationDescriptor containingDeclaration,
|
||||||
@@ -289,6 +292,14 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
|
|||||||
classLikeInfo.getPrimaryConstructorParameters());
|
classLikeInfo.getPrimaryConstructorParameters());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.sealedSubclasses = storageManager.createLazyValue(new Function0<Collection<ClassDescriptor>>() {
|
||||||
|
@Override
|
||||||
|
public Collection<ClassDescriptor> invoke() {
|
||||||
|
// TODO: only consider classes from the same file, not the whole package fragment
|
||||||
|
return DescriptorUtilsKt.computeSealedSubclasses(LazyClassDescriptor.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -549,6 +560,12 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
|
|||||||
return danglingAnnotations;
|
return danglingAnnotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Collection<ClassDescriptor> getSealedSubclasses() {
|
||||||
|
return sealedSubclasses.invoke();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
// not using descriptor render to preserve laziness
|
// not using descriptor render to preserve laziness
|
||||||
|
|||||||
+5
-1
@@ -41,6 +41,10 @@ open class KnownClassDescriptor(
|
|||||||
private val visibility: Visibility,
|
private val visibility: Visibility,
|
||||||
override val annotations: Annotations
|
override val annotations: Annotations
|
||||||
) : ClassDescriptor {
|
) : ClassDescriptor {
|
||||||
|
init {
|
||||||
|
assert(modality != Modality.SEALED) { "Implement getSealedSubclasses() for this class: $javaClass" }
|
||||||
|
}
|
||||||
|
|
||||||
private lateinit var typeConstructor: TypeConstructor
|
private lateinit var typeConstructor: TypeConstructor
|
||||||
private lateinit var supertypes: List<KotlinType>
|
private lateinit var supertypes: List<KotlinType>
|
||||||
private lateinit var defaultType: SimpleType
|
private lateinit var defaultType: SimpleType
|
||||||
@@ -114,6 +118,7 @@ open class KnownClassDescriptor(
|
|||||||
override fun getContainingDeclaration(): DeclarationDescriptor = containingDeclaration
|
override fun getContainingDeclaration(): DeclarationDescriptor = containingDeclaration
|
||||||
override fun getDeclaredTypeParameters(): List<TypeParameterDescriptor> = declaredTypeParameters
|
override fun getDeclaredTypeParameters(): List<TypeParameterDescriptor> = declaredTypeParameters
|
||||||
override fun getKind(): ClassKind = kind
|
override fun getKind(): ClassKind = kind
|
||||||
|
override fun getSealedSubclasses(): Collection<ClassDescriptor> = emptyList()
|
||||||
|
|
||||||
override fun getMemberScope(typeArguments: MutableList<out TypeProjection>): MemberScope = MemberScope.Empty
|
override fun getMemberScope(typeArguments: MutableList<out TypeProjection>): MemberScope = MemberScope.Empty
|
||||||
override fun getMemberScope(typeSubstitution: TypeSubstitution): MemberScope = MemberScope.Empty
|
override fun getMemberScope(typeSubstitution: TypeSubstitution): MemberScope = MemberScope.Empty
|
||||||
@@ -153,4 +158,3 @@ open class KnownClassDescriptor(
|
|||||||
override fun toString(): String =
|
override fun toString(): String =
|
||||||
"KnownClassDescriptor($fqNameUnsafe)"
|
"KnownClassDescriptor($fqNameUnsafe)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -135,6 +135,8 @@ class LazyJavaClassDescriptor(
|
|||||||
|
|
||||||
override fun getFunctionTypeForSamInterface(): SimpleType? = c.components.samConversionResolver.resolveFunctionTypeIfSamInterface(this)
|
override fun getFunctionTypeForSamInterface(): SimpleType? = c.components.samConversionResolver.resolveFunctionTypeIfSamInterface(this)
|
||||||
|
|
||||||
|
override fun getSealedSubclasses(): Collection<ClassDescriptor> = emptyList()
|
||||||
|
|
||||||
override fun toString() = "Lazy Java class ${this.fqNameUnsafe}"
|
override fun toString() = "Lazy Java class ${this.fqNameUnsafe}"
|
||||||
|
|
||||||
private inner class LazyJavaClassTypeConstructor : AbstractClassTypeConstructor(c.storageManager) {
|
private inner class LazyJavaClassTypeConstructor : AbstractClassTypeConstructor(c.storageManager) {
|
||||||
|
|||||||
+2
-1
@@ -106,7 +106,8 @@ class FunctionClassDescriptor(
|
|||||||
override fun isImpl() = false
|
override fun isImpl() = false
|
||||||
override fun isExternal() = false
|
override fun isExternal() = false
|
||||||
override val annotations: Annotations get() = Annotations.EMPTY
|
override val annotations: Annotations get() = Annotations.EMPTY
|
||||||
override fun getSource() = SourceElement.NO_SOURCE
|
override fun getSource(): SourceElement = SourceElement.NO_SOURCE
|
||||||
|
override fun getSealedSubclasses() = emptyList<ClassDescriptor>()
|
||||||
|
|
||||||
override fun getDeclaredTypeParameters() = parameters
|
override fun getDeclaredTypeParameters() = parameters
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,13 @@ public interface ClassDescriptor extends ClassifierDescriptorWithTypeParameters,
|
|||||||
@NotNull
|
@NotNull
|
||||||
List<TypeParameterDescriptor> getDeclaredTypeParameters();
|
List<TypeParameterDescriptor> getDeclaredTypeParameters();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return direct subclasses of this class if it's a sealed class, empty list otherwise
|
||||||
|
*/
|
||||||
|
@ReadOnly
|
||||||
|
@NotNull
|
||||||
|
Collection<ClassDescriptor> getSealedSubclasses();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
ClassDescriptor getOriginal();
|
ClassDescriptor getOriginal();
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public class ClassDescriptorImpl extends ClassDescriptorBase {
|
|||||||
boolean isExternal
|
boolean isExternal
|
||||||
) {
|
) {
|
||||||
super(LockBasedStorageManager.NO_LOCKS, containingDeclaration, name, source, isExternal);
|
super(LockBasedStorageManager.NO_LOCKS, containingDeclaration, name, source, isExternal);
|
||||||
|
assert modality != Modality.SEALED : "Implement getSealedSubclasses() for this class: " + getClass();
|
||||||
this.modality = modality;
|
this.modality = modality;
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
|
|
||||||
@@ -161,4 +162,10 @@ public class ClassDescriptorImpl extends ClassDescriptorBase {
|
|||||||
public List<TypeParameterDescriptor> getDeclaredTypeParameters() {
|
public List<TypeParameterDescriptor> getDeclaredTypeParameters() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Collection<ClassDescriptor> getSealedSubclasses() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -187,6 +187,12 @@ public class EnumEntrySyntheticClassDescriptor extends ClassDescriptorBase {
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Collection<ClassDescriptor> getSealedSubclasses() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
private class EnumEntryScope extends MemberScopeImpl {
|
private class EnumEntryScope extends MemberScopeImpl {
|
||||||
private final MemoizedFunctionToNotNull<Name, Collection<SimpleFunctionDescriptor>> functions;
|
private final MemoizedFunctionToNotNull<Name, Collection<SimpleFunctionDescriptor>> functions;
|
||||||
private final MemoizedFunctionToNotNull<Name, Collection<PropertyDescriptor>> properties;
|
private final MemoizedFunctionToNotNull<Name, Collection<PropertyDescriptor>> properties;
|
||||||
|
|||||||
+6
@@ -270,4 +270,10 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor {
|
|||||||
getSubstitutor();
|
getSubstitutor();
|
||||||
return declaredTypeParameters;
|
return declaredTypeParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Collection<ClassDescriptor> getSealedSubclasses() {
|
||||||
|
return original.getSealedSubclasses();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeProjection
|
import org.jetbrains.kotlin.types.TypeProjection
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
@@ -351,3 +353,33 @@ fun ClassifierDescriptor.getAllSuperClassifiers(): Sequence<ClassifierDescriptor
|
|||||||
|
|
||||||
return doGetAllSuperClassesAndInterfaces()
|
return doGetAllSuperClassesAndInterfaces()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note this is a generic and slow implementation which would work almost for any subclass of ClassDescriptor.
|
||||||
|
// Please avoid using it in new code.
|
||||||
|
// TODO: do something more clever instead at call sites of this function
|
||||||
|
fun computeSealedSubclasses(sealedClass: ClassDescriptor): Collection<ClassDescriptor> {
|
||||||
|
if (sealedClass.modality != Modality.SEALED) return emptyList()
|
||||||
|
|
||||||
|
val result = linkedSetOf<ClassDescriptor>()
|
||||||
|
|
||||||
|
fun collectSubclasses(scope: MemberScope, collectNested: Boolean) {
|
||||||
|
for (descriptor in scope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS)) {
|
||||||
|
if (descriptor !is ClassDescriptor) continue
|
||||||
|
|
||||||
|
if (DescriptorUtils.isDirectSubclass(descriptor, sealedClass)) {
|
||||||
|
result.add(descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collectNested) {
|
||||||
|
collectSubclasses(descriptor.unsubstitutedInnerClassesScope, collectNested)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val container = sealedClass.containingDeclaration
|
||||||
|
if (container is PackageFragmentDescriptor) {
|
||||||
|
collectSubclasses(container.getMemberScope(), collectNested = false)
|
||||||
|
}
|
||||||
|
collectSubclasses(sealedClass.unsubstitutedInnerClassesScope, collectNested = true)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
+1
@@ -110,6 +110,7 @@ class NotFoundClasses(private val storageManager: StorageManager, private val mo
|
|||||||
override fun getConstructors(): Collection<ClassConstructorDescriptor> = emptySet()
|
override fun getConstructors(): Collection<ClassConstructorDescriptor> = emptySet()
|
||||||
override fun getUnsubstitutedPrimaryConstructor(): ClassConstructorDescriptor? = null
|
override fun getUnsubstitutedPrimaryConstructor(): ClassConstructorDescriptor? = null
|
||||||
override fun getCompanionObjectDescriptor(): ClassDescriptor? = null
|
override fun getCompanionObjectDescriptor(): ClassDescriptor? = null
|
||||||
|
override fun getSealedSubclasses(): Collection<ClassDescriptor> = emptyList()
|
||||||
|
|
||||||
override fun toString() = "class $name (not found)"
|
override fun toString() = "class $name (not found)"
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-1
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.DescriptorFactory
|
|||||||
import org.jetbrains.kotlin.resolve.NonReportingOverrideStrategy
|
import org.jetbrains.kotlin.resolve.NonReportingOverrideStrategy
|
||||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.computeSealedSubclasses
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.StaticScopeForKotlinEnum
|
import org.jetbrains.kotlin.resolve.scopes.StaticScopeForKotlinEnum
|
||||||
@@ -46,7 +47,7 @@ class DeserializedClassDescriptor(
|
|||||||
val classProto: ProtoBuf.Class,
|
val classProto: ProtoBuf.Class,
|
||||||
nameResolver: NameResolver,
|
nameResolver: NameResolver,
|
||||||
private val sourceElement: SourceElement
|
private val sourceElement: SourceElement
|
||||||
) : ClassDescriptor, AbstractClassDescriptor(
|
) : AbstractClassDescriptor(
|
||||||
outerContext.storageManager,
|
outerContext.storageManager,
|
||||||
nameResolver.getClassId(classProto.fqName).shortClassName
|
nameResolver.getClassId(classProto.fqName).shortClassName
|
||||||
) {
|
) {
|
||||||
@@ -67,6 +68,7 @@ class DeserializedClassDescriptor(
|
|||||||
private val primaryConstructor = c.storageManager.createNullableLazyValue { computePrimaryConstructor() }
|
private val primaryConstructor = c.storageManager.createNullableLazyValue { computePrimaryConstructor() }
|
||||||
private val constructors = c.storageManager.createLazyValue { computeConstructors() }
|
private val constructors = c.storageManager.createLazyValue { computeConstructors() }
|
||||||
private val companionObjectDescriptor = c.storageManager.createNullableLazyValue { computeCompanionObjectDescriptor() }
|
private val companionObjectDescriptor = c.storageManager.createNullableLazyValue { computeCompanionObjectDescriptor() }
|
||||||
|
private val sealedSubclasses = c.storageManager.createLazyValue { computeSubclassesForSealedClass() }
|
||||||
|
|
||||||
internal val thisAsProtoContainer: ProtoContainer.Class = ProtoContainer.Class(
|
internal val thisAsProtoContainer: ProtoContainer.Class = ProtoContainer.Class(
|
||||||
classProto, c.nameResolver, c.typeTable, sourceElement,
|
classProto, c.nameResolver, c.typeTable, sourceElement,
|
||||||
@@ -147,6 +149,13 @@ class DeserializedClassDescriptor(
|
|||||||
internal fun hasNestedClass(name: Name): Boolean =
|
internal fun hasNestedClass(name: Name): Boolean =
|
||||||
name in memberScope.classNames
|
name in memberScope.classNames
|
||||||
|
|
||||||
|
private fun computeSubclassesForSealedClass(): Collection<ClassDescriptor> {
|
||||||
|
// TODO: store the list of subclasses to metadata
|
||||||
|
return computeSealedSubclasses(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSealedSubclasses() = sealedSubclasses()
|
||||||
|
|
||||||
override fun toString() = "deserialized class $name" // not using descriptor render to preserve laziness
|
override fun toString() = "deserialized class $name" // not using descriptor render to preserve laziness
|
||||||
|
|
||||||
override fun getSource() = sourceElement
|
override fun getSource() = sourceElement
|
||||||
|
|||||||
Reference in New Issue
Block a user