summaryrefslogtreecommitdiff
path: root/plugins/kotlin/uast/uast-kotlin-base/src/org/jetbrains/uast/kotlin/declarations/AbstractKotlinUVariable.kt
blob: f54c5d8316b31ca370e0a059ed8193fe612c134e (plain)
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// 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.uast.kotlin

import com.intellij.psi.*
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable

@ApiStatus.Internal
abstract class AbstractKotlinUVariable(
    givenParent: UElement?
) : KotlinAbstractUElement(givenParent), PsiVariable, UVariableEx, UAnchorOwner {

    override val uastInitializer: UExpression?
        get() {
            val psi = psi
            val initializerExpression = when (psi) {
                is UastKotlinPsiVariable -> psi.ktInitializer
                is UastKotlinPsiParameter -> psi.ktDefaultValue
                is KtLightElement<*, *> -> {
                    val origin = psi.kotlinOrigin?.takeIf { it.canAnalyze() } // EA-137191
                    when (origin) {
                        is KtVariableDeclaration -> origin.initializer
                        is KtParameter -> origin.defaultValue
                        else -> null
                    }
                }
                else -> null
            } ?: return null
            return languagePlugin?.convertElement(initializerExpression, this) as? UExpression ?: UastEmptyExpression(null)
        }

    protected val delegateExpression: UExpression? by lz {
        val psi = psi
        val expression = when (psi) {
            is KtLightElement<*, *> -> (psi.kotlinOrigin as? KtProperty)?.delegateExpression
            is UastKotlinPsiVariable -> (psi.ktElement as? KtProperty)?.delegateExpression
            else -> null
        }

        expression?.let { languagePlugin?.convertElement(it, this) as? UExpression }
    }

    override fun getNameIdentifier(): PsiIdentifier {
        val kotlinOrigin = (psi as? KtLightElement<*, *>)?.kotlinOrigin
        return UastLightIdentifier(psi, kotlinOrigin as? KtDeclaration)
    }

    override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile)

    override val uAnnotations by lz {
        val sourcePsi = sourcePsi ?: return@lz psi.annotations.map { WrappedUAnnotation(it, this) }
        val annotations = SmartList<UAnnotation>(KotlinNullabilityUAnnotation(baseResolveProviderService, sourcePsi, this))
        if (sourcePsi is KtModifierListOwner) {
            sourcePsi.annotationEntries
                .filter { acceptsAnnotationTarget(it.useSiteTarget?.getAnnotationUseSiteTarget()) }
                .mapTo(annotations) { baseResolveProviderService.baseKotlinConverter.convertAnnotation(it, this) }
        }
        annotations
    }

    protected abstract fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean

    override val typeReference: UTypeReferenceExpression? by lz {
        KotlinUTypeReferenceExpression((sourcePsi as? KtCallableDeclaration)?.typeReference, this) { type }
    }

    override val uastAnchor: UIdentifier?
        get() {
            val identifierSourcePsi = when (val sourcePsi = sourcePsi) {
                is KtNamedDeclaration -> sourcePsi.nameIdentifier
                is KtTypeReference -> sourcePsi.typeElement?.let {
                    // receiver param in extension function
                    (it as? KtUserType)?.referenceExpression?.getIdentifier() ?: it
                } ?: sourcePsi
                is KtNameReferenceExpression -> sourcePsi.getReferencedNameElement()
                is KtBinaryExpression, is KtCallExpression -> null // e.g. `foo("Lorem ipsum") ?: foo("dolor sit amet")`
                is KtDestructuringDeclaration -> sourcePsi.valOrVarKeyword
                is KtLambdaExpression -> sourcePsi.functionLiteral.lBrace
                else -> sourcePsi
            } ?: return null
            return KotlinUIdentifier(nameIdentifier, identifierSourcePsi, this)
        }

    override fun equals(other: Any?) = other is AbstractKotlinUVariable && psi == other.psi

    class WrappedUAnnotation(
        psiAnnotation: PsiAnnotation,
        override val uastParent: UElement
    ) : UAnnotation, UAnchorOwner, DelegatedMultiResolve {

        override val javaPsi: PsiAnnotation = psiAnnotation
        override val psi: PsiAnnotation = javaPsi
        override val sourcePsi: PsiElement? = psiAnnotation.safeAs<KtLightAbstractAnnotation>()?.kotlinOrigin

        override val attributeValues: List<UNamedExpression> by lz {
            psi.parameterList.attributes.map { WrappedUNamedExpression(it, this) }
        }

        override val uastAnchor: UIdentifier by lz {
            KotlinUIdentifier(
                { javaPsi.nameReferenceElement?.referenceNameElement },
                sourcePsi.safeAs<KtAnnotationEntry>()?.typeReference?.nameElement,
                this
            )
        }

        class WrappedUNamedExpression(
            pair: PsiNameValuePair,
            override val uastParent: UElement?
        ) : UNamedExpression {
            override val name: String? = pair.name
            override val psi = pair
            override val javaPsi: PsiElement = psi
            override val sourcePsi: PsiElement? = null
            override val uAnnotations: List<UAnnotation> = emptyList()
            override val expression: UExpression by lz { toUExpression(psi.value) }
        }

        override val qualifiedName: String? = psi.qualifiedName

        override fun findAttributeValue(name: String?): UExpression? =
            psi.findAttributeValue(name)?.let { toUExpression(it) }

        override fun findDeclaredAttributeValue(name: String?): UExpression? =
            psi.findDeclaredAttributeValue(name)?.let { toUExpression(it) }

        override fun resolve(): PsiClass? =
            psi.nameReferenceElement?.resolve() as? PsiClass
    }
}

private fun toUExpression(psi: PsiElement?): UExpression = psi.toUElementOfType() ?: UastEmptyExpression(null)