Skip to content

Commit

Permalink
SLI-1556 In Rider, all solution's files should be analyzed
Browse files Browse the repository at this point in the history
  • Loading branch information
nquinquenel committed Aug 26, 2024
1 parent 4d6c923 commit ebef455
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 118 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.sonarlint.intellij.common.analysis;

import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.vfs.VirtualFile;
import java.util.Set;

public interface FilesContributor {
// Name is constructed from plugin-id.extension-point-name
ExtensionPointName<FilesContributor> EP_NAME = ExtensionPointName.create("org.sonarlint.idea.filesContributor");

Set<VirtualFile> listFiles(Module module);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.sonarlint.intellij.common.util

import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.GeneratedSourcesFilter.isGeneratedSourceByAnyFilter
import com.intellij.openapi.roots.ProjectFileIndex
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.openapi.vfs.VirtualFile
import org.sonarlint.intellij.common.ui.ReadActionUtils.Companion.computeReadActionSafely
import org.sonarlint.intellij.common.ui.SonarLintConsole

class FileUtils {

companion object {
fun isFileValidForSonarLint(file: VirtualFile, project: Project): Boolean {
try {
val toSkip = computeReadActionSafely(project) {
isGeneratedSourceByAnyFilter(file, project)
|| ProjectFileIndex.getInstance(project).isExcluded(file)
|| ProjectFileIndex.getInstance(project).isInLibrary(file)
|| (!ApplicationManager.getApplication().isUnitTestMode && FileUtilRt.isTooLarge(file.length))
}
return false == toSkip
} catch (e: Exception) {
SonarLintConsole.get(project).error("Error while visiting a file, reason: " + e.message)
return false
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.sonarlint.intellij.rider

import com.intellij.openapi.module.Module
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

class RiderFilesContributor : FilesContributor {

override fun listFiles(module: Module): MutableSet<VirtualFile> {
val filesInContentRoots = mutableSetOf<VirtualFile>()

val visitor = object : ProjectModelEntityVisitor() {
override fun visitProjectFile(entity: ProjectModelEntity): Result {
if (module.isDisposed) {
return Result.Stop
}

if (entity.isProjectFile()) {
entity.getVirtualFileAsContentRoot()?.let {
if (!it.isDirectory && it.isValid && isFileValidForSonarLint(it, module.project)) {
filesInContentRoots.add(it)
}
}
}

return Result.Continue
}
}
visitor.visit(module.project)

return filesInContentRoots
}

}
48 changes: 13 additions & 35 deletions src/main/java/org/sonarlint/intellij/SonarLintIntelliJClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import org.sonarlint.intellij.analysis.AnalysisSubmitter
import org.sonarlint.intellij.analysis.AnalysisSubmitter.collectContributedLanguages
import org.sonarlint.intellij.analysis.OpenInIdeFindingCache
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.SonarLintUtils.getService
Expand Down Expand Up @@ -647,17 +648,7 @@ object SonarLintIntelliJClient : SonarLintRpcClientDelegate {

override fun listFiles(configScopeId: String): List<ClientFileDto> {
val listClientFiles = BackendService.findModule(configScopeId)?.let { module ->
val listModulesFiles = if (isRider()) {
val listFiles = listModuleFilesForRider(module, configScopeId)
computeRiderSharedConfiguration(module.project, configScopeId)?.let {
listFiles.add(it)
}
listFiles
} else {
listModuleFiles(module, configScopeId)
}

listModulesFiles
listModuleFiles(module, configScopeId)
} ?: findProject(configScopeId)?.let { project ->
val listProjectFiles = listProjectFiles(project, configScopeId)

Expand Down Expand Up @@ -701,9 +692,13 @@ object SonarLintIntelliJClient : SonarLintRpcClientDelegate {
private fun listModuleFiles(module: Module, configScopeId: String): MutableList<ClientFileDto> {
val filesInContentRoots = listFilesInContentRoots(module)

FilesContributor.EP_NAME.extensionList.forEach {
filesInContentRoots.addAll(it.listFiles(module))
}

val forcedLanguages = collectContributedLanguages(module, filesInContentRoots)

return filesInContentRoots.mapNotNull { file ->
val clientFiles = filesInContentRoots.mapNotNull { file ->
val forcedLanguage = forcedLanguages[file]?.let { fl -> Language.valueOf(fl.name) }
getRelativePathForAnalysis(module, file)?.let { relativePath ->
toClientFileDto(
Expand All @@ -715,31 +710,14 @@ object SonarLintIntelliJClient : SonarLintRpcClientDelegate {
)
}
}.toMutableList()
}

private fun listModuleFilesForRider(module: Module, configScopeId: String): MutableList<ClientFileDto> {
val filesInContentRoots = mutableSetOf<VirtualFile>()
module.project.guessProjectDir()?.children?.forEach { contentRoot ->
if (module.isDisposed) {
return@forEach
if (isRider()) {
computeRiderSharedConfiguration(module.project, configScopeId)?.let {
clientFiles.add(it)
}
filesInContentRoots.addAll(visitAndAddFiles(contentRoot, module))
}

val forcedLanguages = collectContributedLanguages(module, filesInContentRoots)

return filesInContentRoots.mapNotNull { file ->
val forcedLanguage = forcedLanguages[file]?.let { fl -> Language.valueOf(fl.name) }
getRelativePathForAnalysis(module, file)?.let { relativePath ->
toClientFileDto(
module.project,
configScopeId,
file,
relativePath,
forcedLanguage
)
}
}.toMutableList()
return clientFiles
}

private fun listProjectFiles(project: Project, configScopeId: String): MutableList<ClientFileDto> {
Expand Down Expand Up @@ -789,15 +767,15 @@ object SonarLintIntelliJClient : SonarLintRpcClientDelegate {

private fun listFilesInContentRoots(
module: Module,
): Set<VirtualFile> {
): MutableSet<VirtualFile> {
val files = mutableListOf<VirtualFile>()
ModuleRootManager.getInstance(module).contentRoots.forEach { contentRoot ->
if (module.isDisposed) {
return@forEach
}
files.addAll(visitAndAddFiles(contentRoot, module))
}
return files.toSet()
return files.toMutableSet()
}

// useful for Rider where the files to find are not located in content roots
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectLocator
import com.intellij.openapi.vfs.VirtualFile
import java.time.Duration
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.isFileValidForSonarLint
import org.sonarsource.sonarlint.plugin.api.module.file.ModuleFileEvent

const val DEBOUNCE_DELAY_MS = 1000L
Expand Down Expand Up @@ -79,7 +79,7 @@ class EditorFileChangeListener : BulkAwareDocumentListener.Simple, Disposable {
val filesToSendPerModule = HashMap<Module, MutableList<VirtualFileEvent>>()

changedFiles
.filter { it.isValid && isFileValidForSonarLint(it, project) }
.filter { it.isValid && FileUtils.Companion.isFileValidForSonarLint(it, project) }
.forEach { file ->
val module = SonarLintAppUtils.findModuleForFile(file, project) ?: return@forEach
filesToSendPerModule.computeIfAbsent(module) { mutableListOf() }.add(VirtualFileEvent(ModuleFileEvent.Type.MODIFIED, file))
Expand All @@ -94,4 +94,4 @@ class EditorFileChangeListener : BulkAwareDocumentListener.Simple, Disposable {
changedFiles.clear()
triggerAlarm.shutdown()
}
}
}
61 changes: 0 additions & 61 deletions src/main/java/org/sonarlint/intellij/util/FileUtils.kt

This file was deleted.

20 changes: 2 additions & 18 deletions src/main/java/org/sonarlint/intellij/util/SonarLintAppUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@
package org.sonarlint.intellij.util;


import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectLocator;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
Expand All @@ -40,9 +38,8 @@
import java.util.List;
import javax.annotation.CheckForNull;
import org.jetbrains.annotations.Nullable;
import org.sonarlint.intellij.common.ui.SonarLintConsole;
import org.sonarlint.intellij.common.util.FileUtils;

import static com.intellij.openapi.roots.GeneratedSourcesFilter.isGeneratedSourceByAnyFilter;
import static com.intellij.openapi.vfs.VirtualFileVisitor.NO_FOLLOW_SYMLINKS;
import static org.sonarlint.intellij.common.ui.ReadActionUtils.computeReadActionSafely;

Expand Down Expand Up @@ -168,7 +165,7 @@ public static List<VirtualFile> visitAndAddFiles(VirtualFile file, Module module
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor<>(NO_FOLLOW_SYMLINKS) {
@Override
public boolean visitFile(VirtualFile file) {
if (!isFileValidForSonarLint(file, module.getProject())) {
if (!FileUtils.Companion.isFileValidForSonarLint(file, module.getProject())) {
return false;
}
if (!file.isDirectory() && file.isValid()) {
Expand All @@ -180,19 +177,6 @@ public boolean visitFile(VirtualFile file) {
return filesToAdd;
}

public static boolean isFileValidForSonarLint(VirtualFile file, Project project) {
try {
var toSkip = computeReadActionSafely(project, () -> isGeneratedSourceByAnyFilter(file, project)
|| ProjectFileIndex.getInstance(project).isExcluded(file)
|| ProjectFileIndex.getInstance(project).isInLibrary(file)
|| (!ApplicationManager.getApplication().isUnitTestMode() && FileUtilRt.isTooLarge(file.getLength())));
return Boolean.FALSE == toSkip;
} catch (Exception e) {
SonarLintConsole.get(project).error("Error while visiting a file, reason: " + e.getMessage());
return false;
}
}

@CheckForNull
private static String getPathRelativeToContentRoot(Module module, VirtualFile file) {
var moduleRootManager = ModuleRootManager.getInstance(module);
Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/META-INF/plugin-rider.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
-->
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
<idea-plugin>
<extensions defaultExtensionNs="org.sonarlint.idea">
<analysisConfiguration implementation="org.sonarlint.intellij.rider.RiderAnalysisConfigurator"/>
<filesContributor implementation="org.sonarlint.intellij.rider.RiderFilesContributor"/>
</extensions>
</idea-plugin>
1 change: 1 addition & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@
<extensionPoints>
<extensionPoint name="analysisConfiguration" interface="org.sonarlint.intellij.common.analysis.AnalysisConfigurator" dynamic="true"/>
<extensionPoint name="fileExclusionContributor" interface="org.sonarlint.intellij.common.analysis.FileExclusionContributor" dynamic="true"/>
<extensionPoint name="filesContributor" interface="org.sonarlint.intellij.common.analysis.FilesContributor" dynamic="true"/>
<extensionPoint name="vcsProvider" interface="org.sonarlint.intellij.common.vcs.ModuleVcsRepoProvider" dynamic="true"/>
</extensionPoints>

Expand Down

0 comments on commit ebef455

Please sign in to comment.