1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.kotlin.idea.references
import com.intellij.psi.*
import com.intellij.psi.impl.source.resolve.ResolveCache
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.safeAnalyze
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.util.application.runWithCancellationCheck
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import java.util.*
interface KtDescriptorsBasedReference : KtReference {
override val resolver get() = KotlinDescriptorsBasedReferenceResolver
fun resolveToDescriptors(bindingContext: BindingContext): Collection<DeclarationDescriptor> {
return getTargetDescriptors(bindingContext)
}
fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor>
override fun isReferenceTo(element: PsiElement): Boolean {
return matchesTarget(element)
}
}
fun KtReference.resolveToDescriptors(bindingContext: BindingContext): Collection<DeclarationDescriptor> {
if (this !is KtDescriptorsBasedReference) {
error("Reference $this should be KtDescriptorsBasedReference but was ${this::class}")
}
return resolveToDescriptors(bindingContext)
}
object KotlinDescriptorsBasedReferenceResolver : ResolveCache.PolyVariantResolver<KtReference> {
class KotlinResolveResult(element: PsiElement) : PsiElementResolveResult(element)
private fun resolveToPsiElements(ref: KtDescriptorsBasedReference): Collection<PsiElement> {
val bindingContext = ref.element.safeAnalyze(BodyResolveMode.PARTIAL)
if (bindingContext == BindingContext.EMPTY) return emptySet()
return resolveToPsiElements(ref, bindingContext, ref.getTargetDescriptors(bindingContext))
}
private fun resolveToPsiElements(
ref: KtDescriptorsBasedReference,
context: BindingContext,
targetDescriptors: Collection<DeclarationDescriptor>
): Collection<PsiElement> {
if (targetDescriptors.isNotEmpty()) {
return targetDescriptors.flatMap { target -> resolveToPsiElements(ref, target) }.toSet()
}
val labelTargets = getLabelTargets(ref, context)
if (labelTargets != null) {
return labelTargets
}
return Collections.emptySet()
}
private fun resolveToPsiElements(
ref: KtDescriptorsBasedReference,
targetDescriptor: DeclarationDescriptor
): Collection<PsiElement> {
return if (targetDescriptor is PackageViewDescriptor) {
val psiFacade = JavaPsiFacade.getInstance(ref.element.project)
val fqName = targetDescriptor.fqName.asString()
listOfNotNull(psiFacade.findPackage(fqName))
} else {
DescriptorToSourceUtilsIde.getAllDeclarations(ref.element.project, targetDescriptor, ref.element.resolveScope)
}
}
private fun getLabelTargets(ref: KtDescriptorsBasedReference, context: BindingContext): Collection<PsiElement>? {
val reference = ref.element as? KtReferenceExpression ?: return null
val labelTarget = context[BindingContext.LABEL_TARGET, reference]
if (labelTarget != null) {
return listOf(labelTarget)
}
return context[BindingContext.AMBIGUOUS_LABEL_TARGET, reference]
}
override fun resolve(ref: KtReference, incompleteCode: Boolean): Array<ResolveResult> {
return runWithCancellationCheck {
val resolveToPsiElements = resolveToPsiElements(ref as KtDescriptorsBasedReference)
resolveToPsiElements.map { KotlinResolveResult(it) }.toTypedArray()
}
}
}
|