From b3e51833cc8c2e7c7bfe6d9347f0f01b9806c290 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Mon, 8 Feb 2021 11:25:26 -0800 Subject: [PATCH 1/2] Implement GetDocumentDiagnosticsAsync in CodeFix DiagnosticProvider --- src/Analyzers/SolutionCodeFixApplier.cs | 5 +- .../ThirdPartyAnalyzerFormatterTests.cs | 46 +++++++++++++++++++ .../analyzer_project/NuGet.config | 8 ++++ .../analyzer_project/analyzer_project.csproj | 1 + 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 tests/projects/for_analyzer_formatter/analyzer_project/NuGet.config diff --git a/src/Analyzers/SolutionCodeFixApplier.cs b/src/Analyzers/SolutionCodeFixApplier.cs index 0f565c0324..c9ae6bfa6b 100644 --- a/src/Analyzers/SolutionCodeFixApplier.cs +++ b/src/Analyzers/SolutionCodeFixApplier.cs @@ -109,9 +109,10 @@ public override Task> GetAllDiagnosticsAsync(Project pro return GetProjectDiagnosticsAsync(project, cancellationToken); } - public override Task> GetDocumentDiagnosticsAsync(Document document, CancellationToken cancellationToken) + public override async Task> GetDocumentDiagnosticsAsync(Document document, CancellationToken cancellationToken) { - throw new NotImplementedException(); + var projectDiagnostics = await GetProjectDiagnosticsAsync(document.Project, cancellationToken); + return projectDiagnostics.Where(diagnostic => diagnostic.Location.SourceTree?.FilePath == document.FilePath).ToImmutableArray(); } public override Task> GetProjectDiagnosticsAsync(Project project, CancellationToken cancellationToken) diff --git a/tests/Analyzers/ThirdPartyAnalyzerFormatterTests.cs b/tests/Analyzers/ThirdPartyAnalyzerFormatterTests.cs index 7893f46d03..3d463bd730 100644 --- a/tests/Analyzers/ThirdPartyAnalyzerFormatterTests.cs +++ b/tests/Analyzers/ThirdPartyAnalyzerFormatterTests.cs @@ -118,5 +118,51 @@ void M() await AssertCodeChangedAsync(testCode, expectedCode, editorConfig, fixCategory: FixCategory.Analyzers, analyzerReferences: analyzerReferences); } + + [Fact] + public async Task TestIDisposableAnalyzer_Loads() + { + var analyzerReferences = GetAnalyzerReferences("IDisposable"); + + var testCode = @" +using System.IO; + +class C +{ + void M() + { + var stream = File.OpenRead(string.Empty); + var b = stream.ReadByte(); + stream.Dispose(); + } +} +"; + + var expectedCode = @" +using System.IO; + +class C +{ + void M() + { + using (var stream = File.OpenRead(string.Empty)) + { + var b = stream.ReadByte(); + } + } +} +"; + + var editorConfig = new Dictionary() + { + // Turn off all diagnostics analyzers + ["dotnet_analyzer_diagnostic.severity"] = "none", + + // Prefer using. IDISP017 + ["dotnet_diagnostic.IDISP017.severity"] = "error", + }; + + await AssertCodeChangedAsync(testCode, expectedCode, editorConfig, fixCategory: FixCategory.Analyzers, analyzerReferences: analyzerReferences); + } } } diff --git a/tests/projects/for_analyzer_formatter/analyzer_project/NuGet.config b/tests/projects/for_analyzer_formatter/analyzer_project/NuGet.config new file mode 100644 index 0000000000..b7fb18432b --- /dev/null +++ b/tests/projects/for_analyzer_formatter/analyzer_project/NuGet.config @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/projects/for_analyzer_formatter/analyzer_project/analyzer_project.csproj b/tests/projects/for_analyzer_formatter/analyzer_project/analyzer_project.csproj index 5f0d40f60c..b106a32018 100644 --- a/tests/projects/for_analyzer_formatter/analyzer_project/analyzer_project.csproj +++ b/tests/projects/for_analyzer_formatter/analyzer_project/analyzer_project.csproj @@ -9,6 +9,7 @@ all runtime; build; native; contentfiles; analyzers + From 5a6bf2d9e92c5a7342006b0a041a04788ad153b6 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Mon, 8 Feb 2021 12:00:03 -0800 Subject: [PATCH 2/2] Isolate each Analyzer assembly by loading into its own context. --- .../AnalyzerReferenceInformationProvider.cs | 4 +- .../ThirdPartyAnalyzerFormatterTests.cs | 49 ++++++++++++++++++- .../analyzer_project/analyzer_project.csproj | 1 + 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/Analyzers/AnalyzerReferenceInformationProvider.cs b/src/Analyzers/AnalyzerReferenceInformationProvider.cs index eaae51abed..9ab076289d 100644 --- a/src/Analyzers/AnalyzerReferenceInformationProvider.cs +++ b/src/Analyzers/AnalyzerReferenceInformationProvider.cs @@ -23,10 +23,8 @@ internal class AnalyzerReferenceInformationProvider : IAnalyzerInformationProvid private AnalyzersAndFixers GetAnalyzersAndFixers(Project project) { - var context = new AnalyzerLoadContext(); - var analyzerAssemblies = project.AnalyzerReferences - .Select(reference => TryLoadAssemblyFrom(reference.FullPath, context)) + .Select(reference => TryLoadAssemblyFrom(reference.FullPath, new AnalyzerLoadContext())) .OfType() .ToImmutableArray(); diff --git a/tests/Analyzers/ThirdPartyAnalyzerFormatterTests.cs b/tests/Analyzers/ThirdPartyAnalyzerFormatterTests.cs index 3d463bd730..f430e9d6af 100644 --- a/tests/Analyzers/ThirdPartyAnalyzerFormatterTests.cs +++ b/tests/Analyzers/ThirdPartyAnalyzerFormatterTests.cs @@ -120,7 +120,7 @@ void M() } [Fact] - public async Task TestIDisposableAnalyzer_Loads() + public async Task TestIDisposableAnalyzer_AddsUsing() { var analyzerReferences = GetAnalyzerReferences("IDisposable"); @@ -141,6 +141,53 @@ void M() var expectedCode = @" using System.IO; +class C +{ + void M() + { + using (var stream = File.OpenRead(string.Empty)) + { + var b = stream.ReadByte(); + } + } +} +"; + + var editorConfig = new Dictionary() + { + // Turn off all diagnostics analyzers + ["dotnet_analyzer_diagnostic.severity"] = "none", + + // Prefer using. IDISP017 + ["dotnet_diagnostic.IDISP017.severity"] = "error", + }; + + await AssertCodeChangedAsync(testCode, expectedCode, editorConfig, fixCategory: FixCategory.Analyzers, analyzerReferences: analyzerReferences); + } + + [Fact] + public async Task TestLoadingAllAnalyzers_LoadsDependenciesFromAllSearchPaths() + { + // Loads all analyzer references. + var analyzerReferences = _analyzerReferencesProject.AnalyzerReferences; + + var testCode = @" +using System.IO; + +class C +{ + void M() + { + var stream = File.OpenRead(string.Empty); + var b = stream.ReadByte(); + stream.Dispose(); + } +} +"; + + var expectedCode = @" +using System.IO; + class C { void M() diff --git a/tests/projects/for_analyzer_formatter/analyzer_project/analyzer_project.csproj b/tests/projects/for_analyzer_formatter/analyzer_project/analyzer_project.csproj index b106a32018..ad9d39ed6d 100644 --- a/tests/projects/for_analyzer_formatter/analyzer_project/analyzer_project.csproj +++ b/tests/projects/for_analyzer_formatter/analyzer_project/analyzer_project.csproj @@ -9,6 +9,7 @@ all runtime; build; native; contentfiles; analyzers +