[FE] Extract computation of sealed class inheritors into separate component

This is needed to provide more optimal provider in IDE plugin
This commit is contained in:
Dmitriy Novozhilov
2020-11-23 11:14:22 +03:00
committed by TeamCityServer
parent c0a1aecf9b
commit 6809adee9c
10 changed files with 87 additions and 43 deletions
@@ -103,6 +103,7 @@ private fun StorageComponentContainer.configurePlatformIndependentComponents() {
useImpl<ClassicTypeSystemContextForCS>() useImpl<ClassicTypeSystemContextForCS>()
useImpl<ClassicConstraintSystemUtilContext>() useImpl<ClassicConstraintSystemUtilContext>()
useInstance(ProgressManagerBasedCancellationChecker) useInstance(ProgressManagerBasedCancellationChecker)
useInstance(SealedClassInheritorsProviderImpl)
} }
/** /**
@@ -48,4 +48,5 @@ interface LazyClassContext {
val kotlinTypeChecker: NewKotlinTypeChecker val kotlinTypeChecker: NewKotlinTypeChecker
val samConversionResolver: SamConversionResolver val samConversionResolver: SamConversionResolver
val additionalClassPartsProvider: AdditionalClassPartsProvider val additionalClassPartsProvider: AdditionalClassPartsProvider
val sealedClassInheritorsProvider: SealedClassInheritorsProvider
} }
@@ -85,6 +85,7 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
private WrappedTypeFactory wrappedTypeFactory; private WrappedTypeFactory wrappedTypeFactory;
private PlatformDiagnosticSuppressor platformDiagnosticSuppressor; private PlatformDiagnosticSuppressor platformDiagnosticSuppressor;
private SamConversionResolver samConversionResolver; private SamConversionResolver samConversionResolver;
private SealedClassInheritorsProvider sealedClassInheritorsProvider;
private AdditionalClassPartsProvider additionalClassPartsProvider; private AdditionalClassPartsProvider additionalClassPartsProvider;
@@ -164,6 +165,11 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
this.additionalClassPartsProvider = additionalClassPartsProvider; this.additionalClassPartsProvider = additionalClassPartsProvider;
} }
@Inject
public void setSealedClassInheritorsProvider(@NotNull SealedClassInheritorsProvider sealedClassInheritorsProvider) {
this.sealedClassInheritorsProvider = sealedClassInheritorsProvider;
}
// Only calls from injectors expected // Only calls from injectors expected
@Deprecated @Deprecated
public ResolveSession( public ResolveSession(
@@ -513,4 +519,10 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
public AdditionalClassPartsProvider getAdditionalClassPartsProvider() { public AdditionalClassPartsProvider getAdditionalClassPartsProvider() {
return additionalClassPartsProvider; return additionalClassPartsProvider;
} }
@NotNull
@Override
public SealedClassInheritorsProvider getSealedClassInheritorsProvider() {
return sealedClassInheritorsProvider;
}
} }
@@ -270,9 +270,8 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
) )
); );
// TODO: only consider classes from the same file, not the whole package fragment
boolean freedomForSealedInterfacesSupported = c.getLanguageVersionSettings().supportsFeature(LanguageFeature.FreedomForSealedClasses); boolean freedomForSealedInterfacesSupported = c.getLanguageVersionSettings().supportsFeature(LanguageFeature.FreedomForSealedClasses);
this.sealedSubclasses = storageManager.createLazyValue(() -> DescriptorUtilsKt.computeSealedSubclasses(this, freedomForSealedInterfacesSupported)); this.sealedSubclasses = storageManager.createLazyValue(() -> c.getSealedClassInheritorsProvider().computeSealedSubclasses(this, freedomForSealedInterfacesSupported));
} }
private static boolean isIllegalInner(@NotNull DeclarationDescriptor descriptor) { private static boolean isIllegalInner(@NotNull DeclarationDescriptor descriptor) {
@@ -71,6 +71,7 @@ class LocalClassifierAnalyzer(
private val kotlinTypeChecker: NewKotlinTypeChecker, private val kotlinTypeChecker: NewKotlinTypeChecker,
private val samConversionResolver: SamConversionResolver, private val samConversionResolver: SamConversionResolver,
private val additionalClassPartsProvider: AdditionalClassPartsProvider, private val additionalClassPartsProvider: AdditionalClassPartsProvider,
private val sealedClassInheritorsProvider: SealedClassInheritorsProvider
) { ) {
fun processClassOrObject( fun processClassOrObject(
scope: LexicalWritableScope?, scope: LexicalWritableScope?,
@@ -107,6 +108,7 @@ class LocalClassifierAnalyzer(
kotlinTypeChecker, kotlinTypeChecker,
samConversionResolver, samConversionResolver,
additionalClassPartsProvider, additionalClassPartsProvider,
sealedClassInheritorsProvider
), ),
analyzerServices analyzerServices
) )
@@ -138,6 +140,7 @@ class LocalClassDescriptorHolder(
val kotlinTypeChecker: NewKotlinTypeChecker, val kotlinTypeChecker: NewKotlinTypeChecker,
val samConversionResolver: SamConversionResolver, val samConversionResolver: SamConversionResolver,
val additionalClassPartsProvider: AdditionalClassPartsProvider, val additionalClassPartsProvider: AdditionalClassPartsProvider,
val sealedClassInheritorsProvider: SealedClassInheritorsProvider
) { ) {
// We do not need to synchronize here, because this code is used strictly from one thread // We do not need to synchronize here, because this code is used strictly from one thread
private var classDescriptor: ClassDescriptor? = null private var classDescriptor: ClassDescriptor? = null
@@ -181,6 +184,7 @@ class LocalClassDescriptorHolder(
override val samConversionResolver: SamConversionResolver = this@LocalClassDescriptorHolder.samConversionResolver override val samConversionResolver: SamConversionResolver = this@LocalClassDescriptorHolder.samConversionResolver
override val additionalClassPartsProvider: AdditionalClassPartsProvider = override val additionalClassPartsProvider: AdditionalClassPartsProvider =
this@LocalClassDescriptorHolder.additionalClassPartsProvider this@LocalClassDescriptorHolder.additionalClassPartsProvider
override val sealedClassInheritorsProvider: SealedClassInheritorsProvider = this@LocalClassDescriptorHolder.sealedClassInheritorsProvider
}, },
containingDeclaration, containingDeclaration,
classOrObject.nameAsSafeName, classOrObject.nameAsSafeName,
@@ -374,43 +374,6 @@ 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, freedomForSealedInterfacesSupported: Boolean): 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 = if (!freedomForSealedInterfacesSupported) {
sealedClass.containingDeclaration
} else {
sealedClass.parents.firstOrNull { it is PackageFragmentDescriptor }
}
if (container is PackageFragmentDescriptor) {
collectSubclasses(
container.getMemberScope(),
collectNested = freedomForSealedInterfacesSupported
)
}
collectSubclasses(sealedClass.unsubstitutedInnerClassesScope, collectNested = true)
return result
}
fun DeclarationDescriptor.isPublishedApi(): Boolean { fun DeclarationDescriptor.isPublishedApi(): Boolean {
val descriptor = if (this is CallableMemberDescriptor) DescriptorUtils.getDirectMember(this) else this val descriptor = if (this is CallableMemberDescriptor) DescriptorUtils.getDirectMember(this) else this
return descriptor.annotations.hasAnnotation(StandardNames.FqNames.publishedApi) return descriptor.annotations.hasAnnotation(StandardNames.FqNames.publishedApi)
@@ -0,0 +1,63 @@
/*
* 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.resolve
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
abstract class SealedClassInheritorsProvider {
abstract fun computeSealedSubclasses(
sealedClass: ClassDescriptor,
freedomForSealedInterfacesSupported: Boolean
): Collection<ClassDescriptor>
}
object SealedClassInheritorsProviderImpl : SealedClassInheritorsProvider() {
// 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
override fun computeSealedSubclasses(
sealedClass: ClassDescriptor,
freedomForSealedInterfacesSupported: Boolean
): 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 = if (!freedomForSealedInterfacesSupported) {
sealedClass.containingDeclaration
} else {
sealedClass.parents.firstOrNull { it is PackageFragmentDescriptor }
}
if (container is PackageFragmentDescriptor) {
collectSubclasses(
container.getMemberScope(),
collectNested = freedomForSealedInterfacesSupported
)
}
collectSubclasses(sealedClass.unsubstitutedInnerClassesScope, collectNested = true)
return result
}
}
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.* import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
import org.jetbrains.kotlin.resolve.SealedClassInheritorsProvider
import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.sam.SamConversionResolver import org.jetbrains.kotlin.resolve.sam.SamConversionResolver
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
@@ -18,8 +18,8 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorFactory 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.SealedClassInheritorsProviderImpl
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
@@ -165,7 +165,7 @@ class DeserializedClassDescriptor(
} }
// This is needed because classes compiled with Kotlin 1.0 did not contain the sealed_subclass_fq_name field // This is needed because classes compiled with Kotlin 1.0 did not contain the sealed_subclass_fq_name field
return computeSealedSubclasses(this, freedomForSealedInterfacesSupported = false) return SealedClassInheritorsProviderImpl.computeSealedSubclasses(this, freedomForSealedInterfacesSupported = false)
} }
override fun getSealedSubclasses() = sealedSubclasses() override fun getSealedSubclasses() = sealedSubclasses()
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorBase
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorFactory.createPrimaryConstructorForObject import org.jetbrains.kotlin.resolve.DescriptorFactory.createPrimaryConstructorForObject
import org.jetbrains.kotlin.resolve.descriptorUtil.computeSealedSubclasses import org.jetbrains.kotlin.resolve.SealedClassInheritorsProviderImpl
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
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
@@ -54,7 +54,7 @@ class CommonizedClassDescriptor(
private val typeConstructor = CommonizedClassTypeConstructor(targetComponents, cirSupertypes) private val typeConstructor = CommonizedClassTypeConstructor(targetComponents, cirSupertypes)
private val sealedSubclasses = targetComponents.storageManager.createLazyValue { private val sealedSubclasses = targetComponents.storageManager.createLazyValue {
// TODO: pass proper language version settings // TODO: pass proper language version settings
computeSealedSubclasses(this, freedomForSealedInterfacesSupported = false) SealedClassInheritorsProviderImpl.computeSealedSubclasses(this, freedomForSealedInterfacesSupported = false)
} }
private val declaredTypeParametersAndTypeParameterResolver = targetComponents.storageManager.createLazyValue { private val declaredTypeParametersAndTypeParameterResolver = targetComponents.storageManager.createLazyValue {