Skip to content

Commit 39948d9

Browse files
committed
Improve Fix All accuracy in Roslyn 1.1
1 parent 04c27a3 commit 39948d9

1 file changed

Lines changed: 39 additions & 1 deletion

File tree

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/Helpers/FixAllContextHelper.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace StyleCop.Analyzers.Helpers
55
{
66
using System;
77
using System.Collections.Concurrent;
8+
using System.Collections.Generic;
89
using System.Collections.Immutable;
910
using System.Linq;
1011
using System.Reflection;
@@ -13,11 +14,29 @@ namespace StyleCop.Analyzers.Helpers
1314
using Microsoft.CodeAnalysis;
1415
using Microsoft.CodeAnalysis.CodeFixes;
1516
using Microsoft.CodeAnalysis.Diagnostics;
17+
using Microsoft.CodeAnalysis.Text;
1618

1719
internal static class FixAllContextHelper
1820
{
1921
private static readonly ImmutableDictionary<string, ImmutableArray<Type>> DiagnosticAnalyzers = GetAllAnalyzers();
2022

23+
private static readonly Func<CompilationWithAnalyzers, SyntaxTree, CancellationToken, Task<ImmutableArray<Diagnostic>>> GetAnalyzerSyntaxDiagnosticsAsync;
24+
private static readonly Func<CompilationWithAnalyzers, SemanticModel, TextSpan?, CancellationToken, Task<ImmutableArray<Diagnostic>>> GetAnalyzerSemanticDiagnosticsAsync;
25+
26+
static FixAllContextHelper()
27+
{
28+
Version roslynVersion = typeof(AdditionalText).GetTypeInfo().Assembly.GetName().Version;
29+
bool avoidGetAnalyzerDiagnosticsAsync = roslynVersion >= new Version(1, 1, 0, 0) && roslynVersion < new Version(1, 2, 0, 0);
30+
if (avoidGetAnalyzerDiagnosticsAsync)
31+
{
32+
var methodInfo = typeof(CompilationWithAnalyzers).GetRuntimeMethod(nameof(GetAnalyzerSyntaxDiagnosticsAsync), new[] { typeof(SyntaxTree), typeof(CancellationToken) });
33+
GetAnalyzerSyntaxDiagnosticsAsync = (Func<CompilationWithAnalyzers, SyntaxTree, CancellationToken, Task<ImmutableArray<Diagnostic>>>)methodInfo?.CreateDelegate(typeof(Func<CompilationWithAnalyzers, SyntaxTree, CancellationToken, Task<ImmutableArray<Diagnostic>>>));
34+
35+
methodInfo = typeof(CompilationWithAnalyzers).GetRuntimeMethod(nameof(GetAnalyzerSemanticDiagnosticsAsync), new[] { typeof(SemanticModel), typeof(TextSpan?), typeof(CancellationToken) });
36+
GetAnalyzerSemanticDiagnosticsAsync = (Func<CompilationWithAnalyzers, SemanticModel, TextSpan?, CancellationToken, Task<ImmutableArray<Diagnostic>>>)methodInfo?.CreateDelegate(typeof(Func<CompilationWithAnalyzers, SemanticModel, TextSpan?, CancellationToken, Task<ImmutableArray<Diagnostic>>>));
37+
}
38+
}
39+
2140
public static async Task<ImmutableDictionary<Document, ImmutableArray<Diagnostic>>> GetDocumentDiagnosticsToFixAsync(FixAllContext fixAllContext)
2241
{
2342
var allDiagnostics = ImmutableArray<Diagnostic>.Empty;
@@ -161,7 +180,26 @@ private static async Task<ImmutableArray<Diagnostic>> GetAllDiagnosticsAsync(Fix
161180
if (analyzers.Any())
162181
{
163182
var compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, project.AnalyzerOptions, fixAllContext.CancellationToken);
164-
diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false);
183+
if (GetAnalyzerSyntaxDiagnosticsAsync != null && GetAnalyzerSemanticDiagnosticsAsync != null)
184+
{
185+
// This whole block is workaround code for issues with Roslyn 1.1...
186+
compilationWithAnalyzers.Compilation.GetDeclarationDiagnostics(fixAllContext.CancellationToken);
187+
188+
foreach (var document in project.Documents)
189+
{
190+
var syntaxTree = await document.GetSyntaxTreeAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
191+
var syntaxDiagnostics = await GetAnalyzerSyntaxDiagnosticsAsync(compilationWithAnalyzers, syntaxTree, fixAllContext.CancellationToken).ConfigureAwait(false);
192+
diagnostics = diagnostics.AddRange(syntaxDiagnostics);
193+
194+
var semanticModel = await document.GetSemanticModelAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
195+
var semanticDiagnostics = await GetAnalyzerSemanticDiagnosticsAsync(compilationWithAnalyzers, semanticModel, default(TextSpan?), fixAllContext.CancellationToken).ConfigureAwait(false);
196+
diagnostics = diagnostics.AddRange(semanticDiagnostics);
197+
}
198+
}
199+
else
200+
{
201+
diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false);
202+
}
165203
}
166204

167205
if (includeCompilerDiagnostics)

0 commit comments

Comments
 (0)