org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtils.kt Maven / Gradle / Ivy
/*
* 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