Skip to content

Commit

Permalink
fix: update code vision after scan, fix multi-project scan, fix paral…
Browse files Browse the repository at this point in the history
…lel resource contention [IDE-204] (#494)

* fix: progress, refactor ui updates, content roots and such

* fix: container bulk file listener test

* fix: update code visions after scan

* fix: UI freezes, code vision refreshes

* fix: run more UI refreshes async & in read action

* fix: auto-scan after config change, subscribe to config changes

* fix: don't trigger LS initialization from bulk file listener

* chore: optimize imports

* fix: avoid recursion during initialization

fix: avoid recursion during initialization

* fix: changelog merge error
  • Loading branch information
bastiandoetsch authored Apr 2, 2024
1 parent 5ef2a28 commit 5282559
Show file tree
Hide file tree
Showing 21 changed files with 278 additions and 158 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Snyk Security Changelog

## [2.7.13]
### Fixed
- (LS Preview) fix progress handling for Snyk Code scans
- (LS Preview) fix multi-project scanning for Snyk Code
- (LS Preview) fix auto-scan newly opened project, and ask for trust if needed
- (LS Preview) fix CodeVision for opened files

## [2.7.12]
### Added
- Mark ignored findings as ignored behind a feature flag.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class SnykProjectManagerListener : ProjectManagerListener {
AnalysisData.instance.removeProjectFromCaches(project)
SnykCodeIgnoreInfoHolder.instance.removeProject(project)
val ls = LanguageServerWrapper.getInstance()
if (ls.isInitialized) {
if (ls.ensureLanguageServerInitialized()) {
ls.updateWorkspaceFolders(emptySet(), ls.getWorkspaceFolders(project))
}
}.get(TIMEOUT, TimeUnit.SECONDS)
Expand Down
21 changes: 18 additions & 3 deletions src/main/kotlin/io/snyk/plugin/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

package io.snyk.plugin

import com.intellij.codeInsight.codeVision.CodeVisionHost
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.ide.util.PsiNavigationSupport
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.application.ReadAction
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Document
import com.intellij.openapi.fileEditor.FileDocumentManager
Expand All @@ -21,6 +23,7 @@ import com.intellij.openapi.util.io.toNioPathOrNull
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.wm.ToolWindow
import com.intellij.openapi.wm.ToolWindowManager
import com.intellij.psi.PsiFile
Expand Down Expand Up @@ -301,8 +304,15 @@ fun findPsiFileIgnoringExceptions(virtualFile: VirtualFile, project: Project): P

fun refreshAnnotationsForOpenFiles(project: Project) {
if (project.isDisposed) return
VirtualFileManager.getInstance().asyncRefresh()

val openFiles = FileEditorManager.getInstance(project).openFiles
FileContentUtil.reparseFiles(project, openFiles.asList(), true)

ApplicationManager.getApplication().invokeLater {
FileContentUtil.reparseFiles(project, openFiles.asList(), true)
project.service<CodeVisionHost>().invalidateProvider(CodeVisionHost.LensInvalidateSignal(null))
}

openFiles.forEach {
val psiFile = findPsiFileIgnoringExceptions(it, project)
if (psiFile != null) {
Expand Down Expand Up @@ -416,8 +426,13 @@ fun getArch(): String {
return archMap[value] ?: value
}

fun String.toVirtualFile(): VirtualFile =
StandardFileSystems.local().refreshAndFindFileByPath(this) ?: throw FileNotFoundException(this)
fun String.toVirtualFile(): VirtualFile {
return if (!this.startsWith("file://")) {
StandardFileSystems.local().refreshAndFindFileByPath(this) ?: throw FileNotFoundException(this)
} else {
VirtualFileManager.getInstance().refreshAndFindFileByUrl(this) ?: throw FileNotFoundException(this)
}
}

fun VirtualFile.getPsiFile(project: Project): PsiFile? {
return runReadAction { PsiManager.getInstance(project).findFile(this) }
Expand Down
31 changes: 23 additions & 8 deletions src/main/kotlin/io/snyk/plugin/services/SnykTaskQueueService.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.snyk.plugin.services

import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.invokeLater
import com.intellij.openapi.components.Service
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.fileEditor.FileDocumentManager
Expand All @@ -11,6 +11,7 @@ import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.Project
import io.snyk.plugin.events.SnykCliDownloadListener
import io.snyk.plugin.events.SnykScanListener
import io.snyk.plugin.events.SnykSettingsListener
import io.snyk.plugin.events.SnykTaskQueueListener
import io.snyk.plugin.getContainerService
import io.snyk.plugin.getIacService
Expand All @@ -19,6 +20,7 @@ import io.snyk.plugin.getSnykApiService
import io.snyk.plugin.getSnykCachedResults
import io.snyk.plugin.getSnykCliDownloaderService
import io.snyk.plugin.getSnykCode
import io.snyk.plugin.getSnykToolWindowPanel
import io.snyk.plugin.getSyncPublisher
import io.snyk.plugin.isCliDownloading
import io.snyk.plugin.isCliInstalled
Expand All @@ -28,6 +30,7 @@ import io.snyk.plugin.isSnykCodeLSEnabled
import io.snyk.plugin.isSnykCodeRunning
import io.snyk.plugin.net.ClientException
import io.snyk.plugin.pluginSettings
import io.snyk.plugin.refreshAnnotationsForOpenFiles
import io.snyk.plugin.snykcode.core.RunUtils
import io.snyk.plugin.ui.SnykBalloonNotificationHelper
import io.snyk.plugin.ui.SnykBalloonNotifications
Expand Down Expand Up @@ -77,9 +80,21 @@ class SnykTaskQueueService(val project: Project) {

fun connectProjectToLanguageServer(project: Project) {
synchronized(LanguageServerWrapper) {
val wrapper = LanguageServerWrapper.getInstance()
val added = wrapper.getWorkspaceFolders(project)
wrapper.updateWorkspaceFolders(added, emptySet())

// subscribe to the settings changed topic
getSnykToolWindowPanel(project)?.let {
project.messageBus.connect(it)
.subscribe(
SnykSettingsListener.SNYK_SETTINGS_TOPIC,
object : SnykSettingsListener {
override fun settingsChanged() {
val wrapper = LanguageServerWrapper.getInstance()
wrapper.updateConfiguration()
}
}
)
}
LanguageServerWrapper.getInstance().addContentRoots(project)
}
}

Expand All @@ -99,7 +114,7 @@ class SnykTaskQueueService(val project: Project) {
if (!isSnykCodeLSEnabled()) {
scheduleSnykCodeScan()
} else {
LanguageServerWrapper.getInstance().sendScanCommand()
LanguageServerWrapper.getInstance().sendScanCommand(project)
}
}
if (settings.ossScanEnable) {
Expand Down Expand Up @@ -155,7 +170,7 @@ class SnykTaskQueueService(val project: Project) {
}
}
logger.debug("Container scan completed")
DaemonCodeAnalyzer.getInstance(project).restart()
invokeLater { refreshAnnotationsForOpenFiles(project) }
}
})
}
Expand Down Expand Up @@ -230,7 +245,7 @@ class SnykTaskQueueService(val project: Project) {
ossResult.getFirstError()?.let { scanPublisher?.scanningOssError(it) }
}
}
DaemonCodeAnalyzer.getInstance(project).restart()
invokeLater { refreshAnnotationsForOpenFiles(project) }
}
})
}
Expand Down Expand Up @@ -273,7 +288,7 @@ class SnykTaskQueueService(val project: Project) {
}
}
logger.debug("IaC scan completed")
DaemonCodeAnalyzer.getInstance(project).restart()
invokeLater { refreshAnnotationsForOpenFiles(project) }
}
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class SnykCliDownloaderService {
} catch (e: ChecksumVerificationException) {
errorHandler.handleChecksumVerificationException(e, indicator, project)
} finally {
if (succeeded) languageServerWrapper.initialize() else stopCliDownload()
if (succeeded) languageServerWrapper.ensureLanguageServerInitialized() else stopCliDownload()
}
} finally {
cliDownloadPublisher.cliDownloadFinished(succeeded)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import io.snyk.plugin.snykcode.core.SnykCodeParams
import io.snyk.plugin.snykcode.newCodeRestApi
import io.snyk.plugin.ui.SnykBalloonNotificationHelper
import io.snyk.plugin.ui.SnykSettingsDialog
import org.eclipse.lsp4j.DidChangeConfigurationParams
import snyk.amplitude.api.ExperimentUser
import snyk.common.lsp.LanguageServerWrapper
import snyk.common.toSnykCodeApiUrl
Expand Down Expand Up @@ -99,14 +98,10 @@ class SnykProjectSettingsConfigurable(val project: Project) : SearchableConfigur
snykProjectSettingsService?.additionalParameters = snykSettingsDialog.getAdditionalParameters()
}

val wrapper = LanguageServerWrapper.getInstance()
val params = DidChangeConfigurationParams(wrapper.getSettings())
wrapper.languageServer.workspaceService.didChangeConfiguration(params)

if (isSnykCodeLSEnabled()) {
runBackgroundableTask("Updating Snyk Code settings", project, true) {
settingsStateService.isGlobalIgnoresFeatureEnabled =
wrapper.getFeatureFlagStatus("snykCodeConsistentIgnores")
LanguageServerWrapper.getInstance().getFeatureFlagStatus("snykCodeConsistentIgnores")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task.Backgroundable
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
import com.intellij.openapi.vfs.readText
import io.snyk.plugin.SnykBulkFileListener
import io.snyk.plugin.getPsiFile
import io.snyk.plugin.getSnykCachedResults
import io.snyk.plugin.getSnykTaskQueueService
import io.snyk.plugin.isSnykCodeLSEnabled
Expand Down Expand Up @@ -82,7 +82,7 @@ class SnykCodeBulkFileListener : SnykBulkFileListener() {
val languageServerWrapper = LanguageServerWrapper.getInstance()

if (!isSnykCodeLSEnabled()) return
if (!languageServerWrapper.ensureLanguageServerInitialized()) return
if (!languageServerWrapper.isInitialized) return

val languageServer = languageServerWrapper.languageServer
for (event in events) {
Expand All @@ -105,10 +105,9 @@ class SnykCodeBulkFileListener : SnykBulkFileListener() {
val cache = getSnykCachedResults(project)?.currentSnykCodeResultsLS ?: return
filesAffected.forEach {
cache.remove(it)
it.virtualFile.getPsiFile(project)?.let { psiFile ->
DaemonCodeAnalyzer.getInstance(project).restart(psiFile)
}
}
VirtualFileManager.getInstance().asyncRefresh()
DaemonCodeAnalyzer.getInstance(project).restart()
}

private fun toSnykCodeFileSet(project: Project, virtualFiles: Set<VirtualFile>) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package io.snyk.plugin.ui.toolwindow

import ai.deepcode.javaclient.core.MyTextRange
import ai.deepcode.javaclient.core.SuggestionForFile
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.notification.NotificationAction
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
Expand Down Expand Up @@ -445,10 +444,10 @@ class SnykToolWindowPanel(val project: Project) : JPanel(), Disposable {
}
}

DaemonCodeAnalyzer.getInstance(project).restart()

ApplicationManager.getApplication().invokeLater {
doCleanUi(true)
refreshAnnotationsForOpenFiles(project)
}
}

Expand Down
1 change: 0 additions & 1 deletion src/main/kotlin/snyk/WelcomeNotifyActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package snyk

import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.ProjectActivity
import com.intellij.openapi.startup.StartupActivity
import io.snyk.plugin.pluginSettings
import io.snyk.plugin.services.SnykApplicationSettingsStateService
import io.snyk.plugin.ui.SnykBalloonNotifications
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/snyk/code/annotator/SnykCodeAnnotatorLS.kt
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ class SnykCodeAnnotatorLS : ExternalAnnotator<PsiFile, Unit>() {
.resolveCodeAction(codeAction).get(TIMEOUT, TimeUnit.SECONDS)

val edit = resolvedCodeAction.edit
if (edit.changes == null) return
if (edit == null || edit.changes == null) return
changes = edit.changes
} else {
val codeActionCommand = resolvedCodeAction.command
Expand Down
5 changes: 3 additions & 2 deletions src/main/kotlin/snyk/common/AnnotatorCommon.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package snyk.common

import com.intellij.openapi.application.invokeLater
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
Expand Down Expand Up @@ -33,7 +34,7 @@ object AnnotatorCommon {
SnykProductsOrSeverityListener.SNYK_ENABLEMENT_TOPIC,
object : SnykProductsOrSeverityListener {
override fun enablementChanged() {
refreshAnnotationsForOpenFiles(project)
invokeLater { refreshAnnotationsForOpenFiles(project) }
}
}
)
Expand All @@ -42,7 +43,7 @@ object AnnotatorCommon {
SnykSettingsListener.SNYK_SETTINGS_TOPIC,
object : SnykSettingsListener {
override fun settingsChanged() {
refreshAnnotationsForOpenFiles(project)
invokeLater { refreshAnnotationsForOpenFiles(project) }
}
}
)
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/snyk/common/CustomEndpoints.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package snyk.common

import io.snyk.plugin.pluginSettings
import io.snyk.plugin.suffixIfNot
import io.snyk.plugin.prefixIfNot
import io.snyk.plugin.suffixIfNot
import java.net.URI
import java.net.URISyntaxException

Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/snyk/common/lsp/LSCodeVisionProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class LSCodeVisionProvider : CodeVisionProvider<Unit> {
override fun computeCodeVision(editor: Editor, uiData: Unit): CodeVisionState {
if (editor.project == null) return CodeVisionState.READY_EMPTY
if (!isSnykCodeLSEnabled()) return CodeVisionState.READY_EMPTY
if (!LanguageServerWrapper.getInstance().ensureLanguageServerInitialized()) return CodeVisionState.READY_EMPTY
if (!LanguageServerWrapper.getInstance().isInitialized) return CodeVisionState.READY_EMPTY
if (isSnykCodeRunning(editor.project!!)) return CodeVisionState.READY_EMPTY

return ReadAction.compute<CodeVisionState, RuntimeException> {
Expand Down
Loading

0 comments on commit 5282559

Please sign in to comment.