From 39948d9d5d574a4bd00a393ffafb3c3eed571787 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Wed, 23 Dec 2015 06:40:49 -0600 Subject: [PATCH] Improve Fix All accuracy in Roslyn 1.1 --- .../Helpers/FixAllContextHelper.cs | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/Helpers/FixAllContextHelper.cs b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/Helpers/FixAllContextHelper.cs index b59234d35..3bee14013 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/Helpers/FixAllContextHelper.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/Helpers/FixAllContextHelper.cs @@ -5,6 +5,7 @@ namespace StyleCop.Analyzers.Helpers { using System; using System.Collections.Concurrent; + using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Reflection; @@ -13,11 +14,29 @@ namespace StyleCop.Analyzers.Helpers using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; + using Microsoft.CodeAnalysis.Text; internal static class FixAllContextHelper { private static readonly ImmutableDictionary> DiagnosticAnalyzers = GetAllAnalyzers(); + private static readonly Func>> GetAnalyzerSyntaxDiagnosticsAsync; + private static readonly Func>> GetAnalyzerSemanticDiagnosticsAsync; + + static FixAllContextHelper() + { + Version roslynVersion = typeof(AdditionalText).GetTypeInfo().Assembly.GetName().Version; + bool avoidGetAnalyzerDiagnosticsAsync = roslynVersion >= new Version(1, 1, 0, 0) && roslynVersion < new Version(1, 2, 0, 0); + if (avoidGetAnalyzerDiagnosticsAsync) + { + var methodInfo = typeof(CompilationWithAnalyzers).GetRuntimeMethod(nameof(GetAnalyzerSyntaxDiagnosticsAsync), new[] { typeof(SyntaxTree), typeof(CancellationToken) }); + GetAnalyzerSyntaxDiagnosticsAsync = (Func>>)methodInfo?.CreateDelegate(typeof(Func>>)); + + methodInfo = typeof(CompilationWithAnalyzers).GetRuntimeMethod(nameof(GetAnalyzerSemanticDiagnosticsAsync), new[] { typeof(SemanticModel), typeof(TextSpan?), typeof(CancellationToken) }); + GetAnalyzerSemanticDiagnosticsAsync = (Func>>)methodInfo?.CreateDelegate(typeof(Func>>)); + } + } + public static async Task>> GetDocumentDiagnosticsToFixAsync(FixAllContext fixAllContext) { var allDiagnostics = ImmutableArray.Empty; @@ -161,7 +180,26 @@ private static async Task> GetAllDiagnosticsAsync(Fix if (analyzers.Any()) { var compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, project.AnalyzerOptions, fixAllContext.CancellationToken); - diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false); + if (GetAnalyzerSyntaxDiagnosticsAsync != null && GetAnalyzerSemanticDiagnosticsAsync != null) + { + // This whole block is workaround code for issues with Roslyn 1.1... + compilationWithAnalyzers.Compilation.GetDeclarationDiagnostics(fixAllContext.CancellationToken); + + foreach (var document in project.Documents) + { + var syntaxTree = await document.GetSyntaxTreeAsync(fixAllContext.CancellationToken).ConfigureAwait(false); + var syntaxDiagnostics = await GetAnalyzerSyntaxDiagnosticsAsync(compilationWithAnalyzers, syntaxTree, fixAllContext.CancellationToken).ConfigureAwait(false); + diagnostics = diagnostics.AddRange(syntaxDiagnostics); + + var semanticModel = await document.GetSemanticModelAsync(fixAllContext.CancellationToken).ConfigureAwait(false); + var semanticDiagnostics = await GetAnalyzerSemanticDiagnosticsAsync(compilationWithAnalyzers, semanticModel, default(TextSpan?), fixAllContext.CancellationToken).ConfigureAwait(false); + diagnostics = diagnostics.AddRange(semanticDiagnostics); + } + } + else + { + diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false); + } } if (includeCompilerDiagnostics)