File: KotlinUastReferencesTest.kt.191

package info (click to toggle)
kotlin 1.3.31%2Bds1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 109,908 kB
  • sloc: java: 454,756; xml: 18,599; javascript: 10,452; sh: 513; python: 97; makefile: 69; ansic: 4
file content (124 lines) | stat: -rw-r--r-- 4,733 bytes parent folder | download | duplicates (2)
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
/*
 * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
 * that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.uast.test.kotlin

import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.util.Disposer
import com.intellij.patterns.uast.injectionHostUExpression
import com.intellij.psi.*
import com.intellij.psi.impl.source.resolve.reference.PsiReferenceContributorEP
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistryImpl
import com.intellij.psi.util.PropertyUtil
import com.intellij.testFramework.LightProjectDescriptor
import com.intellij.testFramework.registerServiceInstance
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.uast.UExpression
import org.jetbrains.uast.evaluateString
import org.jetbrains.uast.toUElementOfType
import org.junit.Test
import kotlin.test.fail


class KotlinUastReferencesTest : KotlinLightCodeInsightFixtureTestCase() {

    override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE


    @Test
    fun `test original getter is visible when reference is under renaming`() {

        registerReferenceProviders(testRootDisposable) {
            registerUastReferenceProvider(injectionHostUExpression(), uastInjectionHostReferenceProvider { _, psiLanguageInjectionHost ->
                arrayOf(GetterReference("KotlinBean", psiLanguageInjectionHost))
            })
        }

        myFixture.configureByText(
            "KotlinBean.kt", """
            data class KotlinBean(val myF<caret>ield: String)

            val reference = "myField"

        """.trimIndent()
        )

        myFixture.renameElementAtCaret("myRenamedField")

        myFixture.checkResult(
            """
                data class KotlinBean(val myRenamedField: String)

                val reference = "myRenamedField"

        """.trimIndent()
        )

    }

}

private class GetterReference(
    val className: String,
    psiElement: PsiElement
) : PsiReferenceBase<PsiElement>(psiElement) {
    override fun resolve(): PsiMethod? {
        val psiClass = JavaPsiFacade.getInstance(element.project).findClass(className, element.resolveScope) ?: return null
        val name = element.toUElementOfType<UExpression>()?.evaluateString() ?: return null
        return PropertyUtil.getGetters(psiClass, name).firstOrNull()
    }

    override fun handleElementRename(newElementName: String): PsiElement {
        val resolve = resolve()
            ?: fail("can't resolve during rename, looks like someone renamed or removed the source element before updating references")

        val newName =
            if (PropertyUtil.getPropertyName(resolve) != null)
                PropertyUtil.getPropertyName(newElementName) ?: newElementName
            else newElementName

        return super.handleElementRename(newName)
    }

    override fun getVariants(): Array<Any> = emptyArray()
}


fun registerReferenceProviders(disposable: Disposable, registerContributors: PsiReferenceRegistrar.() -> Unit) {
    registerReferenceContributor(object : PsiReferenceContributor() {
        override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) = registrar.registerContributors()
    }, disposable)
}

fun registerReferenceContributor(contributor: PsiReferenceContributor, disposable: Disposable) {
    val referenceContributorEp = Extensions.getArea(null).getExtensionPoint<PsiReferenceContributorEP>(PsiReferenceContributor.EP_NAME.name)

    val contributorEp = object : PsiReferenceContributorEP() {
        override fun getInstance(): PsiReferenceContributor = contributor
    }

    referenceContributorEp.registerExtension(contributorEp)

    val application = ApplicationManager.getApplication()

    //we need a fresh ReferenceProvidersRegistry after updating ReferenceContributors
    val oldReferenceProviderRegistry =
        application.picoContainer.getComponentInstance(ReferenceProvidersRegistry::class.java) as ReferenceProvidersRegistry
    application.registerServiceInstance(ReferenceProvidersRegistry::class.java, ReferenceProvidersRegistryImpl())

    Disposer.register(disposable, Disposable {
        referenceContributorEp.unregisterExtension(contributorEp)
        application.registerServiceInstance(ReferenceProvidersRegistry::class.java, oldReferenceProviderRegistry)
    })

}