Skip to content

Commit

Permalink
SLI-1603 Ensure UI thread does not call backend (#1169)
Browse files Browse the repository at this point in the history
Co-authored-by: Nicolas Quinquenel <[email protected]>
  • Loading branch information
eray-felek-sonarsource and nquinquenel authored Sep 23, 2024
1 parent 338028c commit c8da2f5
Show file tree
Hide file tree
Showing 68 changed files with 478 additions and 354 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
17 changes: 5 additions & 12 deletions src/main/java/org/sonarlint/intellij/SonarLintIntelliJClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -594,19 +594,12 @@ object SonarLintIntelliJClient : SonarLintRpcClientDelegate {
if (project == null || project.isDisposed) return@forEach
getService(project, AnalysisReadinessCache::class.java).isReady = areReadyForAnalysis
if (areReadyForAnalysis) {
val findingToShow = getService(project, OpenInIdeFindingCache::class.java).finding
if (findingToShow != null && !getService(project, OpenInIdeFindingCache::class.java).analysisQueued) {
getService(project, AnalysisSubmitter::class.java).analyzeFileAndTrySelectFinding(findingToShow)
}

if (ApplicationManager.getApplication().isUnitTestMode) {
runOnPooledThread(project) {
getService(project, AnalysisSubmitter::class.java).autoAnalyzeOpenFilesForModule(
TriggerType.BINDING_UPDATE,
module
)
runOnPooledThread(project) {
val findingToShow = getService(project, OpenInIdeFindingCache::class.java).finding
if (findingToShow != null && !getService(project, OpenInIdeFindingCache::class.java).analysisQueued) {
getService(project, AnalysisSubmitter::class.java).analyzeFileAndTrySelectFinding(findingToShow)
}
} else {

getService(project, AnalysisSubmitter::class.java).autoAnalyzeOpenFilesForModule(
TriggerType.BINDING_UPDATE,
module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.sonarlint.intellij.trigger.EditorChangeTrigger;

import static org.sonarlint.intellij.common.util.SonarLintUtils.getService;
import static org.sonarlint.intellij.util.ThreadUtilsKt.runOnPooledThread;

public class StartServicesOnProjectOpened implements StartupActivity {

Expand All @@ -38,10 +39,12 @@ public void runActivity(@NotNull Project project) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
return;
}
getService(EditorFileChangeListener.class).startListening();
getService(project, EditorChangeTrigger.class).onProjectOpened();
getService(BackendService.class).projectOpened(project);
getService(project, SecurityHotspotsRefreshTrigger.class).subscribeToTriggeringEvents();
getService(project, PromotionProvider.class).subscribeToTriggeringEvents();
runOnPooledThread(project, () -> {
getService(EditorFileChangeListener.class).startListening();
getService(project, EditorChangeTrigger.class).onProjectOpened();
getService(BackendService.class).projectOpened(project);
getService(project, SecurityHotspotsRefreshTrigger.class).subscribeToTriggeringEvents();
getService(project, PromotionProvider.class).subscribeToTriggeringEvents();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public void actionPerformed(AnActionEvent e) {
}

public Collection<PsiFile> findFiles(Project project, VirtualFile[] files) {
ApplicationManager.getApplication().assertReadAccessAllowed();
var psiManager = PsiManager.getInstance(project);
var psiFiles = new ArrayList<PsiFile>(files.length);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
import com.intellij.openapi.project.Project;
import org.sonarlint.intellij.analysis.AnalysisStatus;
import org.sonarlint.intellij.analysis.AnalysisSubmitter;
import org.sonarlint.intellij.common.util.SonarLintUtils;
import org.sonarlint.intellij.core.BackendService;
import org.sonarlint.intellij.trigger.TriggerType;

import static org.sonarlint.intellij.common.util.SonarLintUtils.getService;
import static org.sonarlint.intellij.config.Settings.getGlobalSettings;
import static org.sonarlint.intellij.config.Settings.getSettingsFor;
import static org.sonarlint.intellij.util.DataKeys.ISSUE_DATA_KEY;
import static org.sonarlint.intellij.util.ThreadUtilsKt.runOnPooledThread;

public class DisableRuleAction extends AbstractSonarAction {

Expand Down Expand Up @@ -62,7 +62,7 @@ public void actionPerformed(AnActionEvent e) {
var issue = e.getData(ISSUE_DATA_KEY);
if (issue != null) {
disableRule(issue.getRuleKey());
SonarLintUtils.getService(project, AnalysisSubmitter.class).autoAnalyzeOpenFiles(TriggerType.BINDING_UPDATE);
runOnPooledThread(project, () -> getService(project, AnalysisSubmitter.class).autoAnalyzeOpenFiles(TriggerType.BINDING_UPDATE));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -64,11 +63,9 @@ 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)
val projectListener = project.messageBus.syncPublisher(ProjectConfigurationListener.TOPIC)
projectListener.changed(settings)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import org.sonarlint.intellij.ui.resolve.MarkAsResolvedDialog
import org.sonarlint.intellij.util.DataKeys.Companion.ISSUE_DATA_KEY
import org.sonarlint.intellij.util.DataKeys.Companion.TAINT_VULNERABILITY_DATA_KEY
import org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile
import org.sonarlint.intellij.util.computeOnPooledThread
import org.sonarlint.intellij.util.runOnPooledThread
import org.sonarsource.sonarlint.core.client.utils.IssueResolutionStatus
import org.sonarsource.sonarlint.core.rpc.protocol.backend.issue.CheckStatusChangePermittedResponse
Expand Down Expand Up @@ -86,7 +87,9 @@ class MarkAsResolvedAction(
project, "No module could be found for this file"
)
val serverKey = issue.getServerKey() ?: issue.getId().toString()
val response = checkPermission(project, connection, serverKey) ?: return
val response = computeOnPooledThread(project, "Checking permission to mark issue as resolved") {
checkPermission(project, connection, serverKey)
} ?: return

if (response.isPermitted) {
runOnUiThread(project) {
Expand All @@ -96,7 +99,9 @@ class MarkAsResolvedAction(
response,
).chooseResolution() ?: return@runOnUiThread
if (confirm(project, connection.productName, resolution.newStatus)) {
markAsResolved(project, module, issue, resolution, serverKey)
runOnPooledThread(project) {
markAsResolved(project, module, issue, resolution, serverKey)
}
}
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import org.sonarlint.intellij.core.BackendService
import org.sonarlint.intellij.core.ProjectBindingManager
import org.sonarlint.intellij.finding.hotspot.LiveSecurityHotspot
import org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile
import org.sonarlint.intellij.util.runOnPooledThread

class OpenSecurityHotspotInBrowserAction : AbstractSonarAction(
"Open In Browser",
Expand Down Expand Up @@ -57,7 +58,9 @@ class OpenSecurityHotspotInBrowserAction : AbstractSonarAction(
val key = securityHotspot?.getServerKey() ?: return
val localFile = securityHotspot.file()
val localFileModule = findModuleForFile(localFile, project) ?: return
getService(BackendService::class.java).openHotspotInBrowser(localFileModule, key)
runOnPooledThread(project) {
getService(BackendService::class.java).openHotspotInBrowser(localFileModule, key)
}
}

private fun serverConnection(project: Project): ServerConnection? = getService(project, ProjectBindingManager::class.java).tryGetServerConnection().orElse(null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@ import org.sonarlint.intellij.analysis.AnalysisStatus
import org.sonarlint.intellij.common.util.SonarLintUtils.getService
import org.sonarlint.intellij.core.BackendService
import org.sonarlint.intellij.core.ProjectBindingManager
import org.sonarlint.intellij.util.runOnPooledThread

class RefreshTaintVulnerabilitiesAction(text: String = "Refresh") : AbstractSonarAction(text, "Refresh taint vulnerabilities for open files", AllIcons.Actions.Refresh) {
override fun isEnabled(e: AnActionEvent, project: Project, status: AnalysisStatus) = getService(project, ProjectBindingManager::class.java).isBindingValid

override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
getService(BackendService::class.java).refreshTaintVulnerabilities(project)

runOnPooledThread {
getService(BackendService::class.java).refreshTaintVulnerabilities(project)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import org.sonarlint.intellij.finding.issue.vulnerabilities.LocalTaintVulnerabil
import org.sonarlint.intellij.notifications.SonarLintProjectNotifications
import org.sonarlint.intellij.util.DataKeys
import org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile
import org.sonarlint.intellij.util.runOnPooledThread

private const val SKIP_CONFIRM_REOPEN_DIALOG_PROPERTY = "SonarLint.reopenIssue.hideConfirmation"

Expand Down Expand Up @@ -73,7 +74,7 @@ class ReopenIssueAction(private var issue: LiveIssue? = null) : AbstractSonarAct
serverKey ?: return displayNotificationError(project, "The issue key could not be found")

if (confirm(project, connection.productName)) {
reopenFinding(project, module, issue, serverKey)
runOnPooledThread(project) { reopenFinding(project, module, issue, serverKey) }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import org.sonarlint.intellij.tasks.FutureAwaitingTask
import org.sonarlint.intellij.ui.UiUtils.Companion.runOnUiThread
import org.sonarlint.intellij.ui.review.ReviewSecurityHotspotDialog
import org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile
import org.sonarlint.intellij.util.computeOnPooledThread
import org.sonarlint.intellij.util.runOnPooledThread
import org.sonarsource.sonarlint.core.commons.HotspotReviewStatus
import org.sonarsource.sonarlint.core.rpc.protocol.backend.hotspot.CheckStatusChangePermittedResponse
Expand Down Expand Up @@ -103,7 +104,10 @@ class ReviewSecurityHotspotAction(private var serverFindingKey: String? = null,
"No module could be found for this file"
)

val response = checkPermission(project, connection, hotspotKey) ?: return
val response = computeOnPooledThread(project, "Checking permission to mark issue as resolved") {
checkPermission(project, connection, hotspotKey)
} ?: return

val newStatus = HotspotStatus.valueOf(currentStatus.name)
runOnUiThread(project) {
if (ReviewSecurityHotspotDialog(project, connection.productName, module, hotspotKey, response, newStatus).showAndGet()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

import static org.sonarlint.intellij.common.util.SonarLintUtils.getService;
import static org.sonarlint.intellij.util.ProjectUtils.hasFiles;
import static org.sonarlint.intellij.util.ThreadUtilsKt.runOnPooledThread;

public class SonarAnalyzeAllFilesAction extends AbstractSonarAction {
private static final String HIDE_WARNING_PROPERTY = "SonarLint.analyzeAllFiles.hideWarning";
Expand Down Expand Up @@ -70,7 +71,7 @@ public void actionPerformed(AnActionEvent e) {
return;
}

SonarLintUtils.getService(project, AnalysisSubmitter.class).analyzeAllFiles();
runOnPooledThread(project, () -> SonarLintUtils.getService(project, AnalysisSubmitter.class).analyzeAllFiles());
}

static boolean userConfirmed(Project project) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
import com.intellij.openapi.vcs.changes.ChangeListManager;
import javax.swing.Icon;
import org.jetbrains.annotations.Nullable;
import org.sonarlint.intellij.analysis.AnalysisSubmitter;
import org.sonarlint.intellij.analysis.AnalysisStatus;
import org.sonarlint.intellij.analysis.AnalysisSubmitter;
import org.sonarlint.intellij.common.util.SonarLintUtils;
import org.sonarlint.intellij.core.BackendService;

import static org.sonarlint.intellij.common.util.SonarLintUtils.getService;
import static org.sonarlint.intellij.util.ThreadUtilsKt.runOnPooledThread;

public class SonarAnalyzeChangedFilesAction extends AbstractSonarAction {
public SonarAnalyzeChangedFilesAction() {
Expand Down Expand Up @@ -62,6 +63,6 @@ protected boolean isVisible(AnActionEvent e) {
return;
}

SonarLintUtils.getService(project, AnalysisSubmitter.class).analyzeVcsChangedFiles();
runOnPooledThread(project, () -> SonarLintUtils.getService(project, AnalysisSubmitter.class).analyzeVcsChangedFiles());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.sonarlint.intellij.core.BackendService;

import static org.sonarlint.intellij.common.util.SonarLintUtils.getService;
import static org.sonarlint.intellij.util.ThreadUtilsKt.runOnPooledThread;

public class SonarAnalyzeFilesAction extends AbstractSonarAction {

Expand Down Expand Up @@ -88,7 +89,7 @@ public void actionPerformed(AnActionEvent e) {
})
.collect(Collectors.toSet());

getService(project, AnalysisSubmitter.class).analyzeFilesOnUserAction(fileSet, e);
runOnPooledThread(project, () -> getService(project, AnalysisSubmitter.class).analyzeFilesOnUserAction(fileSet, e));
}

private static class CollectFilesVisitor extends VirtualFileVisitor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ import com.intellij.openapi.actionSystem.Presentation
import com.intellij.openapi.project.Project
import org.sonarlint.intellij.cayc.CleanAsYouCodeService
import org.sonarlint.intellij.common.util.SonarLintUtils.getService
import org.sonarlint.intellij.config.Settings
import org.sonarlint.intellij.util.runOnPooledThread

class SonarFocusOnNewCode : AbstractSonarToggleAction() {

override fun isSelected(e: AnActionEvent): Boolean = e.project?.let { getService(CleanAsYouCodeService::class.java).shouldFocusOnNewCode(it) }
?: false

override fun setSelected(e: AnActionEvent, isSelected: Boolean) {
getService(CleanAsYouCodeService::class.java).setFocusOnNewCode(isSelected)
e.project?.let { runOnPooledThread(it) { getService(CleanAsYouCodeService::class.java).setFocusOnNewCode(isSelected) } }
}

override fun updatePresentation(project: Project, presentation: Presentation) {
Expand Down
Loading

0 comments on commit c8da2f5

Please sign in to comment.