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

org.jetbrains.kotlin.resolve.OverloadUtil.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 com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.INCOMPATIBLE
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeIntersector
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.oneMoreSpecificThanAnother

object OverloadUtil {

    /**
     * Does not check names.
     */
    public @JvmStatic fun isOverloadable(a: CallableDescriptor, b: CallableDescriptor): Boolean {
        val abc = braceCount(a)
        val bbc = braceCount(b)

        if (abc != bbc) {
            return true
        }

        val receiverAndParameterResult = OverridingUtil.checkReceiverAndParameterCount(a, b)
        if (receiverAndParameterResult != null) {
            return receiverAndParameterResult.result == INCOMPATIBLE
        }

        val aValueParameters = OverridingUtil.compiledValueParameters(a)
        val bValueParameters = OverridingUtil.compiledValueParameters(b)

        for ((aType, bType) in aValueParameters.zip(bValueParameters)) {
            // TODO: check type parameters, create a substitution and compare parameter types according to it, like in OverridingUtil
            val superValueParameterType = aType.upperBound
            val subValueParameterType = bType.upperBound
            if (!KotlinTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType) ||
                oneMoreSpecificThanAnother(subValueParameterType, superValueParameterType)) {
                return true
            }
        }

        return false
    }

    private fun braceCount(a: CallableDescriptor): Int =
            when (a) {
                is PropertyDescriptor -> 0
                is SimpleFunctionDescriptor -> 1
                is ConstructorDescriptor -> 1
                else -> throw IllegalStateException()
            }

    private val KotlinType.upperBound: KotlinType
        get() {
            val classifier = constructor.declarationDescriptor
            return when (classifier) {
                is ClassDescriptor -> this
                is TypeParameterDescriptor -> TypeIntersector.getUpperBoundsAsType(classifier)
                else -> error("Unknown type constructor: $this")
            }
        }

    public @JvmStatic fun groupModulePackageMembersByFqName(
            c: BodiesResolveContext,
            constructorsInPackages: MultiMap,
            overloadFilter: OverloadFilter
    ): MultiMap {
        val packageMembersByName = MultiMap()

        collectModulePackageMembersWithSameName(packageMembersByName, c.functions.values, overloadFilter) {
            scope, name ->
            scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS)
        }

        collectModulePackageMembersWithSameName(packageMembersByName, c.properties.values, overloadFilter) {
            scope, name ->
            scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_REDECLARATIONS).filterIsInstance()
        }

        // TODO handle constructor redeclarations in modules. See also: https://youtrack.jetbrains.com/issue/KT-3632
        packageMembersByName.putAllValues(constructorsInPackages)

        return packageMembersByName
    }

    private inline fun collectModulePackageMembersWithSameName(
            packageMembersByName: MultiMap,
            interestingDescriptors: Collection,
            overloadFilter: OverloadFilter,
            getMembersByName: (MemberScope, Name) -> Collection
    ) {
        val observedFQNs = hashSetOf()
        for (descriptor in interestingDescriptors) {
            if (descriptor.containingDeclaration !is PackageFragmentDescriptor) continue

            val descriptorFQN = DescriptorUtils.getFqName(descriptor)
            if (observedFQNs.contains(descriptorFQN)) continue
            observedFQNs.add(descriptorFQN)

            val packageMembersWithSameName = getModulePackageMembersWithSameName(descriptor, overloadFilter, getMembersByName)
            packageMembersByName.putValues(descriptorFQN, packageMembersWithSameName)
        }
    }

    private inline fun getModulePackageMembersWithSameName(
            packageMember: CallableMemberDescriptor,
            overloadFilter: OverloadFilter,
            getMembersByName: (MemberScope, Name) -> Collection
    ): Collection {
        val containingPackage = packageMember.containingDeclaration
        if (containingPackage !is PackageFragmentDescriptor) {
            throw AssertionError("$packageMember is not a top-level package member")
        }

        val containingModule = DescriptorUtils.getContainingModuleOrNull(packageMember) ?: return listOf(packageMember)

        val containingPackageScope = containingModule.getPackage(containingPackage.fqName).memberScope
        val possibleOverloads =
                getMembersByName(containingPackageScope, packageMember.name).filter {
                    // NB memberScope for PackageViewDescriptor includes module dependencies
                    DescriptorUtils.getContainingModule(it) == containingModule
                }

        return overloadFilter.filterPackageMemberOverloads(possibleOverloads)
    }

    private fun MemberDescriptor.isPrivate() = Visibilities.isPrivate(this.visibility)

    public @JvmStatic fun getPossibleRedeclarationGroups(members: Collection): Collection> {
        val result = arrayListOf>()

        val nonPrivates = members.filter { !it.isPrivate() }
        if (nonPrivates.size > 1) {
            result.add(nonPrivates)
        }

        val bySourceFile = MultiMap.createSmart()
        for (member in members) {
            val sourceFile = DescriptorUtils.getContainingSourceFile(member)
            if (sourceFile != SourceFile.NO_SOURCE_FILE) {
                bySourceFile.putValue(sourceFile, member)
            }
        }

        for ((sourceFile, membersInFile) in bySourceFile.entrySet()) {
            // File member groups are interesting in redeclaration check if at least one file member is private.
            if (membersInFile.size > 1 && membersInFile.any { it.isPrivate() }) {
                result.add(membersInFile)
            }
        }

        return result
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy