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

org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtils.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC
Show newest version
/*
 * Copyright 2010-2016 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.scopes.utils

import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.types.error.ErrorClassDescriptor
import org.jetbrains.kotlin.types.error.ErrorEntity
import org.jetbrains.kotlin.types.error.ErrorUtils
import org.jetbrains.kotlin.util.collectionUtils.concat
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.SmartList

val HierarchicalScope.parentsWithSelf: Sequence
    get() = generateSequence(this) { it.parent }

val HierarchicalScope.parents: Sequence
    get() = parentsWithSelf.drop(1)

/**
 * Adds receivers to the list in order of locality, so that the closest (the most local) receiver goes first
 */
fun LexicalScope.getImplicitReceiversHierarchy(): List = collectFromMeAndParent {
    if (it is LexicalScope) listOfNotNull(it.implicitReceiver) + it.contextReceiversGroup else null
}.flatten()

fun LexicalScope.getDeclarationsByLabel(labelName: Name): Collection = collectAllFromMeAndParent {
    if (it is LexicalScope && it.isOwnerDescriptorAccessibleByLabel && it.ownerDescriptor.name == labelName) {
        listOf(it.ownerDescriptor)
    } else {
        listOf()
    }
}

// Result is guaranteed to be filtered by kind and name.
fun HierarchicalScope.collectDescriptorsFiltered(
    kindFilter: DescriptorKindFilter = DescriptorKindFilter.ALL,
    nameFilter: (Name) -> Boolean = MemberScope.ALL_NAME_FILTER,
    changeNamesForAliased: Boolean = false
): Collection {
    if (kindFilter.kindMask == 0) return listOf()
    return collectAllFromMeAndParent {
        if (it is ImportingScope)
            it.getContributedDescriptors(kindFilter, nameFilter, changeNamesForAliased)
        else
            it.getContributedDescriptors(kindFilter, nameFilter)
    }.filter { kindFilter.accepts(it) && nameFilter(it.name) }
}

@Deprecated("Use getContributedProperties instead")
fun LexicalScope.findLocalVariable(name: Name): VariableDescriptor? {
    return findFirstFromMeAndParent { originalScope ->
        // Unpacking LexicalScopeWrapper may be important to check that it is not ImportingScope
        val possiblyUnpackedScope = when (originalScope) {
            is LexicalScopeWrapper -> originalScope.delegate
            else -> originalScope
        }

        when {
            possiblyUnpackedScope !is ImportingScope && possiblyUnpackedScope !is LexicalChainedScope ->
                possiblyUnpackedScope.getContributedVariables(
                    name,
                    NoLookupLocation.WHEN_GET_LOCAL_VARIABLE
                ).singleOrNull() /* todo check this*/

            else -> null
        }
    }
}

fun HierarchicalScope.findClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? =
    findFirstFromMeAndParent { it.getContributedClassifier(name, location) }

fun DeclarationDescriptor.canBeResolvedWithoutDeprecation(
    scopeForResolution: HierarchicalScope,
    location: LookupLocation
): Boolean {
    for (scope in scopeForResolution.parentsWithSelf) {
        val hasNonDeprecatedSuitableCandidate = when (this) {
            // Looking for classifier: fair check via special method in ResolutionScope
            is ClassifierDescriptor -> scope.getContributedClassifierIncludeDeprecated(name, location)
                ?.let { it.descriptor == this && !it.isDeprecated }

            // Looking for member: heuristically check only one case, when another descriptor visible through explicit import
            is VariableDescriptor -> (scope as? ImportingScope)?.getContributedVariables(name, location)?.any { it == this }

            is FunctionDescriptor -> (scope as? ImportingScope)?.getContributedFunctions(name, location)?.any { it == this }

            else -> null
        }

        if (hasNonDeprecatedSuitableCandidate == true) return true
    }

    return false
}

fun HierarchicalScope.findFirstClassifierWithDeprecationStatus(
    name: Name,
    location: LookupLocation
): DescriptorWithDeprecation? {
    return findFirstFromMeAndParent { it.getContributedClassifierIncludeDeprecated(name, location) }
}

fun HierarchicalScope.findPackage(name: Name): PackageViewDescriptor? = findFirstFromImportingScopes { it.getContributedPackage(name) }

fun HierarchicalScope.collectVariables(name: Name, location: LookupLocation): Collection =
    collectAllFromMeAndParent { it.getContributedVariables(name, location) }

fun HierarchicalScope.collectFunctions(name: Name, location: LookupLocation): Collection =
    collectAllFromMeAndParent { it.getContributedFunctions(name, location) }

fun HierarchicalScope.findVariable(
    name: Name,
    location: LookupLocation,
    predicate: (VariableDescriptor) -> Boolean = { true }
): VariableDescriptor? {
    processForMeAndParent {
        it.getContributedVariables(name, location).firstOrNull(predicate)?.let { return it }
    }
    return null
}

fun HierarchicalScope.findFunction(
    name: Name,
    location: LookupLocation,
    predicate: (FunctionDescriptor) -> Boolean = { true }
): FunctionDescriptor? {
    processForMeAndParent {
        it.getContributedFunctions(name, location).firstOrNull(predicate)?.let { return it }
    }
    return null
}

fun HierarchicalScope.takeSnapshot(): HierarchicalScope = if (this is LexicalWritableScope) takeSnapshot() else this

@JvmOverloads
fun MemberScope.memberScopeAsImportingScope(parentScope: ImportingScope? = null): ImportingScope =
    MemberScopeToImportingScopeAdapter(parentScope, this)

private class MemberScopeToImportingScopeAdapter(override val parent: ImportingScope?, val memberScope: MemberScope) : ImportingScope {
    override fun getContributedPackage(name: Name): PackageViewDescriptor? = null

    override fun getContributedDescriptors(
        kindFilter: DescriptorKindFilter,
        nameFilter: (Name) -> Boolean,
        changeNamesForAliased: Boolean
    ) = memberScope.getContributedDescriptors(kindFilter, nameFilter)

    override fun getContributedClassifier(name: Name, location: LookupLocation) = memberScope.getContributedClassifier(name, location)

    override fun getContributedVariables(name: Name, location: LookupLocation) = memberScope.getContributedVariables(name, location)

    override fun getContributedFunctions(name: Name, location: LookupLocation) = memberScope.getContributedFunctions(name, location)

    override fun equals(other: Any?) = other is MemberScopeToImportingScopeAdapter && other.memberScope == memberScope

    override fun hashCode() = memberScope.hashCode()

    override fun toString() = "${this::class.java.simpleName} for $memberScope"

    override fun computeImportedNames() = memberScope.computeAllNames()

    override fun printStructure(p: Printer) {
        p.println(this::class.java.simpleName)
        p.pushIndent()

        memberScope.printScopeStructure(p.withholdIndentOnce())

        p.popIndent()
        p.println("}")
    }
}

inline fun HierarchicalScope.processForMeAndParent(process: (HierarchicalScope) -> Unit) {
    var currentScope = this
    while (true) {
        process(currentScope)
        currentScope = currentScope.parent ?: break
    }
}

private inline fun  HierarchicalScope.collectFromMeAndParent(
    collect: (HierarchicalScope) -> T?
): List {
    var result: MutableList? = null
    processForMeAndParent {
        val element = collect(it)
        if (element != null) {
            if (result == null) {
                result = SmartList()
            }
            result!!.add(element)
        }
    }
    return result ?: emptyList()
}

inline fun  HierarchicalScope.collectAllFromMeAndParent(
    collect: (HierarchicalScope) -> Collection
): Collection {
    var result: Collection? = null
    processForMeAndParent { result = result.concat(collect(it)) }
    return result ?: emptySet()
}

inline fun  HierarchicalScope.findFirstFromMeAndParent(fetch: (HierarchicalScope) -> T?): T? {
    processForMeAndParent { fetch(it)?.let { return it } }
    return null
}

inline fun  HierarchicalScope.collectAllFromImportingScopes(
    collect: (ImportingScope) -> Collection
): Collection {
    return collectAllFromMeAndParent { if (it is ImportingScope) collect(it) else emptyList() }
}

inline fun  HierarchicalScope.findFirstFromImportingScopes(fetch: (ImportingScope) -> T?): T? {
    return findFirstFromMeAndParent { if (it is ImportingScope) fetch(it) else null }
}

fun LexicalScope.addImportingScopes(importScopes: List): LexicalScope {
    val lastLexicalScope = parentsWithSelf.last { it is LexicalScope }
    val firstImporting = lastLexicalScope.parent as ImportingScope
    val newFirstImporting = chainImportingScopes(importScopes, firstImporting)
    return replaceImportingScopes(newFirstImporting)
}

fun LexicalScope.addImportingScope(importScope: ImportingScope): LexicalScope = addImportingScopes(listOf(importScope))

fun ImportingScope.withParent(newParent: ImportingScope?): ImportingScope {
    return object : ImportingScope by this {
        override val parent: ImportingScope?
            get() = newParent
    }
}

fun LexicalScope.replaceImportingScopes(importingScopeChain: ImportingScope?): LexicalScope {
    val newImportingScopeChain = importingScopeChain ?: ImportingScope.Empty
    if (this is LexicalScopeWrapper) {
        return LexicalScopeWrapper(this.delegate, newImportingScopeChain)
    }
    return LexicalScopeWrapper(this, newImportingScopeChain)
}

fun LexicalScope.createScopeForDestructuring(newReceiver: ReceiverParameterDescriptor?): LexicalScope {
    return LexicalScopeImpl(
        parent, ownerDescriptor, isOwnerDescriptorAccessibleByLabel,
        newReceiver, listOf(),
        LexicalScopeKind.FUNCTION_HEADER_FOR_DESTRUCTURING
    )
}

private class LexicalScopeWrapper(
    val delegate: LexicalScope,
    private val newImportingScopeChain: ImportingScope
) : LexicalScope by delegate {
    init {
        assert(delegate !is LexicalScopeWrapper) {
            "Do not wrap again to avoid performance issues"
        }
    }

    override val parent: HierarchicalScope by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
        assert(delegate !is ImportingScope)

        val parent = delegate.parent
        if (parent is LexicalScope) {
            parent.replaceImportingScopes(newImportingScopeChain)
        } else {
            newImportingScopeChain
        }
    }

    override fun toString() = kind.toString()
}

fun chainImportingScopes(scopes: List, tail: ImportingScope? = null): ImportingScope? {
    return scopes.asReversed()
        .fold(tail) { current, scope ->
            assert(scope.parent == null)
            scope.withParent(current)
        }
}

class ErrorLexicalScope : LexicalScope {
    override val parent: HierarchicalScope = object : HierarchicalScope {
        override val parent: HierarchicalScope? = null

        override fun printStructure(p: Printer) {
            p.print(ErrorEntity.PARENT_OF_ERROR_SCOPE.debugText)
        }

        override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null

        override fun getContributedVariables(name: Name, location: LookupLocation): Collection = emptySet()

        override fun getContributedFunctions(name: Name, location: LookupLocation): Collection = emptySet()

        override fun getContributedDescriptors(
            kindFilter: DescriptorKindFilter,
            nameFilter: (Name) -> Boolean
        ): Collection = emptySet()
    }

    override fun printStructure(p: Printer) {
        p.print(ErrorEntity.ERROR_SCOPE.debugText)
    }

    override val ownerDescriptor: DeclarationDescriptor =
        ErrorClassDescriptor(Name.special(ErrorEntity.ERROR_CLASS.debugText.format("unknown")))
    override val isOwnerDescriptorAccessibleByLabel: Boolean = false
    override val implicitReceiver: ReceiverParameterDescriptor? = null
    override val contextReceiversGroup: List = emptyList()
    override val kind: LexicalScopeKind = LexicalScopeKind.THROWING

    override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null

    override fun getContributedVariables(name: Name, location: LookupLocation): Collection = emptySet()

    override fun getContributedFunctions(name: Name, location: LookupLocation): Collection = emptySet()

    override fun getContributedDescriptors(
        kindFilter: DescriptorKindFilter,
        nameFilter: (Name) -> Boolean
    ): Collection = emptySet()
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy