Move calculating dependencies from script sources to plugin
This commit is contained in:
@@ -74,7 +74,6 @@ import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PRO
|
||||
import org.jetbrains.kotlin.cli.common.config.ContentRoot
|
||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
|
||||
import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING
|
||||
@@ -112,7 +111,6 @@ import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtens
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.CliDeclarationProviderFactoryService
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import java.io.File
|
||||
import java.lang.reflect.Field
|
||||
@@ -199,9 +197,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
|
||||
sourceFiles += createKtFiles(project)
|
||||
|
||||
val (newSourcesClasspath, newSources, _) = collectScriptsCompilationDependencies(configuration, project, sourceFiles)
|
||||
configuration.addJvmClasspathRoots(newSourcesClasspath)
|
||||
sourceFiles += newSources
|
||||
collectAdditionalSources(project)
|
||||
|
||||
sourceFiles.sortBy { it.virtualFile.path }
|
||||
|
||||
@@ -267,6 +263,32 @@ class KotlinCoreEnvironment private constructor(
|
||||
})
|
||||
}
|
||||
|
||||
private fun collectAdditionalSources(project: MockProject) {
|
||||
var unprocessedSources: Collection<KtFile> = sourceFiles
|
||||
val processedSources = HashSet<KtFile>()
|
||||
val processedSourcesByExtension = HashMap<CollectAdditionalSourcesExtension, Collection<KtFile>>()
|
||||
// repeat feeding extensions with sources while new sources a being added
|
||||
var sourceCollectionIterations = 0
|
||||
while (unprocessedSources.isNotEmpty()) {
|
||||
if (sourceCollectionIterations++ > 10) { // TODO: consider using some appropriate global constant
|
||||
throw IllegalStateException("Unable to collect additional sources in reasonable number of iterations")
|
||||
}
|
||||
processedSources.addAll(unprocessedSources)
|
||||
val allNewSources = ArrayList<KtFile>()
|
||||
for (extension in CollectAdditionalSourcesExtension.getInstances(project)) {
|
||||
// do not feed the extension with the sources it returned on the previous iteration
|
||||
val sourcesToProcess = unprocessedSources - (processedSourcesByExtension[extension] ?: emptyList())
|
||||
val newSources = extension.collectAdditionalSourcesAndUpdateConfiguration(sourcesToProcess, configuration, project)
|
||||
if (newSources.isNotEmpty()) {
|
||||
allNewSources.addAll(newSources)
|
||||
processedSourcesByExtension[extension] = newSources
|
||||
}
|
||||
}
|
||||
unprocessedSources = allNewSources.filterNot { processedSources.contains(it) }.distinct()
|
||||
sourceFiles += unprocessedSources
|
||||
}
|
||||
}
|
||||
|
||||
fun createPackagePartProvider(scope: GlobalSearchScope): JvmPackagePartProvider {
|
||||
return JvmPackagePartProvider(configuration.languageVersionSettings, scope).apply {
|
||||
addRoots(initialRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY))
|
||||
@@ -383,7 +405,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
private fun createKtFiles(project: Project): List<KtFile> =
|
||||
createSourceFilesFromSourceRoots(configuration, project, getSourceRootsCheckingForDuplicates())
|
||||
|
||||
internal fun report(severity: CompilerMessageSeverity, message: String) = report(configuration, severity, message)
|
||||
internal fun report(severity: CompilerMessageSeverity, message: String) = configuration.report(severity, message)
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(KotlinCoreEnvironment::class.java)
|
||||
@@ -436,67 +458,6 @@ class KotlinCoreEnvironment private constructor(
|
||||
// used in the daemon for jar cache cleanup
|
||||
val applicationEnvironment: JavaCoreApplicationEnvironment? get() = ourApplicationEnvironment
|
||||
|
||||
internal fun report(
|
||||
configuration: CompilerConfiguration,
|
||||
severity: CompilerMessageSeverity,
|
||||
message: String,
|
||||
location: CompilerMessageLocation? = null
|
||||
) {
|
||||
configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(severity, message, location)
|
||||
}
|
||||
|
||||
internal fun createSourceFilesFromSourceRoots(
|
||||
configuration: CompilerConfiguration,
|
||||
project: Project,
|
||||
sourceRoots: List<KotlinSourceRoot>,
|
||||
reportLocation: CompilerMessageLocation? = null
|
||||
): MutableList<KtFile> {
|
||||
val localFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
|
||||
val processedFiles = hashSetOf<VirtualFile>()
|
||||
val result = mutableListOf<KtFile>()
|
||||
|
||||
val virtualFileCreator = PreprocessedFileCreator(project)
|
||||
|
||||
for ((sourceRootPath, isCommon) in sourceRoots) {
|
||||
val vFile = localFileSystem.findFileByPath(sourceRootPath)
|
||||
if (vFile == null) {
|
||||
val message = "Source file or directory not found: $sourceRootPath"
|
||||
|
||||
val buildFilePath = configuration.get(JVMConfigurationKeys.MODULE_XML_FILE)
|
||||
if (buildFilePath != null && Logger.isInitialized()) {
|
||||
KotlinCoreEnvironment.LOG.warn("$message\n\nbuild file path: $buildFilePath\ncontent:\n${buildFilePath.readText()}")
|
||||
}
|
||||
|
||||
report(configuration, ERROR, message, reportLocation)
|
||||
continue
|
||||
}
|
||||
|
||||
if (!vFile.isDirectory && vFile.fileType != KotlinFileType.INSTANCE) {
|
||||
report(configuration, ERROR, "Source entry is not a Kotlin file: $sourceRootPath", reportLocation)
|
||||
continue
|
||||
}
|
||||
|
||||
for (file in File(sourceRootPath).walkTopDown()) {
|
||||
if (!file.isFile) continue
|
||||
|
||||
val virtualFile = localFileSystem.findFileByPath(file.absolutePath)?.let(virtualFileCreator::create)
|
||||
if (virtualFile != null && processedFiles.add(virtualFile)) {
|
||||
val psiFile = psiManager.findFile(virtualFile)
|
||||
if (psiFile is KtFile) {
|
||||
result.add(psiFile)
|
||||
if (isCommon) {
|
||||
psiFile.isCommonSource = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun getOrCreateApplicationEnvironmentForProduction(configuration: CompilerConfiguration): JavaCoreApplicationEnvironment {
|
||||
synchronized(APPLICATION_LOCK) {
|
||||
if (ourApplicationEnvironment != null)
|
||||
@@ -632,6 +593,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
PreprocessedVirtualFileFactoryExtension.registerExtensionPoint(project)
|
||||
JsSyntheticTranslateExtension.registerExtensionPoint(project)
|
||||
CompilerConfigurationExtension.registerExtensionPoint(project)
|
||||
CollectAdditionalSourcesExtension.registerExtensionPoint(project)
|
||||
IrGenerationExtension.registerExtensionPoint(project)
|
||||
}
|
||||
|
||||
@@ -728,8 +690,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
|
||||
if (!CoreJrtFileSystem.isModularJdk(javaRoot)) {
|
||||
if (classesRoots.isEmpty()) {
|
||||
val messageCollector = get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
messageCollector?.report(ERROR, "No class roots are found in the JDK path: $javaRoot")
|
||||
report(ERROR, "No class roots are found in the JDK path: $javaRoot")
|
||||
} else {
|
||||
addJvmSdkRoots(classesRoots)
|
||||
}
|
||||
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.kotlin.cli.jvm.compiler
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
|
||||
import java.io.File
|
||||
|
||||
data class ScriptsCompilationDependencies(
|
||||
val classpath: List<File>,
|
||||
val sources: List<KtFile>,
|
||||
val sourceDependencies: List<SourceDependencies>
|
||||
) {
|
||||
data class SourceDependencies(
|
||||
val scriptFile: KtFile,
|
||||
val sourceDependencies: List<KtFile>
|
||||
)
|
||||
}
|
||||
|
||||
// recursively collect dependencies from initial and imported scripts
|
||||
fun collectScriptsCompilationDependencies(
|
||||
configuration: CompilerConfiguration,
|
||||
project: Project,
|
||||
initialSources: Iterable<KtFile>
|
||||
): ScriptsCompilationDependencies {
|
||||
val collectedClassPath = ArrayList<File>()
|
||||
val collectedSources = ArrayList<KtFile>()
|
||||
val collectedSourceDependencies = ArrayList<ScriptsCompilationDependencies.SourceDependencies>()
|
||||
var remainingSources = initialSources
|
||||
val knownSourcePaths = initialSources.mapNotNullTo(HashSet()) { it.virtualFile?.path }
|
||||
val importsProvider = ScriptDependenciesProvider.getInstance(project)
|
||||
if (importsProvider != null) {
|
||||
while (true) {
|
||||
val newRemainingSources = ArrayList<KtFile>()
|
||||
for (source in remainingSources) {
|
||||
val dependencies = importsProvider.getScriptDependencies(source)
|
||||
if (dependencies != null) {
|
||||
collectedClassPath.addAll(dependencies.classpath)
|
||||
|
||||
val sourceDependenciesRoots = dependencies.scripts.map {
|
||||
KotlinSourceRoot(it.path, false)
|
||||
}
|
||||
val sourceDependencies =
|
||||
KotlinCoreEnvironment.createSourceFilesFromSourceRoots(
|
||||
configuration, project, sourceDependenciesRoots,
|
||||
// TODO: consider receiving and using precise location from the resolver in the future
|
||||
source.virtualFile?.path?.let { CompilerMessageLocation.create(it) }
|
||||
)
|
||||
if (sourceDependencies.isNotEmpty()) {
|
||||
collectedSourceDependencies.add(ScriptsCompilationDependencies.SourceDependencies(source, sourceDependencies))
|
||||
|
||||
val newSources = sourceDependencies.filterNot { knownSourcePaths.contains(it.virtualFile.path) }
|
||||
for (newSource in newSources) {
|
||||
collectedSources.add(newSource)
|
||||
newRemainingSources.add(newSource)
|
||||
knownSourcePaths.add(newSource.virtualFile.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newRemainingSources.isEmpty()) break
|
||||
else {
|
||||
remainingSources = newRemainingSources
|
||||
}
|
||||
}
|
||||
}
|
||||
return ScriptsCompilationDependencies(
|
||||
collectedClassPath.distinctBy { it.absolutePath },
|
||||
collectedSources,
|
||||
collectedSourceDependencies
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.kotlin.cli.jvm.compiler
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.extensions.PreprocessedFileCreator
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
|
||||
import java.io.File
|
||||
|
||||
fun CompilerConfiguration.report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation? = null) {
|
||||
get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)?.report(severity, message, location)
|
||||
}
|
||||
|
||||
fun createSourceFilesFromSourceRoots(
|
||||
configuration: CompilerConfiguration,
|
||||
project: Project,
|
||||
sourceRoots: List<KotlinSourceRoot>,
|
||||
reportLocation: CompilerMessageLocation? = null
|
||||
): MutableList<KtFile> {
|
||||
val localFileSystem = VirtualFileManager.getInstance()
|
||||
.getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
|
||||
val processedFiles = hashSetOf<VirtualFile>()
|
||||
val result = mutableListOf<KtFile>()
|
||||
|
||||
val virtualFileCreator = PreprocessedFileCreator(project)
|
||||
|
||||
for ((sourceRootPath, isCommon) in sourceRoots) {
|
||||
val vFile = localFileSystem.findFileByPath(sourceRootPath)
|
||||
if (vFile == null) {
|
||||
val message = "Source file or directory not found: $sourceRootPath"
|
||||
|
||||
val buildFilePath = configuration.get(JVMConfigurationKeys.MODULE_XML_FILE)
|
||||
if (buildFilePath != null && Logger.isInitialized()) {
|
||||
Logger.getInstance(KotlinCoreEnvironment::class.java)
|
||||
.warn("$message\n\nbuild file path: $buildFilePath\ncontent:\n${buildFilePath.readText()}")
|
||||
}
|
||||
|
||||
configuration.report(CompilerMessageSeverity.ERROR, message, reportLocation)
|
||||
continue
|
||||
}
|
||||
|
||||
if (!vFile.isDirectory && vFile.fileType != KotlinFileType.INSTANCE) {
|
||||
configuration.report(CompilerMessageSeverity.ERROR, "Source entry is not a Kotlin file: $sourceRootPath", reportLocation)
|
||||
continue
|
||||
}
|
||||
|
||||
for (file in File(sourceRootPath).walkTopDown()) {
|
||||
if (!file.isFile) continue
|
||||
|
||||
val virtualFile = localFileSystem.findFileByPath(file.absolutePath)?.let(virtualFileCreator::create)
|
||||
if (virtualFile != null && processedFiles.add(virtualFile)) {
|
||||
val psiFile = psiManager.findFile(virtualFile)
|
||||
if (psiFile is KtFile) {
|
||||
result.add(psiFile)
|
||||
if (isCommon) {
|
||||
psiFile.isCommonSource = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user