Refactor DelegationChecker and related code
- move getDelegates from CodegenUtil to DelegationResolver, reuse it in DelegationChecker - use getAllOverriddenDescriptors + filterOutOverridden instead of a manual DFS
This commit is contained in:
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DELEGATION
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
|
||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
@@ -27,6 +28,8 @@ import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Res
|
||||
import org.jetbrains.kotlin.resolve.lazy.DelegationFilter
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.isDynamic
|
||||
import org.jetbrains.kotlin.utils.keysToMapExceptNulls
|
||||
|
||||
class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
||||
private val classOrObject: KtPureClassOrObject,
|
||||
@@ -124,5 +127,40 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
||||
private fun isOverridableBy(memberOne: CallableDescriptor, memberTwo: CallableDescriptor): Boolean =
|
||||
OverridingUtil.DEFAULT.isOverridableBy(memberOne, memberTwo, null).result == OVERRIDABLE
|
||||
|
||||
// class Foo : Bar by baz
|
||||
// descriptor = Foo
|
||||
// toInterface = Bar
|
||||
// delegateExpressionType = typeof(baz)
|
||||
// return Map<member of Foo, corresponding member of typeOf(baz)>
|
||||
fun getDelegates(
|
||||
descriptor: ClassDescriptor,
|
||||
toInterface: ClassDescriptor,
|
||||
delegateExpressionType: KotlinType? = null
|
||||
): Map<CallableMemberDescriptor, CallableMemberDescriptor> {
|
||||
if (delegateExpressionType?.isDynamic() ?: false) return emptyMap()
|
||||
|
||||
val delegatedMembers = descriptor.defaultType.memberScope.getContributedDescriptors().asSequence()
|
||||
.filterIsInstance<CallableMemberDescriptor>()
|
||||
.filter { it.kind == CallableMemberDescriptor.Kind.DELEGATION }
|
||||
.asIterable()
|
||||
.sortedWith(MemberComparator.INSTANCE)
|
||||
|
||||
return delegatedMembers
|
||||
.keysToMapExceptNulls { delegatingMember ->
|
||||
val actualDelegates = DescriptorUtils.getAllOverriddenDescriptors(delegatingMember)
|
||||
.filter { it.containingDeclaration == toInterface }
|
||||
.map { overriddenDescriptor ->
|
||||
val scope = (delegateExpressionType ?: toInterface.defaultType).memberScope
|
||||
val name = overriddenDescriptor.name
|
||||
|
||||
// this is the actual member of delegateExpressionType that we are delegating to
|
||||
(scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_OVERRIDES) +
|
||||
scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_OVERRIDES))
|
||||
.firstOrNull { it == overriddenDescriptor || OverridingUtil.overrides(it, overriddenDescriptor) }
|
||||
}
|
||||
|
||||
actualDelegates.firstOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,13 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DelegationResolver
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.MemberComparator
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.keysToMapExceptNulls
|
||||
|
||||
class DelegationChecker : SimpleDeclarationChecker {
|
||||
override fun check(
|
||||
@@ -43,16 +40,12 @@ class DelegationChecker : SimpleDeclarationChecker {
|
||||
if (descriptor !is ClassDescriptor) return
|
||||
if (declaration !is KtClassOrObject) return
|
||||
|
||||
val delegationDescriptors = descriptor.defaultType.memberScope.getContributedDescriptors().
|
||||
filterIsInstance<CallableMemberDescriptor>().filter { it.kind == CallableMemberDescriptor.Kind.DELEGATION }.sortedWith(MemberComparator.INSTANCE)
|
||||
|
||||
for (specifier in declaration.superTypeListEntries) {
|
||||
if (specifier is KtDelegatedSuperTypeEntry) {
|
||||
val superType = specifier.typeReference?.let { bindingContext.get(BindingContext.TYPE, it) } ?: continue
|
||||
val superTypeDescriptor = superType.constructor.declarationDescriptor as? ClassDescriptor ?: continue
|
||||
|
||||
val delegates = getDelegates(delegationDescriptors, superTypeDescriptor)
|
||||
delegates.forEach { (delegated, delegatedTo) ->
|
||||
for ((delegated, delegatedTo) in DelegationResolver.getDelegates(descriptor, superTypeDescriptor)) {
|
||||
checkDescriptor(declaration, delegated, delegatedTo, diagnosticHolder)
|
||||
}
|
||||
}
|
||||
@@ -65,57 +58,16 @@ class DelegationChecker : SimpleDeclarationChecker {
|
||||
delegatedToDescriptor: CallableMemberDescriptor,
|
||||
diagnosticHolder: DiagnosticSink
|
||||
) {
|
||||
val reachableFromDelegated = findAllReachableDeclarations(delegatedDescriptor)
|
||||
reachableFromDelegated.remove(delegatedDescriptor.original)
|
||||
val toRemove = linkedSetOf<CallableMemberDescriptor>()
|
||||
for (declaration in reachableFromDelegated) {
|
||||
val reachable = findAllReachableDeclarations(declaration.original)
|
||||
reachable.remove(declaration)
|
||||
toRemove.addAll(reachable)
|
||||
}
|
||||
reachableFromDelegated.removeAll(toRemove)
|
||||
reachableFromDelegated.remove(DescriptorUtils.unwrapFakeOverride(delegatedToDescriptor).original)
|
||||
val reachableFromDelegated =
|
||||
OverridingUtil.filterOutOverridden(
|
||||
DescriptorUtils.getAllOverriddenDescriptors(delegatedDescriptor).filter { it.kind.isReal }.toSet()
|
||||
) - DescriptorUtils.unwrapFakeOverride(delegatedToDescriptor).original
|
||||
|
||||
val nonAbstractReachable = reachableFromDelegated.filter { it.modality != Modality.ABSTRACT }
|
||||
|
||||
if (nonAbstractReachable.isNotEmpty()) {
|
||||
/*In case of MANY_IMPL_MEMBER_NOT_IMPLEMENTED error there could be several elements otherwise only one*/
|
||||
diagnosticHolder.report(DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE.on(classDeclaration, delegatedDescriptor, nonAbstractReachable.toList()))
|
||||
diagnosticHolder.report(DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE.on(classDeclaration, delegatedDescriptor, nonAbstractReachable))
|
||||
}
|
||||
}
|
||||
|
||||
fun getDelegates(
|
||||
delegatedMethods: Iterable<CallableMemberDescriptor>,
|
||||
toInterface: ClassDescriptor
|
||||
): Map<CallableMemberDescriptor, CallableMemberDescriptor> {
|
||||
return delegatedMethods
|
||||
.keysToMapExceptNulls { delegatingMember ->
|
||||
val actualDelegates = DescriptorUtils.getAllOverriddenDescriptors(delegatingMember)
|
||||
.filter { it.containingDeclaration == toInterface }
|
||||
.map { overriddenDescriptor ->
|
||||
val scope = toInterface.defaultType.memberScope
|
||||
val name = overriddenDescriptor.name
|
||||
|
||||
// this is the actual member of delegateExpressionType that we are delegating to
|
||||
(scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_OVERRIDES) +
|
||||
scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_OVERRIDES))
|
||||
.firstOrNull { it == overriddenDescriptor || OverridingUtil.overrides(it, overriddenDescriptor) }
|
||||
}
|
||||
|
||||
actualDelegates.firstOrNull() as? CallableMemberDescriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun findAllReachableDeclarations(memberDescriptor: CallableMemberDescriptor): MutableSet<CallableMemberDescriptor> {
|
||||
val collector = object : DFS.NodeHandlerWithListResult<CallableMemberDescriptor, CallableMemberDescriptor>() {
|
||||
override fun afterChildren(current: CallableMemberDescriptor) {
|
||||
if (current.kind.isReal) {
|
||||
result.add(current.original)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DFS.dfs(listOf(memberDescriptor), { it.overriddenDescriptors }, collector)
|
||||
return java.util.HashSet(collector.result())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user