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:
Alexander Udalov
2016-12-19 12:34:26 +03:00
parent 2dd7d89048
commit 482b43631c
8 changed files with 122 additions and 109 deletions
@@ -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())
}