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 29, 2024
1 parent 27ae7fd commit 9efa53b
Show file tree
Hide file tree
Showing 17 changed files with 274 additions and 124 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* SonarLint for IntelliJ IDEA
* Copyright (C) 2015-2024 SonarSource
* [email protected]
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
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,50 @@
/*
* SonarLint for IntelliJ IDEA
* Copyright (C) 2015-2024 SonarSource
* [email protected]
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
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
}
}
}

}
6 changes: 6 additions & 0 deletions its/projects/sample-complex-rider/mainFolder/folder1/file1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace NewCADServer
{
public class file1
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "folder1", "folder1\folder1.csproj", "{88EC1BA3-5635-4166-AC4A-9FB6F9B5DB0D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "folder2", "..\mainFolder2\folder2\folder2.csproj", "{244D7F07-F814-4F2E-A54C-8229B8E9ECA9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{88EC1BA3-5635-4166-AC4A-9FB6F9B5DB0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{88EC1BA3-5635-4166-AC4A-9FB6F9B5DB0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88EC1BA3-5635-4166-AC4A-9FB6F9B5DB0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88EC1BA3-5635-4166-AC4A-9FB6F9B5DB0D}.Release|Any CPU.Build.0 = Release|Any CPU
{244D7F07-F814-4F2E-A54C-8229B8E9ECA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{244D7F07-F814-4F2E-A54C-8229B8E9ECA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{244D7F07-F814-4F2E-A54C-8229B8E9ECA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{244D7F07-F814-4F2E-A54C-8229B8E9ECA9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace ClassLibraryFromExternalDirectory
{
public class file2
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class CurrentFileTabTests {
content("CurrentFilePanel") {
expectedMessages.forEach {
// the synchronization can take a while to happen
waitFor(duration = Duration.ofMinutes(1)) {
waitFor(duration = Duration.ofSeconds(30)) {
hasText(it)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.sonarlint.intellij.its.BaseUiTest
import org.sonarlint.intellij.its.tests.domain.CurrentFileTabTests.Companion.verifyCurrentFileTabContainsMessages
import org.sonarlint.intellij.its.utils.OpeningUtils.Companion.openExistingProject
import org.sonarlint.intellij.its.utils.OpeningUtils.Companion.openFile
import org.sonarlint.intellij.its.utils.OpeningUtils.Companion.openFileViaMenu

@EnabledIf("isRider")
class RiderTests : BaseUiTest() {
Expand All @@ -42,4 +43,27 @@ class RiderTests : BaseUiTest() {
)
}

@Test
fun should_analyze_complex_csharp() = uiTest {
openExistingProject("sample-complex-rider")

openFile("folder1/file1.cs")

verifyCurrentFileTabContainsMessages(
"Found 2 issues in 1 file",
"file1.cs",
"Remove this empty class, write its code or make it an \"interface\".",
"Rename class 'file1' to match pascal case naming rules, consider using 'File1'."
)

openFileViaMenu("file2.cs")

verifyCurrentFileTabContainsMessages(
"Found 2 issues in 1 file",
"file2.cs",
"Remove this empty class, write its code or make it an \"interface\".",
"Rename class 'file2' to match pascal case naming rules, consider using 'File2'."
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
*/
package org.sonarlint.intellij.its.utils

import com.intellij.remoterobot.utils.waitFor
import com.intellij.remoterobot.fixtures.JListFixture
import com.intellij.remoterobot.utils.keyboard
import java.awt.Point
import java.io.File
import java.time.Duration
import org.sonarlint.intellij.its.BaseUiTest.Companion.isRider
import org.sonarlint.intellij.its.BaseUiTest.Companion.remoteRobot
import org.sonarlint.intellij.its.fixtures.dialog
import org.sonarlint.intellij.its.fixtures.editor
import org.sonarlint.intellij.its.fixtures.idea
import org.sonarlint.intellij.its.fixtures.isCLion
import org.sonarlint.intellij.its.fixtures.isRider
Expand All @@ -46,14 +46,31 @@ class OpeningUtils {
const file = component.project.getBaseDir().findFileByRelativePath("$filePath");
if (file) {
const openDescriptor = new com.intellij.openapi.fileEditor.OpenFileDescriptor(component.project, file);
com.intellij.openapi.application.ApplicationManager.getApplication().invokeLater(() => openDescriptor.navigate(true));
com.intellij.openapi.application.ApplicationManager.getApplication().invokeLater(() => openDescriptor.navigateInEditor(component.project, true));
}
else {
throw "Cannot open file '" + $filePath +"': not found";
}
""", false
""", true
)
waitFor(Duration.ofSeconds(10)) { editor(fileName).isShowing }
waitBackgroundTasksFinished()
}
}
}

fun openFileViaMenu(fileName: String) {
with(remoteRobot) {
idea {
actionMenu("Navigate") {
open()
item("File...") {
click()
}
keyboard {
enterText(fileName)
enter()
}
}
waitBackgroundTasksFinished()
}
}
Expand Down Expand Up @@ -85,6 +102,16 @@ class OpeningUtils {
}
}
}
if (remoteRobot.isRider()) {
optionalStep {
dialog("Select a Solution to Open") {
jList(JListFixture.byType()) {
clickItemAtIndex(0)
button("Open").click()
}
}
}
}
idea {
waitBackgroundTasksFinished()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* SonarLint for IntelliJ IDEA
* Copyright (C) 2015-2024 SonarSource
* [email protected]
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
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

class RiderFilesContributor : FilesContributor {

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

// 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
}

private fun listFilesInSolution(module: Module): Set<VirtualFile> {
val filesInSolution = 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)) {
filesInSolution.add(it)
}
}
}

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

}
Loading

0 comments on commit 9efa53b

Please sign in to comment.