All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.resolve.DelegationResolver.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-Beta1
Show newest version
/*
 * Copyright 2010-2015 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jetbrains.kotlin.resolve

import org.jetbrains.kotlin.config.LanguageVersionSettings
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
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE
import org.jetbrains.kotlin.resolve.lazy.DelegationFilter
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.utils.keysToMapExceptNulls

class DelegationResolver private constructor(
        private val classOrObject: KtPureClassOrObject,
        private val ownerDescriptor: ClassDescriptor,
        private val existingMembers: Collection,
        private val trace: BindingTrace,
        private val memberExtractor: MemberExtractor,
        private val typeResolver: TypeResolver,
        private val delegationFilter: DelegationFilter,
        private val languageVersionSettings: LanguageVersionSettings
) {

    private fun generateDelegatedMembers(): Collection {
        val delegatedMembers = hashSetOf()
        for (delegationSpecifier in classOrObject.superTypeListEntries) {
            if (delegationSpecifier !is KtDelegatedSuperTypeEntry) {
                continue
            }
            val typeReference = delegationSpecifier.typeReference ?: continue
            val delegatedInterfaceType = typeResolver.resolve(typeReference)
            if (delegatedInterfaceType == null || delegatedInterfaceType.isError) {
                continue
            }
            val delegatesForInterface = generateDelegatesForInterface(delegatedMembers, delegatedInterfaceType)
            delegatedMembers.addAll(delegatesForInterface)
        }
        return delegatedMembers
    }

    private fun generateDelegatesForInterface(existingDelegates: Collection, delegatedInterfaceType: KotlinType): Collection =
            generateDelegationCandidates(delegatedInterfaceType).filter { candidate ->
                !isOverridingAnyOf(candidate, existingMembers) &&
                !checkClashWithOtherDelegatedMember(candidate, existingDelegates)
            }

    private fun generateDelegationCandidates(delegatedInterfaceType: KotlinType): Collection =
            getDelegatableMembers(delegatedInterfaceType).map { memberDescriptor ->
                val newModality = if (memberDescriptor.modality == Modality.ABSTRACT) Modality.OPEN else memberDescriptor.modality
                @Suppress("UNCHECKED_CAST")
                memberDescriptor.newCopyBuilder()
                        .setOwner(ownerDescriptor)
                        .setDispatchReceiverParameter(ownerDescriptor.thisAsReceiverParameter)
                        .setModality(newModality)
                        .setVisibility(Visibilities.INHERITED)
                        .setKind(DELEGATION)
                        .setCopyOverrides(false)
                        .build() as T
            }

    private fun checkClashWithOtherDelegatedMember(candidate: T, delegatedMembers: Collection): Boolean {
        val alreadyDelegated = delegatedMembers.firstOrNull { isOverridableBy(it, candidate) }
        if (alreadyDelegated != null) {
            if (classOrObject is KtClassOrObject) // report errors only for physical (non-synthetic) classes or objects
                trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(classOrObject, classOrObject, alreadyDelegated))
            return true
        }
        return false
    }


    private fun getDelegatableMembers(interfaceType: KotlinType): Collection =
            memberExtractor.getMembersByType(interfaceType).filter { descriptor ->
                descriptor.isOverridable &&
                (descriptor.kind.isReal || !descriptor.overridesClassMembersOnly()) &&
                delegationFilter.filter(descriptor, languageVersionSettings)
            }

    private fun T.overridesClassMembersOnly() =
            DescriptorUtils.getAllOverriddenDeclarations(this).all {
                DescriptorUtils.isClass(it.containingDeclaration)
            }

    interface MemberExtractor {
        fun getMembersByType(type: KotlinType): Collection
    }

    interface TypeResolver {
        fun resolve(reference: KtTypeReference): KotlinType?
    }

    companion object {
        fun  generateDelegatedMembers(
                classOrObject: KtPureClassOrObject,
                ownerDescriptor: ClassDescriptor,
                existingMembers: Collection,
                trace: BindingTrace,
                memberExtractor: MemberExtractor,
                typeResolver: TypeResolver,
                delegationFilter: DelegationFilter,
                languageVersionSettings: LanguageVersionSettings
        ): Collection =
                DelegationResolver(classOrObject, ownerDescriptor, existingMembers, trace, memberExtractor, typeResolver, delegationFilter, languageVersionSettings)
                        .generateDelegatedMembers()

        private fun isOverridingAnyOf(
                candidate: CallableMemberDescriptor,
                possiblyOverriddenBy: Collection
        ): Boolean =
                possiblyOverriddenBy.any { isOverridableBy(it, candidate) }

        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
        fun getDelegates(
                descriptor: ClassDescriptor,
                toInterface: ClassDescriptor,
                delegateExpressionType: KotlinType? = null
        ): Map {
            if (delegateExpressionType?.isDynamic() ?: false) return emptyMap()

            val delegatedMembers = descriptor.defaultType.memberScope.getContributedDescriptors().asSequence()
                    .filterIsInstance()
                    .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()
                    }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy