From 1f52c0e0d4650dbb2d01e515710deab5cdbb69ca Mon Sep 17 00:00:00 2001 From: Sergey Rostov Date: Thu, 9 Jul 2020 21:35:38 +0300 Subject: [PATCH] gradle.kts: improve service initializtion - prevent analyzing .gradle.kts files until all services are loaded - remove services caches where it is not required - replace cached services with cache only during vfs events batch processing - prevent services loading in actions updating --- .../core/script/ScriptConfigurationManager.kt | 4 ++++ .../idea/core/script/ScriptDefinitionsManager.kt | 4 +++- .../ScriptTrafficLightRendererContributor.kt | 10 ++++++++-- .../CompositeScriptConfigurationManager.kt | 3 ++- .../listener/ScriptChangesNotifier.kt | 9 +++++---- .../gradle/AsyncFileChangeListenerHelper.kt | 3 ++- .../gradle/AsyncFileChangeListenerHelper.kt.193 | 9 ++++++--- .../idea/scripting/gradle/GradleImportHelper.kt | 7 ++++++- .../idea/scripting/gradle/GradleScriptListener.kt | 15 +++++++++++++-- .../GradleLegacyScriptConfigurationLoader.kt | 3 ++- .../gradle/legacy/GradleLegacyScriptListener.kt | 3 ++- .../gradle/roots/GradleBuildRootsManager.kt | 3 +-- .../definitions/KotlinScriptDefinitionProvider.kt | 3 +++ 13 files changed, 57 insertions(+), 19 deletions(-) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptConfigurationManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptConfigurationManager.kt index bb8056062af..367b1a374bc 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptConfigurationManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptConfigurationManager.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.idea.core.script import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.components.serviceIfCreated import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.util.Key @@ -108,6 +109,9 @@ interface ScriptConfigurationManager { fun getAllScriptDependenciesSources(): List companion object { + fun getServiceIfCreated(project: Project): ScriptConfigurationManager? = + ServiceManager.getServiceIfCreated(project, ScriptConfigurationManager::class.java) + @JvmStatic fun getInstance(project: Project): ScriptConfigurationManager = ServiceManager.getService(project, ScriptConfigurationManager::class.java) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt index 794952d9e04..c52fe307eb8 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt @@ -84,7 +84,9 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit private val scriptDefinitionsCacheLock = ReentrantLock() private val scriptDefinitionsCache = SLRUMap(10, 10) - val configurations = (ScriptConfigurationManager.getInstance(project) as CompositeScriptConfigurationManager) + // cache service as it's getter is on the hot path + // it is safe, since both services are in same plugin + val configurations = ScriptConfigurationManager.getInstance(project) as CompositeScriptConfigurationManager override fun findDefinition(script: SourceCode): ScriptDefinition? { val locationId = script.locationId ?: return null diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTrafficLightRendererContributor.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTrafficLightRendererContributor.kt index e371f63631d..92015b3cffd 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTrafficLightRendererContributor.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTrafficLightRendererContributor.kt @@ -27,10 +27,16 @@ class ScriptTrafficLightRendererContributor : TrafficLightRendererContributor { TrafficLightRenderer(project, document, file) { override fun getDaemonCodeAnalyzerStatus(severityRegistrar: SeverityRegistrar): DaemonCodeAnalyzerStatus { val status = super.getDaemonCodeAnalyzerStatus(severityRegistrar) - if (!ScriptDefinitionsManager.getInstance(file.project).isReady()) { + + val configurations = ScriptConfigurationManager.getServiceIfCreated(project) + if (configurations == null) { + // services not yet initialized (it should be initialized under the LoadScriptDefinitionsStartupActivity) + status.reasonWhySuspended = KotlinIdeaCoreBundle.message("text.loading.kotlin.script.configuration") + status.errorAnalyzingFinished = false + } else if (!ScriptDefinitionsManager.getInstance(file.project).isReady()) { status.reasonWhySuspended = KotlinIdeaCoreBundle.message("text.loading.kotlin.script.definitions") status.errorAnalyzingFinished = false - } else if (ScriptConfigurationManager.getInstance(project).isConfigurationLoadingInProgress(file)) { + } else if (configurations.isConfigurationLoadingInProgress(file)) { status.reasonWhySuspended = KotlinIdeaCoreBundle.message("text.loading.kotlin.script.configuration") status.errorAnalyzingFinished = false } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/CompositeScriptConfigurationManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/CompositeScriptConfigurationManager.kt index de8f60392b4..ed2fef5d2da 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/CompositeScriptConfigurationManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/CompositeScriptConfigurationManager.kt @@ -49,7 +49,8 @@ class CompositeScriptConfigurationManager(val project: Project) : ScriptConfigur private val classpathRoots: ScriptClassRootsCache get() = updater.classpathRoots - private val plugins = ScriptingSupport.EPN.getPoint(project).extensionList + private val plugins + get() = ScriptingSupport.EPN.getPoint(project).extensionList val default = DefaultScriptingSupport(this) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/listener/ScriptChangesNotifier.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/listener/ScriptChangesNotifier.kt index 14275e55917..a956425bbee 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/listener/ScriptChangesNotifier.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/configuration/listener/ScriptChangesNotifier.kt @@ -83,10 +83,11 @@ internal class ScriptChangesNotifier( } private val defaultListener = DefaultScriptChangeListener(project) - private val listeners: Collection = mutableListOf().apply { - addAll(LISTENER.getPoint(project).extensionList) - add(defaultListener) - } + private val listeners: Collection + get() = mutableListOf().apply { + addAll(LISTENER.getPoint(project).extensionList) + add(defaultListener) + } private fun getListener(project: Project, file: VirtualFile): ScriptChangeListener? { if (project.isDisposed || areListenersDisabled()) return null diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt index 77ed5aa9825..a0eddff6001 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt @@ -33,9 +33,10 @@ fun addVfsListener( } override fun apply() { + val fileChangesProcessor = watcher.fileChangesProcessor changedFiles.forEach { LocalFileSystem.getInstance().findFileByPath(it)?.let { f -> - watcher.fileChanged(f.path, f.timeStamp) + fileChangesProcessor(f.path, f.timeStamp) } } } diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt.193 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt.193 index ccc50c982c4..245705b0954 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt.193 +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt.193 @@ -17,19 +17,22 @@ fun addVfsListener( ) { VirtualFileManager.getInstance().addAsyncFileListener( object : AsyncFileChangeListenerBase() { + var fileChangesProcessor = watcher.fileChangesProcessor + override fun isRelevant(path: String): Boolean { return buildRootsManager.maybeAffectedGradleProjectFile(path) } override fun updateFile(file: VirtualFile, event: VFileEvent) { - watcher.fileChanged(event.path, file.timeStamp) + fileChangesProcessor(event.path, file.timeStamp) } // do nothing override fun prepareFileDeletion(file: VirtualFile) {} override fun apply() {} - override fun reset() {} - + override fun reset() { + fileChangesProcessor = watcher.fileChangesProcessor + } }, watcher.project ) diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt index a26d34d684d..96a50e237ff 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleImportHelper.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings import org.jetbrains.kotlin.idea.scripting.gradle.importing.KotlinDslScriptModelResolver import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRoot import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition import org.jetbrains.plugins.gradle.service.project.GradlePartialResolverPolicy import org.jetbrains.plugins.gradle.settings.GradleProjectSettings @@ -98,10 +99,14 @@ class LoadConfigurationAction : AnAction( private fun getNotificationVisibility(editor: Editor): Boolean { if (!scriptConfigurationsNeedToBeUpdatedBalloon) return false - if (DiffUtil.isDiffEditor(editor)) return false val project = editor.project ?: return false + + // prevent services initializtion + // (all services actually initialized under the ScriptDefinitionProvider during startup activity) + if (ScriptDefinitionProvider.getServiceIfCreated(project) == null) return false + val file = getKotlinScriptFile(editor) ?: return false if (autoReloadScriptConfigurations(project, file)) { diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt index 51db38863de..2d711c39692 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/GradleScriptListener.kt @@ -14,15 +14,26 @@ import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager class GradleScriptListener(project: Project) : ScriptChangeListener(project) { // todo(gradle6): remove private val legacy = GradleLegacyScriptListener(project) - private val buildRootsManager = GradleBuildRootsManager.getInstance(project) + + private val buildRootsManager + get() = GradleBuildRootsManager.getInstance(project) init { // listen changes using VFS events, including gradle-configuration related files addVfsListener(this, buildRootsManager) } + // cache buildRootsManager service for hot path under vfs changes listener + val fileChangesProcessor: (filePath: String, ts: Long) -> Unit + get() { + val buildRootsManager = buildRootsManager + return { filePath, ts -> + buildRootsManager.fileChanged(filePath, ts) + } + } + fun fileChanged(filePath: String, ts: Long) = - buildRootsManager.fileChanged(filePath, ts) + fileChangesProcessor(filePath, ts) override fun isApplicable(vFile: VirtualFile) = // todo(gradle6): replace with `isCustomScriptingSupport(vFile)` diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/legacy/GradleLegacyScriptConfigurationLoader.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/legacy/GradleLegacyScriptConfigurationLoader.kt index 8c1d9c7121c..50ea9a1e90a 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/legacy/GradleLegacyScriptConfigurationLoader.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/legacy/GradleLegacyScriptConfigurationLoader.kt @@ -27,7 +27,8 @@ import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition * TODO(gradle6): remove */ class GradleLegacyScriptConfigurationLoader(project: Project) : DefaultScriptConfigurationLoader(project) { - private val buildRootsManager = GradleBuildRootsManager.getInstance(project) + private val buildRootsManager + get() = GradleBuildRootsManager.getInstance(project) override fun interceptBackgroundLoading(file: VirtualFile, isFirstLoad: Boolean, doLoad: () -> Unit): Boolean { if (!isGradleKotlinScript(file)) return false diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/legacy/GradleLegacyScriptListener.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/legacy/GradleLegacyScriptListener.kt index 88b49b6d449..56beaf3d6ce 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/legacy/GradleLegacyScriptListener.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/legacy/GradleLegacyScriptListener.kt @@ -14,7 +14,8 @@ import org.jetbrains.kotlin.idea.scripting.gradle.roots.GradleBuildRootsManager // called from GradleScriptListener // todo(gradle6): remove class GradleLegacyScriptListener(project: Project) : ScriptChangeListener(project) { - private val buildRootsManager = GradleBuildRootsManager.getInstance(project) + private val buildRootsManager + get() = GradleBuildRootsManager.getInstance(project) override fun isApplicable(vFile: VirtualFile) = isGradleKotlinScript(vFile) diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootsManager.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootsManager.kt index c0641e363ed..efd9dd89a79 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootsManager.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/roots/GradleBuildRootsManager.kt @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager import org.jetbrains.kotlin.idea.core.script.configuration.CompositeScriptConfigurationManager import org.jetbrains.kotlin.idea.core.script.configuration.DefaultScriptingSupport import org.jetbrains.kotlin.idea.core.script.configuration.ScriptingSupport -import org.jetbrains.kotlin.idea.core.script.configuration.ScriptingSupport.Companion.EPN import org.jetbrains.kotlin.idea.core.script.ucache.ScriptClassRootsBuilder import org.jetbrains.kotlin.idea.core.util.EDT import org.jetbrains.kotlin.idea.scripting.gradle.* @@ -456,6 +455,6 @@ class GradleBuildRootsManager(val project: Project) : GradleBuildRootsLocator(), companion object { fun getInstance(project: Project): GradleBuildRootsManager = - EPN.getPoint(project).extensionList.firstIsInstance() + ScriptingSupport.EPN.findExtensionOrFail(GradleBuildRootsManager::class.java, project) } } \ No newline at end of file diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinitionProvider.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinitionProvider.kt index 901ac570f96..d050c7595d8 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinitionProvider.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinitionProvider.kt @@ -26,6 +26,9 @@ interface ScriptDefinitionProvider { companion object { fun getInstance(project: Project): ScriptDefinitionProvider? = ServiceManager.getService(project, ScriptDefinitionProvider::class.java) + + fun getServiceIfCreated(project: Project): ScriptDefinitionProvider? = + ServiceManager.getServiceIfCreated(project, ScriptDefinitionProvider::class.java) } }