Use KotlinCoreEnvironment for parsing Kotlin in IC
Creating and disposing CoreApplicationEnvironment on each call leads to
problems with parallel builds, while KotlinCoreEnvironment
avoids disposing application environment in case of parallel builds.
#KT-23694 fixed
This commit is contained in:
+23
-57
@@ -5,44 +5,48 @@
|
||||
|
||||
package org.jetbrains.kotlin.incremental.parsing
|
||||
|
||||
import com.intellij.core.CoreApplicationEnvironment
|
||||
import com.intellij.core.CoreProjectEnvironment
|
||||
import com.intellij.lang.MetaLanguage
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.openapi.vfs.local.CoreLocalFileSystem
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.SingleRootFileViewProvider
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
|
||||
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
fun classesFqNames(files: Set<File>): Set<String> = withPsiSetup {
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
fun classesFqNames(files: Set<File>): Set<String> {
|
||||
val existingKotlinFiles = files.filter { it.name.endsWith(".kt", ignoreCase = true) && it.isFile }
|
||||
if (existingKotlinFiles.isEmpty()) return emptySet()
|
||||
|
||||
val disposable = Disposer.newDisposable()
|
||||
|
||||
return try {
|
||||
classesFqNames(existingKotlinFiles, disposable)
|
||||
} finally {
|
||||
Disposer.dispose(disposable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun classesFqNames(kotlinFiles: Collection<File>, disposable: Disposable): Set<String> {
|
||||
val config = CompilerConfiguration()
|
||||
val configFiles = EnvironmentConfigFiles.JVM_CONFIG_FILES
|
||||
val environment = KotlinCoreEnvironment.createForProduction(disposable, config, configFiles)
|
||||
val psiManager = PsiManager.getInstance(environment.project)
|
||||
val fileManager = VirtualFileManager.getInstance()
|
||||
val localFS = fileManager.getFileSystem(StandardFileSystems.FILE_PROTOCOL) as CoreLocalFileSystem
|
||||
|
||||
classesFqNames(files, psiManager, localFS)
|
||||
}
|
||||
|
||||
private fun classesFqNames(files: Collection<File>, psiManager: PsiManager, localFS: CoreLocalFileSystem): Set<String> {
|
||||
val result = HashSet<String>()
|
||||
|
||||
for (file in files) {
|
||||
if (!file.name.endsWith(".kt", ignoreCase = true)) continue
|
||||
|
||||
val virtualFile = localFS.findFileByIoFile(file) ?: continue
|
||||
for (file in kotlinFiles) {
|
||||
val virtualFile = localFS.findFileByIoFile(file)!!
|
||||
|
||||
for (psiFile in SingleRootFileViewProvider(psiManager, virtualFile).allFiles) {
|
||||
if (psiFile !is KtFile) continue
|
||||
@@ -65,41 +69,3 @@ private fun classesFqNames(files: Collection<File>, psiManager: PsiManager, loca
|
||||
private fun Collection<KtDeclaration>.filterClassesTo(classes: Deque<KtClassOrObject>) {
|
||||
filterIsInstanceTo<KtClassOrObject, Deque<KtClassOrObject>>(classes)
|
||||
}
|
||||
|
||||
private data class PsiSetup(
|
||||
val applicationEnvironment: CoreApplicationEnvironment,
|
||||
val projectEnvironment: CoreProjectEnvironment,
|
||||
val project: Project,
|
||||
val disposable: Disposable
|
||||
)
|
||||
|
||||
private inline fun <T> withPsiSetup(fn: PsiSetup.() -> T): T {
|
||||
val disposable = Disposer.newDisposable()
|
||||
|
||||
return try {
|
||||
val applicationEnvironment = CoreApplicationEnvironment(disposable, false)
|
||||
val projectEnvironment = CoreProjectEnvironment(disposable, applicationEnvironment)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), MetaLanguage.EP_NAME, MetaLanguage::class.java)
|
||||
applicationEnvironment.registerApplicationService(ScriptDefinitionProvider::class.java,
|
||||
NoopScriptDefinitionProvider()
|
||||
)
|
||||
applicationEnvironment.registerFileType(KotlinFileType.INSTANCE, "kt")
|
||||
applicationEnvironment.registerParserDefinition(KotlinParserDefinition())
|
||||
|
||||
val project = projectEnvironment.project
|
||||
val setup = PsiSetup(applicationEnvironment, projectEnvironment, project, disposable)
|
||||
setup.fn()
|
||||
} finally {
|
||||
Disposer.dispose(disposable)
|
||||
}
|
||||
}
|
||||
|
||||
private class NoopScriptDefinitionProvider : ScriptDefinitionProvider {
|
||||
override fun isScript(fileName: String): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun findScriptDefinition(fileName: String): KotlinScriptDefinition? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user