Scripts: pass script definition as parameter to loader (KT-32554)

This should avoid situation when script definition for file is changed between isApplicable and loadDependencies calls

^KT-32554 Fixed
This commit is contained in:
Natalia Selezneva
2019-07-11 15:47:30 +03:00
parent 763f1e8606
commit e40cdef257
7 changed files with 46 additions and 19 deletions
@@ -30,6 +30,7 @@ import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.idea.caches.project.getAllProjectSdks import org.jetbrains.kotlin.idea.caches.project.getAllProjectSdks
import org.jetbrains.kotlin.idea.core.script.dependencies.SyncScriptDependenciesLoader import org.jetbrains.kotlin.idea.core.script.dependencies.SyncScriptDependenciesLoader
import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
import java.io.File import java.io.File
@@ -125,7 +126,8 @@ class ScriptDependenciesManager internal constructor(
@TestOnly @TestOnly
fun updateScriptDependenciesSynchronously(virtualFile: VirtualFile, project: Project) { fun updateScriptDependenciesSynchronously(virtualFile: VirtualFile, project: Project) {
val loader = SyncScriptDependenciesLoader(project) val loader = SyncScriptDependenciesLoader(project)
loader.loadDependencies(virtualFile) val scriptDefinition = virtualFile.findScriptDefinition(project) ?: return
loader.loadDependencies(virtualFile, scriptDefinition)
loader.notifyRootsChanged() loader.notifyRootsChanged()
} }
} }
@@ -101,7 +101,8 @@ class ScriptsCompilationConfigurationUpdater(
if (!ScriptDefinitionsManager.getInstance(project).isReady()) return if (!ScriptDefinitionsManager.getInstance(project).isReady()) return
if (!cache.shouldRunDependenciesUpdate(file)) return if (!cache.shouldRunDependenciesUpdate(file)) return
loaders.filter { it.isApplicable(file) }.forEach { it.loadDependencies(file) } val scriptDefinition = file.findScriptDefinition(project) ?: return
loaders.filter { it.isApplicable(file, scriptDefinition) }.forEach { it.loadDependencies(file, scriptDefinition) }
} }
private fun makeRootsChangeIfNeeded() { private fun makeRootsChangeIfNeeded() {
@@ -14,6 +14,7 @@ import com.intellij.openapi.vfs.VirtualFile
import kotlinx.coroutines.Runnable import kotlinx.coroutines.Runnable
import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
@@ -28,12 +29,17 @@ class AsyncScriptDependenciesLoader internal constructor(project: Project) : Scr
private var notifyRootChange: Boolean = false private var notifyRootChange: Boolean = false
private var backgroundTasksQueue: LoaderBackgroundTask? = null private var backgroundTasksQueue: LoaderBackgroundTask? = null
override fun isApplicable(file: VirtualFile): Boolean { override fun isApplicable(
val scriptDefinition = file.findScriptDefinition(project) ?: return false file: VirtualFile,
scriptDefinition: ScriptDefinition
): Boolean {
return ScriptsCompilationConfigurationUpdater.getInstance(project).isAsyncDependencyResolver(scriptDefinition) return ScriptsCompilationConfigurationUpdater.getInstance(project).isAsyncDependencyResolver(scriptDefinition)
} }
override fun loadDependencies(file: VirtualFile) { override fun loadDependencies(
file: VirtualFile,
scriptDefinition: ScriptDefinition
) {
lock.write { lock.write {
if (backgroundTasksQueue == null) { if (backgroundTasksQueue == null) {
backgroundTasksQueue = LoaderBackgroundTask() backgroundTasksQueue = LoaderBackgroundTask()
@@ -9,7 +9,7 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.core.script.scriptCompilationConfiguration import org.jetbrains.kotlin.idea.core.script.scriptCompilationConfiguration
import org.jetbrains.kotlin.idea.core.script.scriptDependencies import org.jetbrains.kotlin.idea.core.script.scriptDependencies
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import kotlin.script.experimental.api.asSuccess import kotlin.script.experimental.api.asSuccess
@@ -17,17 +17,23 @@ import kotlin.script.experimental.api.asSuccess
// TODO: rename and provide alias for compatibility - this is not only about dependencies anymore // TODO: rename and provide alias for compatibility - this is not only about dependencies anymore
class FromFileAttributeScriptDependenciesLoader(project: Project) : ScriptDependenciesLoader(project) { class FromFileAttributeScriptDependenciesLoader(project: Project) : ScriptDependenciesLoader(project) {
override fun isApplicable(file: VirtualFile): Boolean { override fun isApplicable(
file: VirtualFile,
scriptDefinition: ScriptDefinition
): Boolean {
return file.scriptDependencies != null || file.scriptCompilationConfiguration != null return file.scriptDependencies != null || file.scriptCompilationConfiguration != null
} }
override fun loadDependencies(file: VirtualFile) { override fun loadDependencies(
file: VirtualFile,
scriptDefinition: ScriptDefinition
) {
file.scriptCompilationConfiguration?.let { file.scriptCompilationConfiguration?.let {
ScriptCompilationConfigurationWrapper.FromCompilationConfiguration(VirtualFileScriptSource(file), it).apply { ScriptCompilationConfigurationWrapper.FromCompilationConfiguration(VirtualFileScriptSource(file), it).apply {
debug(file) { "refined configuration from fileAttributes = $it" } debug(file) { "refined configuration from fileAttributes = $it" }
} }
} ?: file.scriptDependencies?.let { } ?: file.scriptDependencies?.let {
ScriptCompilationConfigurationWrapper.FromLegacy(VirtualFileScriptSource(file), it, file.findScriptDefinition(project)).apply { ScriptCompilationConfigurationWrapper.FromLegacy(VirtualFileScriptSource(file), it, scriptDefinition).apply {
debug(file) { "dependencies from fileAttributes = $it" } debug(file) { "dependencies from fileAttributes = $it" }
} }
}?.let { }?.let {
@@ -10,13 +10,20 @@ import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager
import org.jetbrains.kotlin.idea.highlighter.OutsidersPsiFileSupportUtils import org.jetbrains.kotlin.idea.highlighter.OutsidersPsiFileSupportUtils
import org.jetbrains.kotlin.idea.highlighter.OutsidersPsiFileSupportWrapper import org.jetbrains.kotlin.idea.highlighter.OutsidersPsiFileSupportWrapper
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
class OutsiderFileDependenciesLoader(project: Project) : ScriptDependenciesLoader(project) { class OutsiderFileDependenciesLoader(project: Project) : ScriptDependenciesLoader(project) {
override fun isApplicable(file: VirtualFile): Boolean { override fun isApplicable(
file: VirtualFile,
scriptDefinition: ScriptDefinition
): Boolean {
return OutsidersPsiFileSupportWrapper.isOutsiderFile(file) return OutsidersPsiFileSupportWrapper.isOutsiderFile(file)
} }
override fun loadDependencies(file: VirtualFile) { override fun loadDependencies(
file: VirtualFile,
scriptDefinition: ScriptDefinition
) {
val fileOrigin = OutsidersPsiFileSupportUtils.getOutsiderFileOrigin(project, file) ?: return val fileOrigin = OutsidersPsiFileSupportUtils.getOutsiderFileOrigin(project, file) ?: return
val compilationConfiguration = ScriptDependenciesManager.getInstance(project).getRefinedCompilationConfiguration(fileOrigin) ?: return val compilationConfiguration = ScriptDependenciesManager.getInstance(project).getRefinedCompilationConfiguration(fileOrigin) ?: return
saveToCache(file, compilationConfiguration) saveToCache(file, compilationConfiguration)
@@ -15,6 +15,7 @@ import com.intellij.openapi.util.EmptyRunnable
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.core.script.* import org.jetbrains.kotlin.idea.core.script.*
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
@@ -24,8 +25,8 @@ import kotlin.script.experimental.api.valueOrNull
// TODO: rename and provide alias for compatibility - this is not only about dependencies anymore // TODO: rename and provide alias for compatibility - this is not only about dependencies anymore
abstract class ScriptDependenciesLoader(protected val project: Project) { abstract class ScriptDependenciesLoader(protected val project: Project) {
abstract fun isApplicable(file: VirtualFile): Boolean abstract fun isApplicable(file: VirtualFile, scriptDefinition: ScriptDefinition): Boolean
abstract fun loadDependencies(file: VirtualFile) abstract fun loadDependencies(file: VirtualFile, scriptDefinition: ScriptDefinition)
protected abstract fun shouldShowNotification(): Boolean protected abstract fun shouldShowNotification(): Boolean
@@ -8,20 +8,24 @@ package org.jetbrains.kotlin.idea.core.script.dependencies
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource
import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration
class SyncScriptDependenciesLoader(project: Project) : ScriptDependenciesLoader(project) { class SyncScriptDependenciesLoader(project: Project) : ScriptDependenciesLoader(project) {
override fun isApplicable(file: VirtualFile): Boolean { override fun isApplicable(
val scriptDefinition = file.findScriptDefinition(project) ?: return false file: VirtualFile,
scriptDefinition: ScriptDefinition
): Boolean {
return !ScriptsCompilationConfigurationUpdater.getInstance(project).isAsyncDependencyResolver(scriptDefinition) return !ScriptsCompilationConfigurationUpdater.getInstance(project).isAsyncDependencyResolver(scriptDefinition)
} }
override fun loadDependencies(file: VirtualFile) { override fun loadDependencies(
val scriptDef = file.findScriptDefinition(project) ?: return file: VirtualFile,
scriptDefinition: ScriptDefinition
) {
debug(file) { "start sync dependencies loading" } debug(file) { "start sync dependencies loading" }
val result = refineScriptCompilationConfiguration(VirtualFileScriptSource(file), scriptDef, project) val result = refineScriptCompilationConfiguration(VirtualFileScriptSource(file), scriptDefinition, project)
debug(file) { "finish sync dependencies loading" } debug(file) { "finish sync dependencies loading" }
processRefinedConfiguration(result, file) processRefinedConfiguration(result, file)
} }