diff --git a/common/src/main/java/org/sonarlint/intellij/common/util/FileUtils.kt b/common/src/main/java/org/sonarlint/intellij/common/util/FileUtils.kt index e5d23ef6e..b6ffd0dcb 100644 --- a/common/src/main/java/org/sonarlint/intellij/common/util/FileUtils.kt +++ b/common/src/main/java/org/sonarlint/intellij/common/util/FileUtils.kt @@ -33,12 +33,29 @@ import org.sonarlint.intellij.common.ui.SonarLintConsole class FileUtils { companion object { + // To be used with iterateContent, because it already skips ignored and excluded files fun isFileValidForSonarLint(file: VirtualFile, project: Project): Boolean { + try { + val toSkip = computeReadActionSafely(file, project) { + (!ApplicationManager.getApplication().isUnitTestMode && !file.isDirectory && FileUtilRt.isTooLarge(file.length)) + || FileElement.isArchive(file) + || ProjectCoreUtil.isProjectOrWorkspaceFile(file) + || isGeneratedSourceByAnyFilter(file, project) + } + + return false == toSkip + } catch (e: Exception) { + SonarLintConsole.get(project).error("Error while visiting a file, reason: " + e.message) + return false + } + } + + // To be used when using iterating over all children + fun isFileValidForSonarLintWithExtensiveChecks(file: VirtualFile, project: Project): Boolean { try { val fileIndex = ProjectRootManager.getInstance(project).fileIndex val toSkip = computeReadActionSafely(file, project) { - project.isDisposed - || (!ApplicationManager.getApplication().isUnitTestMode && !file.isDirectory && FileUtilRt.isTooLarge(file.length)) + (!ApplicationManager.getApplication().isUnitTestMode && !file.isDirectory && FileUtilRt.isTooLarge(file.length)) || FileElement.isArchive(file) || !fileIndex.isInContent(file) || fileIndex.isInLibrarySource(file) diff --git a/rider/src/main/java/org/sonarlint/intellij/rider/RiderFilesContributor.kt b/rider/src/main/java/org/sonarlint/intellij/rider/RiderFilesContributor.kt index 628095a4b..3fa926d50 100644 --- a/rider/src/main/java/org/sonarlint/intellij/rider/RiderFilesContributor.kt +++ b/rider/src/main/java/org/sonarlint/intellij/rider/RiderFilesContributor.kt @@ -20,14 +20,13 @@ package org.sonarlint.intellij.rider import com.intellij.openapi.module.Module -import com.intellij.openapi.project.guessProjectDir import com.intellij.openapi.vfs.VirtualFile import com.jetbrains.rider.projectView.workspace.ProjectModelEntity import com.jetbrains.rider.projectView.workspace.ProjectModelEntityVisitor import com.jetbrains.rider.projectView.workspace.getVirtualFileAsContentRoot import com.jetbrains.rider.projectView.workspace.isProjectFile import org.sonarlint.intellij.common.analysis.FilesContributor -import org.sonarlint.intellij.common.util.FileUtils.Companion.isFileValidForSonarLint +import org.sonarlint.intellij.common.util.FileUtils.Companion.isFileValidForSonarLintWithExtensiveChecks class RiderFilesContributor : FilesContributor { @@ -37,11 +36,6 @@ class RiderFilesContributor : FilesContributor { // List files in Solution filesInContentRoots.addAll(listFilesInSolution(module)) - // List files in project dir, sometimes not all files are found via the previous method - filesInContentRoots.addAll( - module.project.guessProjectDir()?.children?.filter { !it.isDirectory && it.isValid }?.toSet() ?: emptySet() - ) - return filesInContentRoots } @@ -55,7 +49,7 @@ class RiderFilesContributor : FilesContributor { if (entity.isProjectFile()) { entity.getVirtualFileAsContentRoot()?.let { - if (!it.isDirectory && it.isValid && isFileValidForSonarLint(it, module.project)) { + if (!it.isDirectory && isFileValidForSonarLintWithExtensiveChecks(it, module.project)) { filesInSolution.add(it) } } diff --git a/rider/src/main/java/org/sonarlint/intellij/rider/RiderSolutionGitRepoProvider.kt b/rider/src/main/java/org/sonarlint/intellij/rider/RiderSolutionGitRepoProvider.kt index 248edf165..dbe275534 100644 --- a/rider/src/main/java/org/sonarlint/intellij/rider/RiderSolutionGitRepoProvider.kt +++ b/rider/src/main/java/org/sonarlint/intellij/rider/RiderSolutionGitRepoProvider.kt @@ -28,7 +28,7 @@ import com.jetbrains.rider.projectView.workspace.isProjectFile import git4idea.repo.GitRepository import git4idea.repo.GitRepositoryManager import org.sonarlint.intellij.common.ui.SonarLintConsole -import org.sonarlint.intellij.common.util.FileUtils.Companion.isFileValidForSonarLint +import org.sonarlint.intellij.common.util.FileUtils.Companion.isFileValidForSonarLintWithExtensiveChecks import org.sonarlint.intellij.common.vcs.VcsRepo import org.sonarlint.intellij.common.vcs.VcsRepoProvider import org.sonarlint.intellij.git.GitRepo @@ -78,7 +78,7 @@ class RiderSolutionGitRepoProvider : VcsRepoProvider { if (entity.isProjectFile()) { entity.getVirtualFileAsContentRoot()?.let { - if (!it.isDirectory && it.isValid && isFileValidForSonarLint(it, project)) { + if (!it.isDirectory && isFileValidForSonarLintWithExtensiveChecks(it, project)) { repositoryManager.getRepositoryForFile(it)?.let { repo -> moduleRepositories.add(repo) } } } diff --git a/src/main/java/org/sonarlint/intellij/SonarLintIntelliJClient.kt b/src/main/java/org/sonarlint/intellij/SonarLintIntelliJClient.kt index 1e27a3675..4975a1421 100644 --- a/src/main/java/org/sonarlint/intellij/SonarLintIntelliJClient.kt +++ b/src/main/java/org/sonarlint/intellij/SonarLintIntelliJClient.kt @@ -34,7 +34,6 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.project.ProjectManager import com.intellij.openapi.project.guessProjectDir import com.intellij.openapi.project.modules -import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.TestSourcesFilter.isTestSources import com.intellij.openapi.ui.MessageDialogBuilder import com.intellij.openapi.util.io.FileUtilRt @@ -70,6 +69,7 @@ import org.sonarlint.intellij.analysis.RunningAnalysesTracker import org.sonarlint.intellij.common.analysis.FilesContributor import org.sonarlint.intellij.common.ui.ReadActionUtils.Companion.computeReadActionSafely import org.sonarlint.intellij.common.ui.SonarLintConsole +import org.sonarlint.intellij.common.util.FileUtils.Companion.isFileValidForSonarLintWithExtensiveChecks import org.sonarlint.intellij.common.util.SonarLintUtils.getService import org.sonarlint.intellij.common.util.SonarLintUtils.isRider import org.sonarlint.intellij.common.vcs.VcsRepo @@ -110,7 +110,7 @@ import org.sonarlint.intellij.util.GlobalLogOutput import org.sonarlint.intellij.util.ProjectUtils.tryFindFile import org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile import org.sonarlint.intellij.util.SonarLintAppUtils.getRelativePathForAnalysis -import org.sonarlint.intellij.util.SonarLintAppUtils.visitAndAddFiles +import org.sonarlint.intellij.util.SonarLintAppUtils.visitAndAddAllFilesForModule import org.sonarlint.intellij.util.VirtualFileUtils import org.sonarlint.intellij.util.VirtualFileUtils.getFileContent import org.sonarlint.intellij.util.computeInEDT @@ -674,17 +674,19 @@ object SonarLintIntelliJClient : SonarLintRpcClientDelegate { override fun listFiles(configScopeId: String): List { val timeStart = System.currentTimeMillis() val listClientFiles = BackendService.findModule(configScopeId)?.let { module -> - listModuleFiles(module, configScopeId) + computeOnPooledThread(module.project, "Listing All Module Files") { listModuleFiles(module, configScopeId) } } ?: findProject(configScopeId)?.let { project -> - val listProjectFiles = listProjectFiles(project, configScopeId) + computeOnPooledThread(project, "Listing All Project Files") { + val listProjectFiles = listProjectFiles(project, configScopeId) - if (isRider()) { - computeRiderSharedConfiguration(project, configScopeId)?.let { - listProjectFiles.add(it) + if (isRider()) { + computeRiderSharedConfiguration(project, configScopeId)?.let { + listProjectFiles.add(it) + } } + + listProjectFiles } - - listProjectFiles } ?: emptyList() val timeEnd = System.currentTimeMillis() @@ -720,7 +722,7 @@ object SonarLintIntelliJClient : SonarLintRpcClientDelegate { } private fun listModuleFiles(module: Module, configScopeId: String): MutableList { - val filesInContentRoots = listFilesInContentRoots(module) + val filesInContentRoots = visitAndAddAllFilesForModule(module) FilesContributor.EP_NAME.extensionList.forEach { filesInContentRoots.addAll(it.listFiles(module)) @@ -764,6 +766,16 @@ object SonarLintIntelliJClient : SonarLintRpcClientDelegate { }.toMutableList() } + // useful for Rider where the files to find are not located in content roots + private fun listFilesInProjectBaseDir(project: Project): Set { + return project.guessProjectDir()?.children?.filter { + !it.isDirectory && isFileValidForSonarLintWithExtensiveChecks( + it, + project + ) + }?.toSet() ?: return emptySet() + } + private fun toClientFileDto( project: Project, configScopeId: String, @@ -795,24 +807,6 @@ object SonarLintIntelliJClient : SonarLintRpcClientDelegate { } } - private fun listFilesInContentRoots( - module: Module, - ): MutableSet { - val files = mutableListOf() - ModuleRootManager.getInstance(module).contentRoots.forEach { contentRoot -> - if (module.isDisposed) { - return@forEach - } - files.addAll(visitAndAddFiles(contentRoot, module.project)) - } - return files.toMutableSet() - } - - // useful for Rider where the files to find are not located in content roots - private fun listFilesInProjectBaseDir(project: Project): Set { - return project.guessProjectDir()?.children?.filter { !it.isDirectory && it.isValid }?.toSet() ?: return emptySet() - } - override fun didChangeTaintVulnerabilities( configurationScopeId: String, closedTaintVulnerabilityIds: Set, addedTaintVulnerabilities: List, updatedTaintVulnerabilities: List, diff --git a/src/main/java/org/sonarlint/intellij/actions/ExcludeFileAction.kt b/src/main/java/org/sonarlint/intellij/actions/ExcludeFileAction.kt index 44c753218..6d9c15de1 100644 --- a/src/main/java/org/sonarlint/intellij/actions/ExcludeFileAction.kt +++ b/src/main/java/org/sonarlint/intellij/actions/ExcludeFileAction.kt @@ -32,7 +32,7 @@ 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.util.SonarLintAppUtils +import org.sonarlint.intellij.util.SonarLintAppUtils.getRelativePathForAnalysis import org.sonarlint.intellij.util.runOnPooledThread class ExcludeFileAction : AbstractSonarAction { @@ -77,7 +77,7 @@ class ExcludeFileAction : AbstractSonarAction { } private fun toExclusion(project: Project, virtualFile: VirtualFile): ExclusionItem? { - val relativeFilePath = SonarLintAppUtils.getRelativePathForAnalysis(project, virtualFile) ?: return null + val relativeFilePath = getRelativePathForAnalysis(project, virtualFile) ?: return null return if (virtualFile.isDirectory) { ExclusionItem(ExclusionItem.Type.DIRECTORY, relativeFilePath) } else { diff --git a/src/main/java/org/sonarlint/intellij/actions/SonarAnalyzeFilesAction.java b/src/main/java/org/sonarlint/intellij/actions/SonarAnalyzeFilesAction.java index 580c15eb5..2a39c48ef 100644 --- a/src/main/java/org/sonarlint/intellij/actions/SonarAnalyzeFilesAction.java +++ b/src/main/java/org/sonarlint/intellij/actions/SonarAnalyzeFilesAction.java @@ -28,9 +28,9 @@ import org.sonarlint.intellij.analysis.AnalysisStatus; import org.sonarlint.intellij.analysis.AnalysisSubmitter; import org.sonarlint.intellij.core.BackendService; -import org.sonarlint.intellij.util.SonarLintAppUtils; import static org.sonarlint.intellij.common.util.SonarLintUtils.getService; +import static org.sonarlint.intellij.util.SonarLintAppUtils.visitAndAddAllChildren; import static org.sonarlint.intellij.util.ThreadUtilsKt.runOnPooledThread; public class SonarAnalyzeFilesAction extends AbstractSonarAction { @@ -74,7 +74,7 @@ public void actionPerformed(AnActionEvent e) { var fileSet = Stream.of(files) .flatMap(f -> { if (f.isDirectory()) { - var listFiles = SonarLintAppUtils.visitAndAddFiles(f, project); + var listFiles = visitAndAddAllChildren(f, project); return listFiles.stream(); } else { return Stream.of(f); diff --git a/src/main/java/org/sonarlint/intellij/analysis/AnalysisSubmitter.java b/src/main/java/org/sonarlint/intellij/analysis/AnalysisSubmitter.java index ec87307f3..5a3df9239 100644 --- a/src/main/java/org/sonarlint/intellij/analysis/AnalysisSubmitter.java +++ b/src/main/java/org/sonarlint/intellij/analysis/AnalysisSubmitter.java @@ -51,11 +51,11 @@ import org.sonarlint.intellij.tasks.TaskRunnerKt; import org.sonarlint.intellij.trigger.TriggerType; import org.sonarlint.intellij.ui.SonarLintToolWindowFactory; -import org.sonarlint.intellij.util.SonarLintAppUtils; import static org.sonarlint.intellij.common.util.SonarLintUtils.getService; import static org.sonarlint.intellij.config.Settings.getGlobalSettings; -import static org.sonarlint.intellij.util.ProjectUtils.getAllFiles; +import static org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile; +import static org.sonarlint.intellij.util.SonarLintAppUtils.visitAndAddAllFilesForProject; @Service(Service.Level.PROJECT) public final class AnalysisSubmitter { @@ -81,7 +81,7 @@ public void cancelCurrentManualAnalysis() { } public void analyzeAllFiles() { - var allFiles = getAllFiles(project); + var allFiles = visitAndAddAllFilesForProject(project); var callback = new ShowReportCallable(project); var analysis = new Analysis(project, allFiles, TriggerType.ALL, callback); TaskRunnerKt.startBackgroundableModalTask(project, ANALYSIS_TASK_TITLE, analysis::run); @@ -102,7 +102,7 @@ public void autoAnalyzeOpenFilesForModule(TriggerType triggerType, @Nullable Mod var openFiles = FileEditorManager.getInstance(project).getOpenFiles(); var filesToAnalyze = Arrays.stream(openFiles) - .filter(file -> module.equals(SonarLintAppUtils.findModuleForFile(file, project))) + .filter(file -> module.equals(findModuleForFile(file, project))) .toList(); if (!filesToAnalyze.isEmpty()) { diff --git a/src/main/java/org/sonarlint/intellij/analysis/LocalFileExclusions.java b/src/main/java/org/sonarlint/intellij/analysis/LocalFileExclusions.java index 22743807b..495341e01 100644 --- a/src/main/java/org/sonarlint/intellij/analysis/LocalFileExclusions.java +++ b/src/main/java/org/sonarlint/intellij/analysis/LocalFileExclusions.java @@ -47,12 +47,13 @@ import org.sonarlint.intellij.config.project.SonarLintProjectSettings; import org.sonarlint.intellij.messages.GlobalConfigurationListener; import org.sonarlint.intellij.messages.ProjectConfigurationListener; -import org.sonarlint.intellij.util.SonarLintAppUtils; import org.sonarsource.sonarlint.core.client.utils.ClientFileExclusions; import static org.sonarlint.intellij.common.ui.ReadActionUtils.computeReadActionSafely; import static org.sonarlint.intellij.config.Settings.getGlobalSettings; import static org.sonarlint.intellij.config.Settings.getSettingsFor; +import static org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile; +import static org.sonarlint.intellij.util.SonarLintAppUtils.getRelativePathForAnalysis; @Service(Service.Level.PROJECT) public final class LocalFileExclusions { @@ -107,7 +108,7 @@ public void applied(SonarLintGlobalSettings previousSettings, SonarLintGlobalSet * Checks if a file is excluded from analysis based on locally configured exclusions. */ private ExcludeResult checkExclusionsFromSonarLintSettings(VirtualFile file, Module module) { - var relativePath = SonarLintAppUtils.getRelativePathForAnalysis(module, file); + var relativePath = getRelativePathForAnalysis(module, file); if (relativePath == null) { return ExcludeResult.excluded("Could not create a relative path"); } @@ -159,7 +160,7 @@ public Map> retainNonExcludedFilesByModules(Coll private void checkExclusionsFileByFile(boolean forcedAnalysis, BiConsumer excludedFileHandler, Map> filesByModule, VirtualFile file) { - var module = SonarLintAppUtils.findModuleForFile(file, myProject); + var module = findModuleForFile(file, myProject); // Handle this case first, so that later we are guaranteed module is not null if (module == null) { excludedFileHandler.accept(file, ExcludeResult.excluded("file is not part of any module in IntelliJ's project structure")); diff --git a/src/main/java/org/sonarlint/intellij/analysis/SonarLintAnalyzer.java b/src/main/java/org/sonarlint/intellij/analysis/SonarLintAnalyzer.java index 99e1fedfa..35bc13806 100644 --- a/src/main/java/org/sonarlint/intellij/analysis/SonarLintAnalyzer.java +++ b/src/main/java/org/sonarlint/intellij/analysis/SonarLintAnalyzer.java @@ -40,13 +40,13 @@ import org.sonarlint.intellij.common.ui.SonarLintConsole; import org.sonarlint.intellij.config.Settings; import org.sonarlint.intellij.core.BackendService; -import org.sonarlint.intellij.util.SonarLintAppUtils; import org.sonarlint.intellij.util.VirtualFileUtils; import org.sonarsource.sonarlint.core.rpc.protocol.backend.analysis.AnalyzeFilesResponse; import static org.sonarlint.intellij.common.ui.ReadActionUtils.computeReadActionSafely; import static org.sonarlint.intellij.common.util.SonarLintUtils.getService; import static org.sonarlint.intellij.util.ProgressUtils.waitForFuture; +import static org.sonarlint.intellij.util.SonarLintAppUtils.getRelativePathForAnalysis; @Service(Service.Level.PROJECT) public final class SonarLintAnalyzer { @@ -148,7 +148,7 @@ private static List getInputFiles(Module module, Collection fi @CheckForNull private static URI createClientInputFile(Module module, VirtualFile virtualFile) { - var relativePath = SonarLintAppUtils.getRelativePathForAnalysis(module, virtualFile); + var relativePath = getRelativePathForAnalysis(module, virtualFile); if (relativePath != null) { return createURI(virtualFile); } diff --git a/src/main/java/org/sonarlint/intellij/core/BackendService.kt b/src/main/java/org/sonarlint/intellij/core/BackendService.kt index 37e256c28..b04fb1503 100644 --- a/src/main/java/org/sonarlint/intellij/core/BackendService.kt +++ b/src/main/java/org/sonarlint/intellij/core/BackendService.kt @@ -77,7 +77,7 @@ import org.sonarlint.intellij.messages.GlobalConfigurationListener import org.sonarlint.intellij.notifications.SonarLintProjectNotifications.Companion.projectLessNotification import org.sonarlint.intellij.ui.UiUtils.Companion.runOnUiThread import org.sonarlint.intellij.util.GlobalLogOutput -import org.sonarlint.intellij.util.SonarLintAppUtils +import org.sonarlint.intellij.util.SonarLintAppUtils.getRelativePathForAnalysis import org.sonarlint.intellij.util.VirtualFileUtils import org.sonarlint.intellij.util.VirtualFileUtils.getFileContent import org.sonarlint.intellij.util.runOnPooledThread @@ -917,7 +917,7 @@ class BackendService : Disposable { event.filter { it.type != ModuleFileEvent.Type.DELETED } .mapNotNull { - val relativePath = SonarLintAppUtils.getRelativePathForAnalysis(module, it.virtualFile) ?: return@mapNotNull null + val relativePath = getRelativePathForAnalysis(module, it.virtualFile) ?: return@mapNotNull null val forcedLanguage = contributedLanguages[it.virtualFile]?.let { fl -> Language.valueOf(fl.name) } val uri = VirtualFileUtils.toURI(it.virtualFile) ClientFileDto( diff --git a/src/main/java/org/sonarlint/intellij/fs/DefaultVirtualFileSystemEventsHandler.kt b/src/main/java/org/sonarlint/intellij/fs/DefaultVirtualFileSystemEventsHandler.kt index cd076e201..5d0d2ab33 100644 --- a/src/main/java/org/sonarlint/intellij/fs/DefaultVirtualFileSystemEventsHandler.kt +++ b/src/main/java/org/sonarlint/intellij/fs/DefaultVirtualFileSystemEventsHandler.kt @@ -34,7 +34,7 @@ import org.sonarlint.intellij.common.util.FileUtils import org.sonarlint.intellij.common.util.SonarLintUtils.getService import org.sonarlint.intellij.core.BackendService import org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile -import org.sonarlint.intellij.util.SonarLintAppUtils.visitAndAddFiles +import org.sonarlint.intellij.util.SonarLintAppUtils.visitAndAddAllChildren import org.sonarsource.sonarlint.plugin.api.module.file.ModuleFileEvent open class DefaultVirtualFileSystemEventsHandler @NonInjectable constructor(private val executorService: ExecutorService) : VirtualFileSystemEventsHandler, Disposable { @@ -70,7 +70,7 @@ open class DefaultVirtualFileSystemEventsHandler @NonInjectable constructor(priv val file = event.file ?: continue if (ProjectCoreUtil.isProjectOrWorkspaceFile(file)) continue val fileModule = findModule(file, openProjects) ?: continue - if (!FileUtils.Companion.isFileValidForSonarLint(file, fileModule.project)) continue + if (!FileUtils.Companion.isFileValidForSonarLintWithExtensiveChecks(file, fileModule.project)) continue val fileInvolved = if (event is VFileCopyEvent) event.findCreatedFile() else file fileInvolved ?: continue val type = eventTypeConverter(event) ?: continue @@ -85,7 +85,7 @@ open class DefaultVirtualFileSystemEventsHandler @NonInjectable constructor(priv fileModule: Module, type: ModuleFileEvent.Type, ): List { - return visitAndAddFiles(file, fileModule.project).mapNotNull { VirtualFileEvent(type, it) } + return visitAndAddAllChildren(file, fileModule.project).mapNotNull { VirtualFileEvent(type, it) } } private fun findModule(file: VirtualFile?, openProjects: List): Module? { diff --git a/src/main/java/org/sonarlint/intellij/fs/EditorFileChangeListener.kt b/src/main/java/org/sonarlint/intellij/fs/EditorFileChangeListener.kt index e6405b017..9132ce396 100644 --- a/src/main/java/org/sonarlint/intellij/fs/EditorFileChangeListener.kt +++ b/src/main/java/org/sonarlint/intellij/fs/EditorFileChangeListener.kt @@ -34,7 +34,7 @@ import org.sonarlint.intellij.common.util.FileUtils import org.sonarlint.intellij.common.util.SonarLintUtils.getService import org.sonarlint.intellij.core.BackendService import org.sonarlint.intellij.util.Alarm -import org.sonarlint.intellij.util.SonarLintAppUtils +import org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile import org.sonarsource.sonarlint.plugin.api.module.file.ModuleFileEvent const val DEBOUNCE_DELAY_MS = 1000L @@ -79,9 +79,9 @@ class EditorFileChangeListener : BulkAwareDocumentListener.Simple, Disposable { val filesToSendPerModule = HashMap>() changedFiles - .filter { it.isValid && FileUtils.Companion.isFileValidForSonarLint(it, project) } + .filter { FileUtils.Companion.isFileValidForSonarLintWithExtensiveChecks(it, project) } .forEach { file -> - val module = SonarLintAppUtils.findModuleForFile(file, project) ?: return@forEach + val module = findModuleForFile(file, project) ?: return@forEach filesToSendPerModule.computeIfAbsent(module) { mutableListOf() }.add(VirtualFileEvent(ModuleFileEvent.Type.MODIFIED, file)) } diff --git a/src/main/java/org/sonarlint/intellij/trigger/EditorChangeTrigger.java b/src/main/java/org/sonarlint/intellij/trigger/EditorChangeTrigger.java index 9de95392b..9df6343bf 100644 --- a/src/main/java/org/sonarlint/intellij/trigger/EditorChangeTrigger.java +++ b/src/main/java/org/sonarlint/intellij/trigger/EditorChangeTrigger.java @@ -33,9 +33,9 @@ import java.util.concurrent.ConcurrentHashMap; import javax.annotation.concurrent.ThreadSafe; import org.sonarlint.intellij.messages.AnalysisListener; -import org.sonarlint.intellij.util.SonarLintAppUtils; import static org.sonarlint.intellij.config.Settings.getGlobalSettings; +import static org.sonarlint.intellij.util.SonarLintAppUtils.guessProjectForFile; @ThreadSafe @Service(Service.Level.PROJECT) @@ -78,7 +78,7 @@ public void documentChanged(DocumentEvent event) { if (file == null) { return; } - var project = SonarLintAppUtils.guessProjectForFile(file); + var project = guessProjectForFile(file); if (project == null || !project.equals(myProject)) { return; diff --git a/src/main/java/org/sonarlint/intellij/trigger/EditorOpenTrigger.java b/src/main/java/org/sonarlint/intellij/trigger/EditorOpenTrigger.java index 499a377a6..2557b0f8a 100644 --- a/src/main/java/org/sonarlint/intellij/trigger/EditorOpenTrigger.java +++ b/src/main/java/org/sonarlint/intellij/trigger/EditorOpenTrigger.java @@ -34,10 +34,10 @@ import org.sonarlint.intellij.core.BackendService; import org.sonarlint.intellij.fs.VirtualFileEvent; import org.sonarlint.intellij.messages.AnalysisListener; -import org.sonarlint.intellij.util.SonarLintAppUtils; import org.sonarsource.sonarlint.plugin.api.module.file.ModuleFileEvent; import static org.sonarlint.intellij.common.util.SonarLintUtils.getService; +import static org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile; import static org.sonarlint.intellij.util.ThreadUtilsKt.runOnPooledThread; @ThreadSafe @@ -76,7 +76,7 @@ private void removeFiles(Collection files) { @Override public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) { runOnPooledThread(source.getProject(), () -> { - var module = SonarLintAppUtils.findModuleForFile(file, source.getProject()); + var module = findModuleForFile(file, source.getProject()); if (module != null) { getService(BackendService.class).updateFileSystem(Map.of(module, List.of(new VirtualFileEvent(ModuleFileEvent.Type.CREATED, file)))); } diff --git a/src/main/java/org/sonarlint/intellij/ui/AutoTriggerStatusPanel.java b/src/main/java/org/sonarlint/intellij/ui/AutoTriggerStatusPanel.java index 98c4914a8..366f77dad 100644 --- a/src/main/java/org/sonarlint/intellij/ui/AutoTriggerStatusPanel.java +++ b/src/main/java/org/sonarlint/intellij/ui/AutoTriggerStatusPanel.java @@ -46,11 +46,11 @@ import org.sonarlint.intellij.analysis.LocalFileExclusions; import org.sonarlint.intellij.common.util.SonarLintUtils; import org.sonarlint.intellij.core.BackendService; -import org.sonarlint.intellij.util.SonarLintAppUtils; import static org.sonarlint.intellij.common.util.SonarLintUtils.getService; import static org.sonarlint.intellij.config.Settings.getGlobalSettings; import static org.sonarlint.intellij.ui.UiUtils.runOnUiThread; +import static org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile; import static org.sonarlint.intellij.util.ThreadUtilsKt.runOnPooledThread; public class AutoTriggerStatusPanel { @@ -120,7 +120,7 @@ private void switchCards() { } private void handleExcludedFiles(VirtualFile selectedFile, Map> nonExcluded) { - var module = SonarLintAppUtils.findModuleForFile(selectedFile, project); + var module = findModuleForFile(selectedFile, project); if (!nonExcluded.isEmpty() && module != null) { var files = nonExcluded.get(module); var excludedFilesFromServer = getService(BackendService.class).getExcludedFiles(module, files); diff --git a/src/main/java/org/sonarlint/intellij/ui/CurrentFileConnectedModePanel.java b/src/main/java/org/sonarlint/intellij/ui/CurrentFileConnectedModePanel.java index c0ef36a8d..10164b5c1 100644 --- a/src/main/java/org/sonarlint/intellij/ui/CurrentFileConnectedModePanel.java +++ b/src/main/java/org/sonarlint/intellij/ui/CurrentFileConnectedModePanel.java @@ -46,12 +46,12 @@ import org.sonarlint.intellij.core.ProjectBindingManager; import org.sonarlint.intellij.documentation.SonarLintDocumentation; import org.sonarlint.intellij.util.SonarLintActions; -import org.sonarlint.intellij.util.SonarLintAppUtils; import static org.apache.commons.text.StringEscapeUtils.escapeHtml4; import static org.sonarlint.intellij.common.util.SonarLintUtils.getService; import static org.sonarlint.intellij.common.util.SonarLintUtils.withoutTrailingSlash; import static org.sonarlint.intellij.ui.UiUtils.runOnUiThread; +import static org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile; import static org.sonarlint.intellij.util.ThreadUtilsKt.runOnPooledThread; public class CurrentFileConnectedModePanel { @@ -165,7 +165,7 @@ private void switchCards() { var projectBindingManager = getService(project, ProjectBindingManager.class); projectBindingManager.tryGetServerConnection().ifPresentOrElse(serverConnection -> { try { - var module = SonarLintAppUtils.findModuleForFile(selectedFile, project); + var module = findModuleForFile(selectedFile, project); if (module == null) { switchCard(EMPTY); } else { @@ -191,7 +191,7 @@ private void updateBranchTooltip() { var selectedFile = SonarLintUtils.getSelectedFile(project); if (selectedFile != null) { runOnPooledThread(project, () -> { - var module = SonarLintAppUtils.findModuleForFile(selectedFile, project); + var module = findModuleForFile(selectedFile, project); if (module != null) { runOnUiThread(project, () -> connectedCard.updateTooltip(module, serverConnection)); } diff --git a/src/main/java/org/sonarlint/intellij/util/Extensions.kt b/src/main/java/org/sonarlint/intellij/util/Extensions.kt index 0625efc71..6306fb24d 100644 --- a/src/main/java/org/sonarlint/intellij/util/Extensions.kt +++ b/src/main/java/org/sonarlint/intellij/util/Extensions.kt @@ -31,10 +31,11 @@ import com.intellij.psi.PsiDocumentManager import java.util.concurrent.atomic.AtomicReference import org.sonarlint.intellij.common.ui.ReadActionUtils.Companion.runReadActionSafely import org.sonarlint.intellij.util.SonarLintAppUtils.findModuleForFile +import org.sonarlint.intellij.util.SonarLintAppUtils.getRelativePathForAnalysis fun Project.getOpenFiles() = FileEditorManager.getInstance(this).openFiles.toList() -fun Project.getRelativePathOf(file: VirtualFile) = SonarLintAppUtils.getRelativePathForAnalysis(this, file) +fun Project.getRelativePathOf(file: VirtualFile) = getRelativePathForAnalysis(this, file) fun Project.findModuleOf(file: VirtualFile): Module? { return findModuleForFile(file, this) diff --git a/src/main/java/org/sonarlint/intellij/util/ProjectUtils.java b/src/main/java/org/sonarlint/intellij/util/ProjectUtils.java index b9b91e93c..d2221b6a1 100644 --- a/src/main/java/org/sonarlint/intellij/util/ProjectUtils.java +++ b/src/main/java/org/sonarlint/intellij/util/ProjectUtils.java @@ -31,33 +31,15 @@ import java.nio.file.Paths; import java.util.Collection; import java.util.HashMap; -import java.util.LinkedHashSet; import java.util.Map; import javax.annotation.CheckForNull; -import org.sonarlint.intellij.common.util.FileUtils; import org.sonarlint.intellij.finding.TextRangeMatcher; import static org.sonarlint.intellij.common.ui.ReadActionUtils.computeReadActionSafely; +import static org.sonarlint.intellij.util.SonarLintAppUtils.getRelativePathForAnalysis; public class ProjectUtils { - public static Collection getAllFiles(Project project) { - var fileSet = new LinkedHashSet(); - var fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); - fileIndex.iterateContent(vFile -> { - if (project.isDisposed()) { - return false; - } - if (!vFile.isDirectory() && vFile.isValid() && FileUtils.Companion.isFileValidForSonarLint(vFile, project)) { - fileSet.add(vFile); - return true; - } - // Continue iteration - return true; - }); - return fileSet; - } - public static PsiFile toPsiFile(Project project, VirtualFile file) throws TextRangeMatcher.NoMatchException { ApplicationManager.getApplication().assertReadAccessAllowed(); var psiManager = PsiManager.getInstance(project); @@ -73,7 +55,7 @@ public static Map getRelativePaths(Project project, Collectio Map relativePathPerFile = new HashMap<>(); for (var file : files) { - var relativePath = SonarLintAppUtils.getRelativePathForAnalysis(project, file); + var relativePath = getRelativePathForAnalysis(project, file); if (relativePath != null) { relativePathPerFile.put(file, Paths.get(relativePath)); } diff --git a/src/main/java/org/sonarlint/intellij/util/SonarLintAppUtils.java b/src/main/java/org/sonarlint/intellij/util/SonarLintAppUtils.java index 9a3bf5991..474ab2f25 100644 --- a/src/main/java/org/sonarlint/intellij/util/SonarLintAppUtils.java +++ b/src/main/java/org/sonarlint/intellij/util/SonarLintAppUtils.java @@ -27,6 +27,7 @@ import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileVisitor; @@ -157,17 +158,55 @@ static String getPathRelativeToModuleBaseDir(Module module, VirtualFile file) { return null; } - public static List visitAndAddFiles(VirtualFile file, Project project) { + public static List visitAndAddAllFilesForModule(Module module) { + var filesToAdd = new ArrayList(); + var moduleFileIndex = ModuleRootManager.getInstance(module).getFileIndex(); + moduleFileIndex.iterateContent(vFile -> { + if (module.isDisposed()) { + return false; + } + + if (!vFile.isDirectory() && FileUtils.Companion.isFileValidForSonarLint(vFile, module.getProject())) { + filesToAdd.add(vFile); + return true; + } + + return true; + }); + return filesToAdd; + } + + public static List visitAndAddAllFilesForProject(Project project) { + var filesToAdd = new ArrayList(); + var projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex(); + projectFileIndex.iterateContent(vFile -> { + if (project.isDisposed()) { + return false; + } + + if (!vFile.isDirectory() && FileUtils.Companion.isFileValidForSonarLint(vFile, project)) { + filesToAdd.add(vFile); + return true; + } + + return true; + }); + return filesToAdd; + } + + public static List visitAndAddAllChildren(VirtualFile file, Project project) { var filesToAdd = new ArrayList(); VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor<>(NO_FOLLOW_SYMLINKS) { @Override public boolean visitFile(VirtualFile file) { - if (!FileUtils.Companion.isFileValidForSonarLint(file, project)) { + if (!FileUtils.Companion.isFileValidForSonarLintWithExtensiveChecks(file, project)) { return false; } - if (!file.isDirectory() && file.isValid()) { + + if (!file.isDirectory()) { filesToAdd.add(file); } + return !".git".equals(file.getName()); } }); diff --git a/src/test/java/org/sonarlint/intellij/mediumtests/StandaloneModeMediumTests.kt b/src/test/java/org/sonarlint/intellij/mediumtests/StandaloneModeMediumTests.kt index 04c19d733..a92fabd7d 100644 --- a/src/test/java/org/sonarlint/intellij/mediumtests/StandaloneModeMediumTests.kt +++ b/src/test/java/org/sonarlint/intellij/mediumtests/StandaloneModeMediumTests.kt @@ -53,13 +53,12 @@ import org.sonarlint.intellij.core.BackendService import org.sonarlint.intellij.finding.issue.LiveIssue import org.sonarlint.intellij.fs.VirtualFileEvent import org.sonarlint.intellij.trigger.TriggerType -import org.sonarlint.intellij.util.ProjectUtils +import org.sonarlint.intellij.util.SonarLintAppUtils import org.sonarlint.intellij.util.getDocument import org.sonarsource.sonarlint.core.rpc.protocol.common.IssueSeverity import org.sonarsource.sonarlint.core.rpc.protocol.common.RuleType import org.sonarsource.sonarlint.plugin.api.module.file.ModuleFileEvent -@Disabled("Symbolic link check from SLCORE does not work with temp files") class StandaloneModeMediumTests : AbstractSonarLintLightTests() { private val diamondQuickFix = "SonarLint: Replace with <>" @@ -144,7 +143,7 @@ class StandaloneModeMediumTests : AbstractSonarLintLightTests() { } @Test - @Disabled("Error: ENOENT: no such file or directory, scandir '/src'") + @Disabled("Provider \"temp\" not installed") fun should_analyze_js_in_yaml_file() { val fileToAnalyze = sendFileToBackend("src/lambda.yaml") @@ -313,7 +312,7 @@ class StandaloneModeMediumTests : AbstractSonarLintLightTests() { } @Test - @Disabled("Ignored file still analyzed") + @Disabled("Provider \"temp\" not installed") fun should_find_secrets_excluding_vcs_ignored_files() { sendFileToBackend("src/devenv.js") val fileToAnalyzeIgnored = sendFileToBackend("src/devenv_ignored.js") @@ -492,7 +491,7 @@ class StandaloneModeMediumTests : AbstractSonarLintLightTests() { } val onTheFlyFindingsHolder = getService(project, AnalysisSubmitter::class.java).onTheFlyFindingsHolder - val issues = ProjectUtils.getAllFiles(project).toList().map { + val issues = SonarLintAppUtils.visitAndAddAllFilesForProject(project).toList().map { onTheFlyFindingsHolder.getIssuesForFile(it) }.toList().flatten() return issues