From 639d1c9145e3d48f7d8f9e5eeb456cd42ab982dd Mon Sep 17 00:00:00 2001 From: Nicolas QUINQUENEL Date: Tue, 17 Sep 2024 16:28:06 +0200 Subject: [PATCH] SLI-1589 Investigate and improve UI thread usage --- .../intellij/common/util/SonarLintUtils.java | 1 + .../actions/ClearCurrentFileIssuesAction.java | 1 + .../intellij/actions/ExcludeFileAction.kt | 10 ++---- .../intellij/actions/SonarLintToolWindow.java | 18 +++------- .../analysis/OnTheFlyFindingsHolder.kt | 6 ++-- .../intellij/callable/ShowReportCallable.kt | 7 ++-- .../ShowUpdatedCurrentFileCallable.java | 8 ++--- .../sonarlint/intellij/core/BackendService.kt | 8 ++--- .../intellij/editor/CodeAnalyzerRestarter.kt | 2 ++ .../editor/ShowLocationsIntentionAction.java | 4 +-- .../ShowRuleDescriptionIntentionAction.java | 5 +-- .../intellij/fix/ShowFixSuggestion.kt | 35 ++++++++++--------- .../ConfigureNotificationsAction.kt | 14 ++++---- .../binding/BindProjectAction.kt | 1 - .../trigger/SonarLintCheckinHandler.java | 4 +-- .../intellij/ui/AbstractIssuesPanel.java | 6 ++-- .../intellij/ui/CurrentFilePanel.java | 4 ++- .../intellij/ui/FindingDetailsPanel.kt | 6 ++-- .../intellij/ui/WhatsInThisViewPanel.kt | 23 ++++-------- .../sonarlint/intellij/util/ProjectUtils.java | 2 ++ .../intellij/util/SonarLintAppUtils.java | 11 +++--- 21 files changed, 70 insertions(+), 106 deletions(-) diff --git a/common/src/main/java/org/sonarlint/intellij/common/util/SonarLintUtils.java b/common/src/main/java/org/sonarlint/intellij/common/util/SonarLintUtils.java index 60b30df874..861d7effee 100644 --- a/common/src/main/java/org/sonarlint/intellij/common/util/SonarLintUtils.java +++ b/common/src/main/java/org/sonarlint/intellij/common/util/SonarLintUtils.java @@ -119,6 +119,7 @@ public static VirtualFile getSelectedFile(Project project) { if (project.isDisposed()) { return null; } + ApplicationManager.getApplication().assertIsDispatchThread(); var editorManager = FileEditorManager.getInstance(project); var editor = editorManager.getSelectedTextEditor(); diff --git a/src/main/java/org/sonarlint/intellij/actions/ClearCurrentFileIssuesAction.java b/src/main/java/org/sonarlint/intellij/actions/ClearCurrentFileIssuesAction.java index 9199f1be18..39ae1c177c 100644 --- a/src/main/java/org/sonarlint/intellij/actions/ClearCurrentFileIssuesAction.java +++ b/src/main/java/org/sonarlint/intellij/actions/ClearCurrentFileIssuesAction.java @@ -64,6 +64,7 @@ public void actionPerformed(AnActionEvent e) { } public Collection findFiles(Project project, VirtualFile[] files) { + ApplicationManager.getApplication().assertReadAccessAllowed(); var psiManager = PsiManager.getInstance(project); var psiFiles = new ArrayList(files.length); diff --git a/src/main/java/org/sonarlint/intellij/actions/ExcludeFileAction.kt b/src/main/java/org/sonarlint/intellij/actions/ExcludeFileAction.kt index e17546fd85..dd5439eb75 100644 --- a/src/main/java/org/sonarlint/intellij/actions/ExcludeFileAction.kt +++ b/src/main/java/org/sonarlint/intellij/actions/ExcludeFileAction.kt @@ -27,12 +27,11 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import org.sonarlint.intellij.analysis.AnalysisStatus import org.sonarlint.intellij.analysis.AnalysisSubmitter -import org.sonarlint.intellij.common.util.SonarLintUtils +import org.sonarlint.intellij.common.util.SonarLintUtils.getService import org.sonarlint.intellij.config.Settings import org.sonarlint.intellij.config.project.ExclusionItem import org.sonarlint.intellij.messages.ProjectConfigurationListener import org.sonarlint.intellij.trigger.TriggerType -import org.sonarlint.intellij.ui.UiUtils.Companion.runOnUiThread import org.sonarlint.intellij.util.SonarLintAppUtils import org.sonarlint.intellij.util.runOnPooledThread @@ -64,11 +63,8 @@ class ExcludeFileAction : AbstractSonarAction { if (newExclusions.isNotEmpty()) { exclusions.addAll(newExclusions) settings.fileExclusions = exclusions - SonarLintUtils.getService(project, AnalysisSubmitter::class.java).autoAnalyzeOpenFiles(TriggerType.CONFIG_CHANGE) - runOnUiThread(project) { - val projectListener = project.messageBus.syncPublisher(ProjectConfigurationListener.TOPIC) - projectListener.changed(settings) - } + getService(project, AnalysisSubmitter::class.java).autoAnalyzeOpenFiles(TriggerType.CONFIG_CHANGE) + project.messageBus.syncPublisher(ProjectConfigurationListener.TOPIC).changed(settings) } } } diff --git a/src/main/java/org/sonarlint/intellij/actions/SonarLintToolWindow.java b/src/main/java/org/sonarlint/intellij/actions/SonarLintToolWindow.java index b4584e1144..b51275956a 100644 --- a/src/main/java/org/sonarlint/intellij/actions/SonarLintToolWindow.java +++ b/src/main/java/org/sonarlint/intellij/actions/SonarLintToolWindow.java @@ -20,6 +20,7 @@ package org.sonarlint.intellij.actions; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.Service; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; @@ -78,11 +79,9 @@ public SonarLintToolWindow(Project project) { project.getMessageBus().connect().subscribe(ProjectBindingListenerKt.getPROJECT_BINDING_TOPIC(), this); } - /** - * Must run in EDT - */ public void openReportTab(AnalysisResult analysisResult) { - this.openTab(SonarLintToolWindowFactory.REPORT_TAB_TITLE, panel -> panel.updateFindings(analysisResult)); + runOnUiThread(project, ModalityState.stateForComponent(getToolWindow().getComponent()), + () -> this.openTab(SonarLintToolWindowFactory.REPORT_TAB_TITLE, panel -> panel.updateFindings(analysisResult))); } public void clearReportTab() { @@ -131,7 +130,6 @@ private void openTab(String displayName, Consumer tabPanelConsumer) { } private ToolWindow updateTab(String displayName, Consumer tabPanelConsumer) { - ApplicationManager.getApplication().assertIsDispatchThread(); var toolWindow = getToolWindow(); if (toolWindow != null) { var contentManager = toolWindow.getContentManager(); @@ -156,16 +154,10 @@ public void filterTaintVulnerabilityTab(boolean isResolved) { } } - /** - * Must run in EDT - */ public void openCurrentFileTab() { - openTab(SonarLintToolWindowFactory.CURRENT_FILE_TAB_TITLE); + runOnUiThread(project, ModalityState.stateForComponent(getToolWindow().getComponent()), () -> openTab(SonarLintToolWindowFactory.CURRENT_FILE_TAB_TITLE)); } - /** - * Must run in EDT - */ public void openTaintVulnerabilityTab() { ApplicationManager.getApplication().assertIsDispatchThread(); var toolWindow = getToolWindow(); @@ -469,6 +461,6 @@ private Content getTaintVulnerabilitiesContent() { @Override public void bindingChanged() { - runOnUiThread(project, this::refreshViews); + refreshViews(); } } diff --git a/src/main/java/org/sonarlint/intellij/analysis/OnTheFlyFindingsHolder.kt b/src/main/java/org/sonarlint/intellij/analysis/OnTheFlyFindingsHolder.kt index 945d2527d4..6c5b943a5a 100644 --- a/src/main/java/org/sonarlint/intellij/analysis/OnTheFlyFindingsHolder.kt +++ b/src/main/java/org/sonarlint/intellij/analysis/OnTheFlyFindingsHolder.kt @@ -72,8 +72,8 @@ class OnTheFlyFindingsHolder(private val project: Project) : FileEditorManagerLi runOnUiThread(project) { updateCurrentFileTab() updateSecurityHotspots() - getService(project, CodeAnalyzerRestarter::class.java).refreshFiles(findings.onlyFor(openedFiles).filesInvolved) } + getService(project, CodeAnalyzerRestarter::class.java).refreshFiles(findings.onlyFor(openedFiles).filesInvolved) } fun updateViewsWithNewIssues(module: Module, raisedIssues: Map>) { @@ -90,8 +90,8 @@ class OnTheFlyFindingsHolder(private val project: Project) : FileEditorManagerLi selectedFile = SonarLintUtils.getSelectedFile(project) } updateCurrentFileTab() - getService(project, CodeAnalyzerRestarter::class.java).refreshFiles(issues.keys) } + getService(project, CodeAnalyzerRestarter::class.java).refreshFiles(issues.keys) } fun updateViewsWithNewSecurityHotspots(module: Module, raisedSecurityHotspots: Map>) { @@ -108,8 +108,8 @@ class OnTheFlyFindingsHolder(private val project: Project) : FileEditorManagerLi selectedFile = SonarLintUtils.getSelectedFile(project) } updateSecurityHotspots() - getService(project, CodeAnalyzerRestarter::class.java).refreshFiles(securityHotspots.keys) } + getService(project, CodeAnalyzerRestarter::class.java).refreshFiles(securityHotspots.keys) } override fun selectionChanged(event: FileEditorManagerEvent) { diff --git a/src/main/java/org/sonarlint/intellij/callable/ShowReportCallable.kt b/src/main/java/org/sonarlint/intellij/callable/ShowReportCallable.kt index 19c18f06c9..ccdc24f386 100644 --- a/src/main/java/org/sonarlint/intellij/callable/ShowReportCallable.kt +++ b/src/main/java/org/sonarlint/intellij/callable/ShowReportCallable.kt @@ -25,7 +25,6 @@ import org.sonarlint.intellij.analysis.AnalysisCallback import org.sonarlint.intellij.analysis.AnalysisResult import org.sonarlint.intellij.common.util.SonarLintUtils import org.sonarlint.intellij.editor.CodeAnalyzerRestarter -import org.sonarlint.intellij.ui.UiUtils.Companion.runOnUiThread class ShowReportCallable(private val project: Project) : AnalysisCallback { @@ -45,10 +44,8 @@ class ShowReportCallable(private val project: Project) : AnalysisCallback { private fun showReportTab() { results?.let { - runOnUiThread(project) { - SonarLintUtils.getService(project, SonarLintToolWindow::class.java).openReportTab(it) - SonarLintUtils.getService(project, CodeAnalyzerRestarter::class.java).refreshOpenFiles() - } + SonarLintUtils.getService(project, SonarLintToolWindow::class.java).openReportTab(it) + SonarLintUtils.getService(project, CodeAnalyzerRestarter::class.java).refreshOpenFiles() } } diff --git a/src/main/java/org/sonarlint/intellij/callable/ShowUpdatedCurrentFileCallable.java b/src/main/java/org/sonarlint/intellij/callable/ShowUpdatedCurrentFileCallable.java index 502d43f549..84d37f5029 100644 --- a/src/main/java/org/sonarlint/intellij/callable/ShowUpdatedCurrentFileCallable.java +++ b/src/main/java/org/sonarlint/intellij/callable/ShowUpdatedCurrentFileCallable.java @@ -27,8 +27,6 @@ import org.sonarlint.intellij.analysis.OnTheFlyFindingsHolder; import org.sonarlint.intellij.common.util.SonarLintUtils; -import static org.sonarlint.intellij.ui.UiUtils.runOnUiThread; - public class ShowUpdatedCurrentFileCallable implements AnalysisCallback { private final Project project; private final UpdateOnTheFlyFindingsCallable updateOnTheFlyFindingsCallable; @@ -54,9 +52,7 @@ public void onSuccess(AnalysisResult analysisResult) { } private void showCurrentFileTab() { - runOnUiThread(project, () -> { - var toolWindow = SonarLintUtils.getService(project, SonarLintToolWindow.class); - toolWindow.openCurrentFileTab(); - }); + var toolWindow = SonarLintUtils.getService(project, SonarLintToolWindow.class); + toolWindow.openCurrentFileTab(); } } diff --git a/src/main/java/org/sonarlint/intellij/core/BackendService.kt b/src/main/java/org/sonarlint/intellij/core/BackendService.kt index ec6f8ce4f1..42023990e2 100644 --- a/src/main/java/org/sonarlint/intellij/core/BackendService.kt +++ b/src/main/java/org/sonarlint/intellij/core/BackendService.kt @@ -280,9 +280,7 @@ class BackendService : Disposable { private fun handleSloopExited() { ProjectManager.getInstance().openProjects.forEach { project -> - runOnUiThread(project) { - getService(project, SonarLintToolWindow::class.java).refreshViews() - } + getService(project, SonarLintToolWindow::class.java).refreshViews() } projectLessNotification( null, @@ -784,9 +782,7 @@ class BackendService : Disposable { private fun catchUpWithBackend(rpcServer: SonarLintRpcServer) { ProjectManager.getInstance().openProjects.forEach { project -> - runOnUiThread(project) { - getService(project, SonarLintToolWindow::class.java).refreshViews() - } + getService(project, SonarLintToolWindow::class.java).refreshViews() val binding = getService(project, ProjectBindingManager::class.java).binding rpcServer.configurationService.didAddConfigurationScopes( diff --git a/src/main/java/org/sonarlint/intellij/editor/CodeAnalyzerRestarter.kt b/src/main/java/org/sonarlint/intellij/editor/CodeAnalyzerRestarter.kt index 5d0eba14aa..8c7330291c 100644 --- a/src/main/java/org/sonarlint/intellij/editor/CodeAnalyzerRestarter.kt +++ b/src/main/java/org/sonarlint/intellij/editor/CodeAnalyzerRestarter.kt @@ -20,6 +20,7 @@ package org.sonarlint.intellij.editor import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.Service import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project @@ -55,6 +56,7 @@ class CodeAnalyzerRestarter @NonInjectable internal constructor(private val myPr if (!virtualFile.isValid) { return null } + ApplicationManager.getApplication().assertReadAccessAllowed() return PsiManager.getInstance(myProject).findFile(virtualFile) } } diff --git a/src/main/java/org/sonarlint/intellij/editor/ShowLocationsIntentionAction.java b/src/main/java/org/sonarlint/intellij/editor/ShowLocationsIntentionAction.java index e655e75385..6db2dfa5ac 100644 --- a/src/main/java/org/sonarlint/intellij/editor/ShowLocationsIntentionAction.java +++ b/src/main/java/org/sonarlint/intellij/editor/ShowLocationsIntentionAction.java @@ -34,8 +34,6 @@ import org.sonarlint.intellij.finding.FindingContext; import org.sonarlint.intellij.finding.LiveFinding; -import static org.sonarlint.intellij.ui.UiUtils.runOnUiThread; - public class ShowLocationsIntentionAction implements IntentionAction, PriorityAction, Iconable { private final LiveFinding finding; private final FindingContext context; @@ -60,7 +58,7 @@ public ShowLocationsIntentionAction(LiveFinding finding, FindingContext context) @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file) { SonarLintUtils.getService(project, EditorDecorator.class).highlightFinding(finding); var sonarLintToolWindow = SonarLintUtils.getService(project, SonarLintToolWindow.class); - runOnUiThread(project, () -> sonarLintToolWindow.showFindingLocations(finding)); + sonarLintToolWindow.showFindingLocations(finding); } @Override public boolean startInWriteAction() { diff --git a/src/main/java/org/sonarlint/intellij/editor/ShowRuleDescriptionIntentionAction.java b/src/main/java/org/sonarlint/intellij/editor/ShowRuleDescriptionIntentionAction.java index 1cc0be9dd1..e57b12213f 100644 --- a/src/main/java/org/sonarlint/intellij/editor/ShowRuleDescriptionIntentionAction.java +++ b/src/main/java/org/sonarlint/intellij/editor/ShowRuleDescriptionIntentionAction.java @@ -33,8 +33,6 @@ import org.sonarlint.intellij.common.util.SonarLintUtils; import org.sonarlint.intellij.finding.LiveFinding; -import static org.sonarlint.intellij.ui.UiUtils.runOnUiThread; - public class ShowRuleDescriptionIntentionAction implements IntentionAction, PriorityAction, Iconable { private final LiveFinding liveFinding; @@ -59,8 +57,7 @@ public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file) { - runOnUiThread(project, () -> SonarLintUtils.getService(project, SonarLintToolWindow.class) - .showFindingDescription(liveFinding)); + SonarLintUtils.getService(project, SonarLintToolWindow.class).showFindingDescription(liveFinding); } @Override diff --git a/src/main/java/org/sonarlint/intellij/fix/ShowFixSuggestion.kt b/src/main/java/org/sonarlint/intellij/fix/ShowFixSuggestion.kt index 2dfe16ddc0..81a4863031 100644 --- a/src/main/java/org/sonarlint/intellij/fix/ShowFixSuggestion.kt +++ b/src/main/java/org/sonarlint/intellij/fix/ShowFixSuggestion.kt @@ -28,7 +28,6 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.util.TextRange import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiManager -import org.sonarlint.intellij.common.ui.ReadActionUtils.Companion.computeReadActionSafely import org.sonarlint.intellij.common.ui.SonarLintConsole import org.sonarlint.intellij.notifications.SonarLintProjectNotifications.Companion.get import org.sonarlint.intellij.ui.UiUtils.Companion.runOnUiThread @@ -37,25 +36,25 @@ import org.sonarlint.intellij.ui.inlay.InlayManager import org.sonarlint.intellij.util.getDocument import org.sonarsource.sonarlint.core.rpc.protocol.client.fix.FixSuggestionDto -class ShowFixSuggestion(private val project: Project, private val file: VirtualFile, private val fixSuggestion: FixSuggestionDto) { +class ShowFixSuggestion( + private val project: Project, private val file: VirtualFile, private val fixSuggestion: FixSuggestionDto +) { fun show() { - val fileEditorManager = FileEditorManager.getInstance(project) - val psiFile = PsiManager.getInstance(project).findFile(file) ?: return - val document = computeReadActionSafely(project) { file.getDocument() } ?: return - - if (!isWithinBounds(document)) { - get(project).simpleNotification( - null, - "Unable to open the fix suggestion, your file has probably changed", - NotificationType.WARNING - ) - return - } + runOnUiThread(project, ModalityState.defaultModalityState()) { + val fileEditorManager = FileEditorManager.getInstance(project) + val psiFile = PsiManager.getInstance(project).findFile(file) ?: return@runOnUiThread + val document = file.getDocument() ?: return@runOnUiThread + + if (!isWithinBounds(document)) { + get(project).simpleNotification( + null, "Unable to open the fix suggestion, your file has probably changed", NotificationType.WARNING + ) + return@runOnUiThread + } - var successfullyOpened = true + var successfullyOpened = true - runOnUiThread(project, ModalityState.defaultModalityState()) { fixSuggestion.fileEdit().changes().forEachIndexed { index, change -> val startLine = change.beforeLineRange().startLine val endLine = change.beforeLineRange().endLine @@ -74,7 +73,9 @@ class ShowFixSuggestion(private val project: Project, private val file: VirtualF fileEditorManager.selectedTextEditor?.let { val doc = it.document try { - val rangeMarker = doc.createRangeMarker(doc.getLineStartOffset(startLine - 1), doc.getLineEndOffset(endLine - 1)) + val rangeMarker = doc.createRangeMarker( + doc.getLineStartOffset(startLine - 1), doc.getLineEndOffset(endLine - 1) + ) val currentCode = doc.getText(TextRange(rangeMarker.startOffset, rangeMarker.endOffset)) val fixSuggestionSnippet = FixSuggestionSnippet( currentCode, diff --git a/src/main/java/org/sonarlint/intellij/notifications/ConfigureNotificationsAction.kt b/src/main/java/org/sonarlint/intellij/notifications/ConfigureNotificationsAction.kt index 4f15c59c69..2b5b3321cc 100644 --- a/src/main/java/org/sonarlint/intellij/notifications/ConfigureNotificationsAction.kt +++ b/src/main/java/org/sonarlint/intellij/notifications/ConfigureNotificationsAction.kt @@ -33,20 +33,20 @@ class ConfigureNotificationsAction(private val connectionName: String, private v override fun actionPerformed(e: AnActionEvent, notification: Notification) { WindowManager.getInstance().getFrame(e.project) ?: return - runOnUiThread(project) { - val connectionToEdit = Settings.getGlobalSettings().serverConnections.find { it.name == connectionName } - if (connectionToEdit != null) { - val wizard = ServerConnectionWizard.forNotificationsEdition(connectionToEdit) + val connectionToEdit = Settings.getGlobalSettings().serverConnections.find { it.name == connectionName } + if (connectionToEdit != null) { + val wizard = ServerConnectionWizard.forNotificationsEdition(connectionToEdit) + runOnUiThread(project) { if (wizard.showAndGet()) { val editedConnection = wizard.connection val serverConnections = Settings.getGlobalSettings().serverConnections.toMutableList() serverConnections[serverConnections.indexOf(connectionToEdit)] = editedConnection Settings.getGlobalSettings().serverConnections = serverConnections } - } else if (e.project != null) { - SonarLintConsole.get(e.project!!).error("Unable to find connection with name: $connectionName") - notification.expire() } + } else if (e.project != null) { + SonarLintConsole.get(e.project!!).error("Unable to find connection with name: $connectionName") + notification.expire() } } diff --git a/src/main/java/org/sonarlint/intellij/notifications/binding/BindProjectAction.kt b/src/main/java/org/sonarlint/intellij/notifications/binding/BindProjectAction.kt index e231f34418..09a9d6fa9e 100644 --- a/src/main/java/org/sonarlint/intellij/notifications/binding/BindProjectAction.kt +++ b/src/main/java/org/sonarlint/intellij/notifications/binding/BindProjectAction.kt @@ -50,6 +50,5 @@ class BindProjectAction(private val bindingSuggestion: BindingSuggestion, privat SonarLintConsole.get(project) .debug("Cannot bind project as suggested, connection $connectionId has been removed") }) - } } diff --git a/src/main/java/org/sonarlint/intellij/trigger/SonarLintCheckinHandler.java b/src/main/java/org/sonarlint/intellij/trigger/SonarLintCheckinHandler.java index 4d3ee22446..eb5d73f6bd 100644 --- a/src/main/java/org/sonarlint/intellij/trigger/SonarLintCheckinHandler.java +++ b/src/main/java/org/sonarlint/intellij/trigger/SonarLintCheckinHandler.java @@ -95,7 +95,7 @@ public ReturnResult beforeCheckin(@Nullable CommitExecutor executor, PairConsume var affectedFiles = new HashSet<>(checkinPanel.getVirtualFiles()); // this will block EDT (modal) try { - var analysisIdsByCallback = SonarLintUtils.getService(project, AnalysisSubmitter.class).analyzeFilesPreCommit(affectedFiles); + var analysisIdsByCallback = getService(project, AnalysisSubmitter.class).analyzeFilesPreCommit(affectedFiles); if (analysisIdsByCallback == null) { return ReturnResult.CANCEL; } @@ -240,7 +240,7 @@ private ReturnResult showYesNoCancel(String resultStr) { } private void showChangedFilesTab(AnalysisResult analysisResult) { - SonarLintUtils.getService(project, SonarLintToolWindow.class).openReportTab(analysisResult); + getService(project, SonarLintToolWindow.class).openReportTab(analysisResult); } private class MyRefreshableOnComponent implements RefreshableOnComponent, UnnamedConfigurable { diff --git a/src/main/java/org/sonarlint/intellij/ui/AbstractIssuesPanel.java b/src/main/java/org/sonarlint/intellij/ui/AbstractIssuesPanel.java index 964d2cc86d..6409f8021a 100644 --- a/src/main/java/org/sonarlint/intellij/ui/AbstractIssuesPanel.java +++ b/src/main/java/org/sonarlint/intellij/ui/AbstractIssuesPanel.java @@ -52,7 +52,6 @@ import org.sonarlint.intellij.ui.tree.IssueTreeModelBuilder; import static org.sonarlint.intellij.common.ui.ReadActionUtils.computeReadActionSafely; -import static org.sonarlint.intellij.ui.UiUtils.runOnUiThread; import static org.sonarlint.intellij.util.ThreadUtilsKt.runOnPooledThread; public abstract class AbstractIssuesPanel extends SimpleToolWindowPanel implements Disposable { @@ -242,9 +241,8 @@ public void updateOnSelect(@Nullable LiveFinding issue, Show return; } - runOnUiThread(project, () -> - findingDetailsPanel.showServerOnlyIssue(showFinding.getModule(), showFinding.getFile(), showFinding.getRuleKey(), rangeMarker, showFinding.getFlows(), - showFinding.getFlowMessage())); + findingDetailsPanel.showServerOnlyIssue(showFinding.getModule(), showFinding.getFile(), showFinding.getRuleKey(), rangeMarker, showFinding.getFlows(), + showFinding.getFlowMessage()); }); } } diff --git a/src/main/java/org/sonarlint/intellij/ui/CurrentFilePanel.java b/src/main/java/org/sonarlint/intellij/ui/CurrentFilePanel.java index 60589cb2a6..758af02671 100644 --- a/src/main/java/org/sonarlint/intellij/ui/CurrentFilePanel.java +++ b/src/main/java/org/sonarlint/intellij/ui/CurrentFilePanel.java @@ -23,6 +23,7 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.ex.ActionUtil; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.VerticalFlowLayout; import com.intellij.openapi.vfs.VirtualFile; @@ -199,11 +200,12 @@ public void trySelectFilteredIssue(@Nullable LiveIssue issue private void updateIcon(@Nullable VirtualFile file, Collection issues) { var toolWindow = ToolWindowManager.getInstance(project).getToolWindow(SONARLINT_TOOLWINDOW_ID); if (toolWindow != null) { - doUpdateIcon(file, issues, toolWindow); + runOnUiThread(project, () -> doUpdateIcon(file, issues, toolWindow)); } } private static void doUpdateIcon(@Nullable VirtualFile file, Collection issues, ToolWindow toolWindow) { + ApplicationManager.getApplication().assertIsDispatchThread(); boolean empty = file == null || issues.isEmpty(); toolWindow.setIcon(empty ? SonarLintIcons.SONARLINT_TOOLWINDOW_EMPTY : SonarLintIcons.SONARLINT_TOOLWINDOW); } diff --git a/src/main/java/org/sonarlint/intellij/ui/FindingDetailsPanel.kt b/src/main/java/org/sonarlint/intellij/ui/FindingDetailsPanel.kt index a055e7a6d1..90bad0d634 100644 --- a/src/main/java/org/sonarlint/intellij/ui/FindingDetailsPanel.kt +++ b/src/main/java/org/sonarlint/intellij/ui/FindingDetailsPanel.kt @@ -26,7 +26,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import com.intellij.ui.ScrollPaneFactory import com.intellij.ui.components.JBTabbedPane -import org.sonarlint.intellij.common.util.SonarLintUtils +import org.sonarlint.intellij.common.util.SonarLintUtils.getService import org.sonarlint.intellij.editor.EditorDecorator import org.sonarlint.intellij.finding.Flow import org.sonarlint.intellij.finding.LiveFinding @@ -75,7 +75,7 @@ class FindingDetailsPanel(private val project: Project, parentDisposable: Dispos fun show(liveFinding: LiveFinding) { rulePanel.setSelectedFinding(liveFinding.module, liveFinding, liveFinding.getRuleKey(), liveFinding.getRuleDescriptionContextKey()) flowsTreeBuilder.populateForFinding(liveFinding) - SonarLintUtils.getService(project, EditorDecorator::class.java).highlightFinding(liveFinding) + getService(project, EditorDecorator::class.java).highlightFinding(liveFinding) flowsTree.emptyText.setText("Selected $findingKindText doesn't have flows") flowsTree.expandAll() } @@ -83,7 +83,7 @@ class FindingDetailsPanel(private val project: Project, parentDisposable: Dispos fun showServerOnlyIssue(module: Module, file: VirtualFile, ruleKey: String, range: RangeMarker, flows: MutableList, flowMessage: String) { rulePanel.setSelectedFinding(module, null, ruleKey, null) flowsTreeBuilder.populateForFinding(file, range, flowMessage, flows) - SonarLintUtils.getService(project, EditorDecorator::class.java).highlightRange(range) + getService(project, EditorDecorator::class.java).highlightRange(range) flowsTree.emptyText.setText("Selected $findingKindText doesn't have flows") flowsTree.expandAll() } diff --git a/src/main/java/org/sonarlint/intellij/ui/WhatsInThisViewPanel.kt b/src/main/java/org/sonarlint/intellij/ui/WhatsInThisViewPanel.kt index d233965d74..1108fc8e37 100644 --- a/src/main/java/org/sonarlint/intellij/ui/WhatsInThisViewPanel.kt +++ b/src/main/java/org/sonarlint/intellij/ui/WhatsInThisViewPanel.kt @@ -19,7 +19,6 @@ */ package org.sonarlint.intellij.ui -import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.Project import com.intellij.util.ui.JBUI import java.awt.CardLayout @@ -33,7 +32,6 @@ import org.sonarlint.intellij.ui.CurrentFileStatusPanel.subscribeToEventsThatAff import org.sonarlint.intellij.ui.UiUtils.Companion.runOnUiThread import org.sonarlint.intellij.util.HelpLabelUtils.Companion.createHelpText import org.sonarlint.intellij.util.HelpLabelUtils.Companion.createHelpTextNotConnected -import org.sonarlint.intellij.util.runOnPooledThread class WhatsInThisViewPanel(val project: Project, private var helpText: String) { var panel: JPanel @@ -43,7 +41,7 @@ class WhatsInThisViewPanel(val project: Project, private var helpText: String) { panel = JPanel(layout) createPanel() switchCards() - runOnUiThread(project) { subscribeToEventsThatAffectCurrentFile(project) { this.switchCards() } } + subscribeToEventsThatAffectCurrentFile(project) { this.switchCards() } } private fun createPanel() { @@ -71,20 +69,11 @@ class WhatsInThisViewPanel(val project: Project, private var helpText: String) { } private fun switchCards() { - ApplicationManager.getApplication().assertIsDispatchThread() - - // Checking connected mode state may take time, so lets move from EDT to pooled thread - runOnPooledThread(project) { - val projectBindingManager = - SonarLintUtils.getService(project, ProjectBindingManager::class.java) - projectBindingManager.tryGetServerConnection().ifPresentOrElse( - { - switchCard(CONNECTED) - } - ) // No connection settings for project - { switchCard(NOT_CONNECTED) } - } - + val projectBindingManager = SonarLintUtils.getService(project, ProjectBindingManager::class.java) + projectBindingManager.tryGetServerConnection().ifPresentOrElse({ + switchCard(CONNECTED) + }) // No connection settings for project + { switchCard(NOT_CONNECTED) } } private fun switchCard(cardName: String) { diff --git a/src/main/java/org/sonarlint/intellij/util/ProjectUtils.java b/src/main/java/org/sonarlint/intellij/util/ProjectUtils.java index 4256c9c1a0..265a0beaad 100644 --- a/src/main/java/org/sonarlint/intellij/util/ProjectUtils.java +++ b/src/main/java/org/sonarlint/intellij/util/ProjectUtils.java @@ -19,6 +19,7 @@ */ package org.sonarlint.intellij.util; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectCoreUtil; import com.intellij.openapi.project.ProjectUtil; @@ -77,6 +78,7 @@ private static void iterateFilesToAnalyze(Project project, Predicate retainOpenFiles(Project project, List files) { - var openFiles = computeReadActionSafely(project, () -> { - if (!project.isOpen()) { - return Collections.emptyList(); - } - return files.stream().filter(f -> FileEditorManager.getInstance(project).isFileOpen(f)).toList(); - }); - return openFiles != null ? openFiles : Collections.emptyList(); + if (project.isDisposed() || !project.isOpen()) { + return Collections.emptyList(); + } + return files.stream().filter(f -> FileEditorManager.getInstance(project).isFileOpen(f)).toList(); } /**