summaryrefslogtreecommitdiff
path: root/plugins/kotlin/uast/uast-kotlin/tests/test/org/jetbrains/uast/test/kotlin/AbstractKotlinUastTest.kt
blob: 2d168759d9afe1a5ccc0eb5df01ef927e13b1308 (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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// 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.test.kotlin

import com.intellij.mock.MockComponentManager
import com.intellij.mock.MockProject
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.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.util.io.URLUtil
import org.jetbrains.kotlin.idea.checkers.CompilerTestLanguageVersionSettings
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.idea.artifacts.KotlinArtifacts
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.idea.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinRoot
import org.jetbrains.kotlin.idea.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.idea.test.testFramework.resetApplicationToNull
import org.jetbrains.uast.UastLanguagePlugin
import org.jetbrains.uast.evaluation.UEvaluatorExtension
import org.jetbrains.uast.kotlin.BaseKotlinUastResolveProviderService
import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin
import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService
import org.jetbrains.uast.kotlin.evaluation.KotlinEvaluatorExtension
import org.jetbrains.uast.kotlin.internal.CliKotlinUastResolveProviderService
import org.jetbrains.uast.kotlin.internal.UastAnalysisHandlerExtension
import org.jetbrains.uast.test.env.AbstractCoreEnvironment
import org.jetbrains.uast.test.kotlin.env.AbstractUastTest
import java.io.File

abstract class AbstractKotlinUastTest : AbstractUastTest() {

    private lateinit var compilerConfiguration: CompilerConfiguration
    private var kotlinCoreEnvironment: KotlinCoreEnvironment? = null

    open var testDataDir: File = KotlinRoot.DIR.resolve("uast/uast-kotlin/tests/testData")

    override fun getVirtualFile(testName: String): VirtualFile {
        val testFile = testDataDir.listFiles { pathname -> pathname.nameWithoutExtension == testName }.first()

        super.initializeEnvironment(testFile)

        initializeKotlinEnvironment()

        enableNewTypeInferenceIfNeeded()

        val trace = NoScopeRecordCliBindingTrace()

        val environment = kotlinCoreEnvironment!!
        TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
            project, environment.getSourceFiles(), trace, compilerConfiguration, environment::createPackagePartProvider
        )

        val vfs = VirtualFileManager.getInstance().getFileSystem(URLUtil.FILE_PROTOCOL)

        val ideaProject = project
        ideaProject.baseDir = vfs.findFileByPath(TEST_KOTLIN_MODEL_DIR.canonicalPath)

        return vfs.findFileByPath(testFile.canonicalPath)!!
    }

    private fun enableNewTypeInferenceIfNeeded() {
        val currentLanguageVersionSettings = compilerConfiguration.languageVersionSettings
        if (currentLanguageVersionSettings.supportsFeature(LanguageFeature.NewInference)) return

        val extraLanguageFeatures = mutableMapOf<LanguageFeature, LanguageFeature.State>()
        val extraAnalysisFlags = mutableMapOf<AnalysisFlag<*>, Any?>()

        if (currentLanguageVersionSettings is CompilerTestLanguageVersionSettings) {
            extraLanguageFeatures += currentLanguageVersionSettings.extraLanguageFeatures
            extraAnalysisFlags += currentLanguageVersionSettings.analysisFlags
        }

        compilerConfiguration.languageVersionSettings = CompilerTestLanguageVersionSettings(
            extraLanguageFeatures + (LanguageFeature.NewInference to LanguageFeature.State.ENABLED),
            currentLanguageVersionSettings.apiVersion,
            currentLanguageVersionSettings.languageVersion,
            extraAnalysisFlags
        )
    }

    private fun initializeKotlinEnvironment() {
        val area = Extensions.getRootArea()
        area.getExtensionPoint(UastLanguagePlugin.extensionPointName).registerExtension(KotlinUastLanguagePlugin(), project)
        area.getExtensionPoint(UEvaluatorExtension.EXTENSION_POINT_NAME).registerExtension(KotlinEvaluatorExtension(), project)

        val application = ApplicationManager.getApplication() as MockComponentManager
        application.registerService(
            BaseKotlinUastResolveProviderService::class.java,
            CliKotlinUastResolveProviderService::class.java
        )
        project.registerService(
            KotlinUastResolveProviderService::class.java,
            CliKotlinUastResolveProviderService::class.java
        )
    }

    override fun createEnvironment(source: File): AbstractCoreEnvironment {
        val appWasNull = ApplicationManager.getApplication() == null
        compilerConfiguration = createKotlinCompilerConfiguration(source)
        compilerConfiguration.put(JVMConfigurationKeys.USE_PSI_CLASS_FILES_READING, true)
        compilerConfiguration.put(CLIConfigurationKeys.PATH_TO_KOTLIN_COMPILER_JAR, KotlinArtifacts.instance.kotlinCompiler)

        val parentDisposable = Disposer.newDisposable()
        val kotlinCoreEnvironment =
            KotlinCoreEnvironment.createForTests(parentDisposable, compilerConfiguration, EnvironmentConfigFiles.JVM_CONFIG_FILES)

        this.kotlinCoreEnvironment = kotlinCoreEnvironment

        AnalysisHandlerExtension.registerExtension(
            kotlinCoreEnvironment.project, UastAnalysisHandlerExtension()
        )

        return KotlinCoreEnvironmentWrapper(kotlinCoreEnvironment, parentDisposable, appWasNull)
    }

    override fun tearDown() {
        kotlinCoreEnvironment = null
        super.tearDown()
    }

    private fun createKotlinCompilerConfiguration(sourceFile: File): CompilerConfiguration {
        return KotlinTestUtils.newConfiguration(ConfigurationKind.STDLIB_REFLECT, TestJdkKind.FULL_JDK).apply {
            addKotlinSourceRoot(sourceFile.canonicalPath)

            val messageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_RELATIVE_PATHS, true)
            put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)

            put(CommonConfigurationKeys.MODULE_NAME, "test-module")

            if (sourceFile.extension == KotlinParserDefinition.STD_SCRIPT_SUFFIX) {
                loadScriptingPlugin(this)
            }
        }
    }

    private class KotlinCoreEnvironmentWrapper(
        val environment: KotlinCoreEnvironment,
        val parentDisposable: Disposable,
        val appWasNull: Boolean
    ) : AbstractCoreEnvironment() {
        override fun addJavaSourceRoot(root: File) {
            TODO("not implemented")
        }

        override fun addJar(root: File) {
            TODO("not implemented")
        }

        override val project: MockProject
            get() = environment.project as MockProject

        override fun dispose() {
            Disposer.dispose(parentDisposable)
            if (appWasNull) {
                resetApplicationToNull()
            }
        }
    }
}

val TEST_KOTLIN_MODEL_DIR = KotlinRoot.DIR.resolve("uast/uast-kotlin/tests/testData")

private fun loadScriptingPlugin(configuration: CompilerConfiguration) {
    val artifacts = KotlinArtifacts.instance
    val pluginClasspath = listOf(
        artifacts.kotlinScriptingCompiler,
        artifacts.kotlinScriptingCompilerImpl,
        artifacts.kotlinScriptingCommon,
        artifacts.kotlinScriptingJvm
    ).map { it.absolutePath }

    PluginCliParser.loadPluginsSafe(pluginClasspath, null, configuration)
}