diff --git a/build.json b/build.json index a3423f9d5d..633b5dd7f0 100644 --- a/build.json +++ b/build.json @@ -49,7 +49,8 @@ "NetCore31Project", "Net50Project", "ProjectWithAnalyzersAndEditorConfig", - "ProjectWithParentEditorConfig" + "ProjectWithParentEditorConfig", + "TwoProjectsWithAnalyzerSuppressor" ], "CakeTestAssets": [ "CakeProject" diff --git a/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs b/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs index 23f9297353..31ec749afd 100644 --- a/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs +++ b/src/OmniSharp.Roslyn.CSharp/Workers/Diagnostics/CSharpDiagnosticWorkerWithAnalyzers.cs @@ -291,6 +291,7 @@ private async Task> AnalyzeDocument(Project project, diagnostics = semanticDiagnosticsWithAnalyzers .Concat(syntaxDiagnosticsWithAnalyzers) + .Where(d => !d.IsSuppressed) .Concat(documentSemanticModel.GetDiagnostics()) .ToImmutableArray(); } diff --git a/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/App/App.csproj b/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/App/App.csproj new file mode 100644 index 0000000000..5757a5c6b8 --- /dev/null +++ b/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/App/App.csproj @@ -0,0 +1,23 @@ + + + Exe + netcoreapp3.1 + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + false + Analyzer + + + + + diff --git a/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/App/Program.cs b/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/App/Program.cs new file mode 100644 index 0000000000..be4278310c --- /dev/null +++ b/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/App/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace App +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/Lib/Class1.cs b/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/Lib/Class1.cs new file mode 100644 index 0000000000..10789ed6e2 --- /dev/null +++ b/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/Lib/Class1.cs @@ -0,0 +1,23 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using System.Collections.Immutable; + +namespace Lib +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class MySuppressor : DiagnosticSuppressor + { + public override ImmutableArray SupportedSuppressions { get; } = new[] + { + new SuppressionDescriptor("SUPP3662", "SA1200", "Dummy suppression") + }.ToImmutableArray(); + + public override void ReportSuppressions(SuppressionAnalysisContext context) + { + foreach (Diagnostic diagnostic in context.ReportedDiagnostics) + { + context.ReportSuppression(Suppression.Create(SupportedSuppressions[0], diagnostic)); + } + } + } +} diff --git a/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/Lib/Lib.csproj b/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/Lib/Lib.csproj new file mode 100644 index 0000000000..529fad1e77 --- /dev/null +++ b/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/Lib/Lib.csproj @@ -0,0 +1,11 @@ + + + + netstandard2.0 + + + + + + + diff --git a/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/TwoProjectsWithAnalyzerSuppressor.sln b/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/TwoProjectsWithAnalyzerSuppressor.sln new file mode 100644 index 0000000000..89113c0870 --- /dev/null +++ b/test-assets/test-projects/TwoProjectsWithAnalyzerSuppressor/TwoProjectsWithAnalyzerSuppressor.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib", "Lib\Lib.csproj", "{7120F661-4FCB-4D55-921F-6FBFC3746443}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "App\App.csproj", "{8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7120F661-4FCB-4D55-921F-6FBFC3746443}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7120F661-4FCB-4D55-921F-6FBFC3746443}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7120F661-4FCB-4D55-921F-6FBFC3746443}.Debug|x64.ActiveCfg = Debug|Any CPU + {7120F661-4FCB-4D55-921F-6FBFC3746443}.Debug|x64.Build.0 = Debug|Any CPU + {7120F661-4FCB-4D55-921F-6FBFC3746443}.Debug|x86.ActiveCfg = Debug|Any CPU + {7120F661-4FCB-4D55-921F-6FBFC3746443}.Debug|x86.Build.0 = Debug|Any CPU + {7120F661-4FCB-4D55-921F-6FBFC3746443}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7120F661-4FCB-4D55-921F-6FBFC3746443}.Release|Any CPU.Build.0 = Release|Any CPU + {7120F661-4FCB-4D55-921F-6FBFC3746443}.Release|x64.ActiveCfg = Release|Any CPU + {7120F661-4FCB-4D55-921F-6FBFC3746443}.Release|x64.Build.0 = Release|Any CPU + {7120F661-4FCB-4D55-921F-6FBFC3746443}.Release|x86.ActiveCfg = Release|Any CPU + {7120F661-4FCB-4D55-921F-6FBFC3746443}.Release|x86.Build.0 = Release|Any CPU + {8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}.Debug|x64.ActiveCfg = Debug|Any CPU + {8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}.Debug|x64.Build.0 = Debug|Any CPU + {8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}.Debug|x86.ActiveCfg = Debug|Any CPU + {8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}.Debug|x86.Build.0 = Debug|Any CPU + {8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}.Release|Any CPU.Build.0 = Release|Any CPU + {8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}.Release|x64.ActiveCfg = Release|Any CPU + {8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}.Release|x64.Build.0 = Release|Any CPU + {8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}.Release|x86.ActiveCfg = Release|Any CPU + {8CC04E3C-AF7D-40F1-BEB4-BACF30A895C2}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/tests/OmniSharp.MSBuild.Tests/ProjectWithAnalyzersTests.cs b/tests/OmniSharp.MSBuild.Tests/ProjectWithAnalyzersTests.cs index 187ca7b789..39a59508c1 100644 --- a/tests/OmniSharp.MSBuild.Tests/ProjectWithAnalyzersTests.cs +++ b/tests/OmniSharp.MSBuild.Tests/ProjectWithAnalyzersTests.cs @@ -302,6 +302,32 @@ public async Task WhenNewAnalyzerReferenceIsAdded_ThenAutomaticallyUseItWithoutR } } + [Fact] + public async Task WhenProjectIsLoadedThenItRespectsDiagnosticSuppressors() + { + using (var testProject = await TestAssets.Instance.GetTestProjectAsync("TwoProjectsWithAnalyzerSuppressor")) + using (var host = CreateMSBuildTestHost(testProject.Directory, configurationData: TestHelpers.GetConfigurationDataWithAnalyzerConfig(roslynAnalyzersEnabled: true))) + { + var project = host.Workspace.CurrentSolution.Projects.First(p => p.Name == "App"); + + // by default Stylecop reported diagnostics should be: + // - The file header is missing or not located at the top of the file. [App] SA1633 + // - Elements should be documented [App] SA1600 + // - Element 'Program' should declare an access modifier [App] SA1400 + // - Element 'Main' should declare an access modifier [App] SA1400 + // However, SA1200 should be suppressed + + var diagnostics = await host.RequestCodeCheckAsync(Path.Combine(testProject.Directory, "App", "Program.cs")); + + Assert.NotEmpty(diagnostics.QuickFixes); + + Assert.Contains(diagnostics.QuickFixes.OfType(), x => x.Id == "SA1633" && x.LogLevel == "Warning"); + Assert.Contains(diagnostics.QuickFixes.OfType(), x => x.Id == "SA1600" && x.LogLevel == "Warning"); + Assert.Contains(diagnostics.QuickFixes.OfType(), x => x.Id == "SA1400" && x.LogLevel == "Warning"); + Assert.DoesNotContain(diagnostics.QuickFixes.OfType(), x => x.Id == "SA1200"); + } + } + private string ModifyXmlFileInPlace(string file, Action docUpdateAction) { var xmlFile = XDocument.Load(file);