private async Task <FixResult> FixDiagnosticsAsync( string diagnosticId, Project project, ImmutableArray <DiagnosticAnalyzer> analyzers, ImmutableArray <CodeFixProvider> fixers, CancellationToken cancellationToken) { ImmutableArray <Diagnostic> previousDiagnostics = ImmutableArray <Diagnostic> .Empty; while (true) { Compilation compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); if (!VerifyCompilerDiagnostics(compilation, cancellationToken)) { return(FixResult.CompilerError); } var compilationWithAnalyzers = new CompilationWithAnalyzers(compilation, analyzers, DefaultCompilationWithAnalyzersOptions); ImmutableArray <Diagnostic> diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false); diagnostics = diagnostics .Where(f => f.Id == diagnosticId && f.Severity != DiagnosticSeverity.Hidden) .ToImmutableArray(); int length = diagnostics.Length; if (length == 0) { return(FixResult.Success); } if (length == previousDiagnostics.Length && !diagnostics.Except(previousDiagnostics, DiagnosticDeepEqualityComparer.Instance).Any()) { break; } previousDiagnostics = diagnostics; if (Options.BatchSize > 0 && length > Options.BatchSize) { diagnostics = ImmutableArray.CreateRange(diagnostics, 0, Options.BatchSize, f => f); } await FixDiagnosticsAsync(diagnosticId, project, diagnostics, fixers, cancellationToken).ConfigureAwait(false); if (Options.BatchSize <= 0 || length <= Options.BatchSize) { break; } project = CurrentSolution.GetProject(project.Id); } return(FixResult.Success); }
private ImmutableArray <Diagnostic> GetDiagnosticsForDocument([NotNull] Document document) { ImmutableArray <DiagnosticAnalyzer> analyzers = ImmutableArray.Create(CreateAnalyzer()); Compilation compilation = document.Project.GetCompilationAsync().Result; CompilationWithAnalyzers compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, cancellationToken: CancellationToken.None); ImmutableArray <Diagnostic> compilerDiagnostics = compilation.GetDiagnostics(CancellationToken.None); ValidateCompilerDiagnostics(compilerDiagnostics); SyntaxTree tree = document.GetSyntaxTreeAsync().Result; ImmutableArray <Diagnostic> .Builder builder = ImmutableArray.CreateBuilder <Diagnostic>(); foreach (Diagnostic analyzerDiagnostic in compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result) { Location location = analyzerDiagnostic.Location; if (location.IsInSource && location.SourceTree == tree) { builder.Add(analyzerDiagnostic); } } return(builder.ToImmutable()); }
private ImmutableArray <Diagnostic> GetDiagnostics(string filePath, string csharpSource) { SyntaxTree tree = CSharpSyntaxTree.ParseText(csharpSource, path: filePath); CSharpCompilation compilation = CSharpCompilation.Create("target") .AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)) .AddSyntaxTrees(tree); ImmutableArray <Diagnostic> parseDiagnostics = compilation.GetParseDiagnostics(); Assembly stylecopAnalyzersAssembly = Assembly.LoadFile(GetPathToFile(@"StyleCop.Analyzers.dll")); ImmutableArray <DiagnosticAnalyzer> analyzers = stylecopAnalyzersAssembly.GetTypes() .Where(t => t.IsAbstract == false && typeof(DiagnosticAnalyzer).IsAssignableFrom(t)) .Select(t => Activator.CreateInstance(t) as DiagnosticAnalyzer) .ToImmutableArray(); CompilationWithAnalyzersOptions options = new CompilationWithAnalyzersOptions( new AnalyzerOptions(default(ImmutableArray <AdditionalText>)), OnAnalyzerException, false, false); CompilationWithAnalyzers compilationWithAnalyzers = new CompilationWithAnalyzers(compilation, analyzers, options); Task <ImmutableArray <Diagnostic> > analyzerDiagnosticsTask = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(); analyzerDiagnosticsTask.Wait(); ImmutableArray <Diagnostic> analyzerDiagnostics = analyzerDiagnosticsTask.Result; return(parseDiagnostics.Concat(analyzerDiagnostics).ToImmutableArray()); }
private static async Task Main(string[] args) { string solutionPath = args[0]; MSBuildWorkspace workspace = MSBuildWorkspace.Create(); Solution solution = await workspace.OpenSolutionAsync(solutionPath).ConfigureAwait(false); SealedAnalyzer analyzer = new SealedAnalyzer(); ImmutableArray <DiagnosticAnalyzer> analyzers = ImmutableArray.Create <DiagnosticAnalyzer>(analyzer); foreach (Project project in solution.Projects) { Compilation compilation = await project.GetCompilationAsync().ConfigureAwait(false); CompilationWithAnalyzers compilationWithAnalyzers = compilation.WithAnalyzers(analyzers); ImmutableArray <Diagnostic> analyzerDiagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false); PrintDiagnostics(analyzerDiagnostics); void PrintDiagnostics(ImmutableArray <Diagnostic> diagnostics) { if (diagnostics.Length > 0) { System.Console.WriteLine("----------------------------------------"); System.Console.WriteLine($"{project.Name}: {diagnostics.Length} diagnostics"); foreach (Diagnostic diagnostic in diagnostics) { System.Console.Write("\t"); System.Console.WriteLine(diagnostic); } } } } }
public async Task <Diagnostic[]> GetDiagnosticsAsync(string path) { string source = File.ReadAllText(path); var syntaxTree = CSharpSyntaxTree.ParseText(source); var baseCompilation = CSharpCompilation.Create( "analyzer-output", new[] { syntaxTree }, new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }, new CSharpCompilationOptions(OutputKind.NetModule) ); var analyzers = AnalyzerTypes.Select(Activator.CreateInstance) .Cast <DiagnosticAnalyzer>() .ToArray(); var compilation = new CompilationWithAnalyzers( baseCompilation, ImmutableArray.Create(analyzers), new AnalyzerOptions(ImmutableArray.Create <AdditionalText>()), CancellationToken.None ); ImmutableArray <Diagnostic> diagnostics = await compilation.GetAnalyzerDiagnosticsAsync(); return(diagnostics.ToArray()); }
protected Diagnostic[] GetDiagnostics(IEnumerable <string> sourceCodes) { DiagnosticAnalyzer analyzer = GetDiagnosticAnalyzer(); Project project = CreateProject(sourceCodes); CompilationWithAnalyzers compilationWithAnalyzers = project.GetCompilationAsync().Result .WithAnalyzers(ImmutableArray.Create(analyzer)); ImmutableArray <Diagnostic> analyzerDiagnostics = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result; List <Diagnostic> diagnostics = new List <Diagnostic>(analyzerDiagnostics.Length); foreach (Diagnostic diagnostic in analyzerDiagnostics) { if (diagnostic.Location == Location.None || diagnostic.Location.IsInMetadata) { diagnostics.Add(diagnostic); } else { SyntaxTree tree; foreach (Document doc in project.Documents) { tree = doc.GetSyntaxTreeAsync().Result; if (tree == diagnostic.Location.SourceTree) { diagnostics.Add(diagnostic); } } } } return(diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray()); }
public static Task <ImmutableArray <Diagnostic> > GetAnalyzerDiagnosticsAsync( this Compilation compilation, ImmutableArray <DiagnosticAnalyzer> analyzers, CompilationWithAnalyzersOptions analysisOptions, CancellationToken cancellationToken = default) { var compilationWithAnalyzers = new CompilationWithAnalyzers(compilation, analyzers, analysisOptions); return(compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(cancellationToken)); }
private async Task FormatWithAnalyzersCoreAsync(Workspace workspace, ProjectId projectId, IEnumerable <DiagnosticAnalyzer> analyzers, CancellationToken cancellationToken) { if (analyzers != null && analyzers.Count() != 0) { var project = workspace.CurrentSolution.GetProject(projectId); var diagnostics = await GetDiagnostics(project, analyzers, cancellationToken).ConfigureAwait(false); // Ensure at least 1 analyzer supporting the current project's language ran if (_compilationWithAnalyzers != null) { var extension = StringComparer.OrdinalIgnoreCase.Equals(project.Language, "C#") ? ".csproj" : ".vbproj"; var resultFile = project.FilePath?.Substring(project.FilePath.LastIndexOf(Path.DirectorySeparatorChar)).Replace(extension, "_CodeFormatterResults.txt"); foreach (var analyzer in analyzers) { var diags = await _compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(ImmutableArray.Create(analyzer), cancellationToken); if (Verbose || LogOutputPath != null) { var analyzerTelemetryInfo = await _compilationWithAnalyzers.GetAnalyzerTelemetryInfoAsync(analyzer, cancellationToken); FormatLogger.WriteLine("{0}\t{1}\t{2}\t{3}", project.Name, analyzer.ToString(), diags.Count(), analyzerTelemetryInfo.ExecutionTime); var resultPath = Path.ChangeExtension(LogOutputPath + resultFile, "json"); LogDiagnostics(resultPath, diags); } } } if (ApplyFixes) { var batchFixer = WellKnownFixAllProviders.BatchFixer; var context = new FixAllContext( project.Documents.First(), // TODO: Shouldn't this be the whole project? new UberCodeFixer(_diagnosticIdToFixerMap), FixAllScope.Project, null, diagnostics.Select(d => d.Id), new FormattingEngineDiagnosticProvider(project, diagnostics), cancellationToken); var fix = await batchFixer.GetFixAsync(context).ConfigureAwait(false); if (fix != null) { foreach (var operation in await fix.GetOperationsAsync(cancellationToken).ConfigureAwait(false)) { operation.Apply(workspace, cancellationToken); } } } } }
public static async Task <ImmutableDictionary <DiagnosticAnalyzer, AnalysisResult> > AnalyzeAsync(this CompilationWithAnalyzers analyzerDriver, Project project, CancellationToken cancellationToken) { var version = await DiagnosticIncrementalAnalyzer.GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false); // Run all analyzers at once. // REVIEW: why there are 2 different cancellation token? one that I can give to constructor and one I can give in to each method? // REVIEW: we drop all those allocations for the diagnostics returned. can we avoid this? await analyzerDriver.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false); // this is wierd, but now we iterate through each analyzer for each tree to get cached result. // REVIEW: no better way to do this? var noSpanFilter = default(TextSpan?); var analyzers = analyzerDriver.Analyzers; var compilation = analyzerDriver.Compilation; var builder = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, AnalysisResult>(); foreach (var analyzer in analyzers) { var result = new Builder(project, version); // REVIEW: more unnecessary allocations just to get diagnostics per analyzer var oneAnalyzers = ImmutableArray.Create(analyzer); foreach (var tree in compilation.SyntaxTrees) { var model = compilation.GetSemanticModel(tree); var syntax = await analyzerDriver.GetAnalyzerSyntaxDiagnosticsAsync(tree, oneAnalyzers, cancellationToken).ConfigureAwait(false); Contract.Requires(syntax.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(syntax, analyzerDriver.Compilation).Count()); result.AddSyntaxDiagnostics(tree, syntax); var semantic = await analyzerDriver.GetAnalyzerSemanticDiagnosticsAsync(model, noSpanFilter, oneAnalyzers, cancellationToken).ConfigureAwait(false); Contract.Requires(semantic.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(semantic, analyzerDriver.Compilation).Count()); result.AddSemanticDiagnostics(tree, semantic); } var rest = await analyzerDriver.GetAnalyzerCompilationDiagnosticsAsync(oneAnalyzers, cancellationToken).ConfigureAwait(false); Contract.Requires(rest.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(rest, analyzerDriver.Compilation).Count()); result.AddCompilationDiagnostics(rest); builder.Add(analyzer, result.ToResult()); } return(builder.ToImmutable()); }
private static IEnumerable <Diagnostic> EnumerateAnalyzerDiagnostics( [NotNull] CompilationWithAnalyzers compilationWithAnalyzers, [NotNull] SyntaxTree tree, DiagnosticsCaptureMode diagnosticsCaptureMode) { foreach (Diagnostic analyzerDiagnostic in compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result) { Location location = analyzerDiagnostic.Location; if (diagnosticsCaptureMode == DiagnosticsCaptureMode.AllowOutsideSourceTree || LocationIsInSourceTree(location, tree)) { yield return(analyzerDiagnostic); } } }
public IEnumerable <Diagnostic> GetDiagnostics(Compilation compilation) { if (diagnosticAnalyzers.IsDefaultOrEmpty) { return(new Diagnostic[0]); } using (var tokenSource = new CancellationTokenSource()) { var compilationWithAnalyzer = new CompilationWithAnalyzers(compilation, diagnosticAnalyzers, null, tokenSource.Token); return(compilationWithAnalyzer.GetAnalyzerDiagnosticsAsync().Result); } }
public static async Task <ImmutableArray <Diagnostic> > GetAnalyzerDiagnosticsAsync( this Compilation compilation, ImmutableArray <DiagnosticAnalyzer> analyzers, IComparer <Diagnostic> comparer = null, CancellationToken cancellationToken = default) { CompilationWithAnalyzers compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, default(AnalyzerOptions), cancellationToken); ImmutableArray <Diagnostic> diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(cancellationToken); if (comparer != null) { diagnostics = diagnostics.Sort(comparer); } return(diagnostics); }
public static async Task <ImmutableArray <Diagnostic> > GetAnalyzerDiagnosticsAsync( this Compilation compilation, DiagnosticAnalyzer analyzer, IComparer <Diagnostic> comparer = null, CancellationToken cancellationToken = default(CancellationToken)) { CompilationWithAnalyzers compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer), default(AnalyzerOptions), cancellationToken); ImmutableArray <Diagnostic> diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false); if (comparer != null) { diagnostics = diagnostics.Sort(comparer); } return(diagnostics); }
/// <summary> /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. /// The returned diagnostics are then ordered by location in the source document. /// </summary> /// <param name="analyzer">The analyzer to run on the documents</param> /// <param name="documents">The Documents that the analyzer will be run on</param> /// <returns>An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location</returns> protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, Document[] documents) { if (documents is null) { throw new ArgumentNullException(nameof(documents)); } var projects = new HashSet <Project>(); foreach (Document document in documents) { projects.Add(document.Project); } var diagnostics = new List <Diagnostic>(); foreach (Project project in projects) { CompilationWithAnalyzers compilationWithAnalyzers = project.GetCompilationAsync().Result.WithAnalyzers(ImmutableArray.Create(analyzer)); ImmutableArray <Diagnostic> diags = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result; foreach (Diagnostic diag in diags) { if (diag.Location == Location.None || diag.Location.IsInMetadata) { diagnostics.Add(diag); } else { for (int i = 0; i < documents.Length; i++) { Document document = documents[i]; SyntaxTree tree = document.GetSyntaxTreeAsync().Result; if (tree == diag.Location.SourceTree) { diagnostics.Add(diag); } } } } } Diagnostic[] results = SortDiagnostics(diagnostics); diagnostics.Clear(); return(results); }
public async Task <List <Diagnostic> > GetDiagnosticsAsync(string sourceCode) { var compilation = new CompilationWithAnalyzers( GetCompilation(sourceCode), ImmutableArray.Create <DiagnosticAnalyzer>(new EqualityAnalyzer()), new CompilationWithAnalyzersOptions( new AnalyzerOptions(ImmutableArray <AdditionalText> .Empty), (ex, _, _) => Assert.True(false, ex.Message), concurrentAnalysis: false, logAnalyzerExecutionTime: false)); var diagnostics = await compilation .GetAnalyzerDiagnosticsAsync() .ConfigureAwait(false); return(diagnostics .OrderBy(x => x.Id) .ToList()); }
private static async Task <ImmutableArray <Diagnostic> > GetDiagnosticsAsync(Project project, DiagnosticAnalyzer analyzer) { Compilation compilation = await project.GetCompilationAsync().ConfigureAwait(false); //foreach (Diagnostic diagnostic in compilation.GetDiagnostics()) //{ // if (diagnostic.Descriptor.DefaultSeverity == DiagnosticSeverity.Error // && diagnostic.Descriptor.CustomTags.Contains(WellKnownDiagnosticTags.Compiler)) // { // Debug.WriteLine(diagnostic.ToString()); // } //} compilation = EnableDiagnosticsDisabledByDefault(analyzer, compilation); CompilationWithAnalyzers compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer)); return(await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false)); }
public static async Task ProcessProject(FileInfo projectFile) { if (projectFile is null) { throw new ArgumentNullException(nameof(projectFile)); } using var workspace = MSBuildWorkspace.Create(); Project project = await workspace.OpenProjectAsync(projectFile.FullName).ConfigureAwait(false); CompilationWithAnalyzers compilationWithAnalyzers = (await project.GetCompilationAsync().ConfigureAwait(false)) .WithAnalyzers(ImmutableArray.Create(GetAnalyzers().ToArray())); ImmutableArray <Diagnostic> diags = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false); foreach (Diagnostic diag in diags) { Assert.Fail(diag.ToString()); } }
private async Task <ImmutableArray <Diagnostic> > GetDiagnosticsAsync(Document document) { var analyzers = ImmutableArray.Create(this.CreateAnalyzer()); Compilation compilation = await document.Project.GetCompilationAsync(CancellationToken.None).ConfigureAwait(false); CompilationWithAnalyzers compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, cancellationToken: CancellationToken.None); compilation.GetDiagnostics(CancellationToken.None); foreach (Diagnostic diagnostic in await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false)) { Location location = diagnostic.Location; if (location.IsInSource && location.SourceTree == (SyntaxTree)document.GetSyntaxTreeAsync(CancellationToken.None).Result) { ImmutableArray.CreateBuilder <Diagnostic>().Add(diagnostic); } } return(ImmutableArray.CreateBuilder <Diagnostic>().ToImmutable()); }
/// <summary> /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. /// The returned diagnostics are then ordered by location in the source document. /// </summary> /// <param name="analyzer">The analyzer to run on the documents</param> /// <param name="documents">The Documents that the analyzer will be run on</param> /// <returns>An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location</returns> protected async Task <Diagnostic[]> GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, Document[] documents) { HashSet <Project> projects = new HashSet <Project>(); foreach (Document document in documents) { projects.Add(document.Project); } List <Diagnostic> diagnostics = new List <Diagnostic>(); foreach (Project project in projects) { CompilationWithAnalyzers compilationWithAnalyzers = (await project.GetCompilationAsync()).WithAnalyzers(ImmutableArray.Create(analyzer)); ImmutableArray <Diagnostic> diags = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(); foreach (Diagnostic diag in diags) { if (diag.Location == Location.None || diag.Location.IsInMetadata) { diagnostics.Add(diag); } else { foreach (Document document in documents) { SyntaxTree tree = await document.GetSyntaxTreeAsync(); if (tree == diag.Location.SourceTree) { diagnostics.Add(diag); } } } } } Diagnostic[] results = SortDiagnostics(diagnostics); diagnostics.Clear(); return(results); }
public async Task <IEnumerable <ISymbol> > GetSymbolsAsync( Project project, RenameScope scope, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); var compilationWithAnalyzersOptions = new CompilationWithAnalyzersOptions( options: default(AnalyzerOptions), onAnalyzerException: default(Action <Exception, DiagnosticAnalyzer, Diagnostic>), concurrentAnalysis: true, logAnalyzerExecutionTime: false, reportSuppressedDiagnostics: false); Compilation compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); ImmutableArray <SymbolKind> symbolKinds = scope switch { RenameScope.Type => ImmutableArray.Create(SymbolKind.NamedType), RenameScope.Member => ImmutableArray.Create(SymbolKind.Field, SymbolKind.Event, SymbolKind.Method, SymbolKind.Property), RenameScope.Local => ImmutableArray.Create(SymbolKind.Field, SymbolKind.Event, SymbolKind.Method, SymbolKind.Property), _ => throw new InvalidOperationException(), }; var analyzer = new Analyzer( symbolKinds, IncludeGeneratedCode); var compilationWithAnalyzers = new CompilationWithAnalyzers( compilation, ImmutableArray.Create((DiagnosticAnalyzer)analyzer), compilationWithAnalyzersOptions); ImmutableArray <Diagnostic> _ = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false); return(analyzer.Symbols); }
public async Task <ImmutableArray <SpellingFixResult> > FixProjectAsync( Project project, CancellationToken cancellationToken = default) { project = CurrentSolution.GetProject(project.Id); ISpellingService service = MefWorkspaceServices.Default.GetService <ISpellingService>(project.Language); if (service == null) { return(ImmutableArray <SpellingFixResult> .Empty); } ImmutableArray <Diagnostic> previousDiagnostics = ImmutableArray <Diagnostic> .Empty; ImmutableArray <Diagnostic> previousPreviousDiagnostics = ImmutableArray <Diagnostic> .Empty; ImmutableArray <SpellingFixResult> .Builder results = ImmutableArray.CreateBuilder <SpellingFixResult>(); bool nonSymbolsFixed = (Options.ScopeFilter & (SpellingScopeFilter.NonSymbol)) == 0; while (true) { cancellationToken.ThrowIfCancellationRequested(); var compilationWithAnalyzersOptions = new CompilationWithAnalyzersOptions( options: default(AnalyzerOptions), onAnalyzerException: default(Action <Exception, DiagnosticAnalyzer, Diagnostic>), concurrentAnalysis: true, logAnalyzerExecutionTime: false, reportSuppressedDiagnostics: false); Compilation compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); DiagnosticAnalyzer analyzer = service.CreateAnalyzer(SpellingData, Options); var compilationWithAnalyzers = new CompilationWithAnalyzers( compilation, ImmutableArray.Create(analyzer), compilationWithAnalyzersOptions); ImmutableArray <Diagnostic> diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false); #if DEBUG foreach (IGrouping <Diagnostic, Diagnostic> grouping in diagnostics .GroupBy(f => f, DiagnosticDeepEqualityComparer.Instance)) { using (IEnumerator <Diagnostic> en = grouping.GetEnumerator()) { if (en.MoveNext() && en.MoveNext()) { Debug.Fail(DiagnosticFormatter.FormatDiagnostic(en.Current)); } } } #endif int length = diagnostics.Length; if (length == 0) { break; } if (length == previousDiagnostics.Length && !diagnostics.Except(previousDiagnostics, DiagnosticDeepEqualityComparer.Instance).Any()) { break; } if (length == previousPreviousDiagnostics.Length && !diagnostics.Except(previousPreviousDiagnostics, DiagnosticDeepEqualityComparer.Instance).Any()) { LogHelpers.WriteInfiniteLoopSummary(diagnostics, previousDiagnostics, project, FormatProvider); break; } var spellingDiagnostics = new List <SpellingDiagnostic>(); foreach (Diagnostic diagnostic in diagnostics) { Debug.Assert(diagnostic.Id == CommonDiagnosticIdentifiers.PossibleMisspellingOrTypo, diagnostic.Id); if (diagnostic.Id != CommonDiagnosticIdentifiers.PossibleMisspellingOrTypo) { if (diagnostic.IsAnalyzerExceptionDiagnostic()) { LogHelpers.WriteDiagnostic(diagnostic, baseDirectoryPath: Path.GetDirectoryName(project.FilePath), formatProvider: FormatProvider, indentation: " ", verbosity: Verbosity.Detailed); } continue; } SpellingDiagnostic spellingDiagnostic = service.CreateSpellingDiagnostic(diagnostic); spellingDiagnostics.Add(spellingDiagnostic); } if (!nonSymbolsFixed) { List <SpellingFixResult> commentResults = await FixCommentsAsync(project, spellingDiagnostics, cancellationToken).ConfigureAwait(false); results.AddRange(commentResults); nonSymbolsFixed = true; } if ((Options.ScopeFilter & SpellingScopeFilter.Symbol) == 0) { break; } (List <SpellingFixResult> symbolResults, bool allIgnored) = await FixSymbolsAsync( project, spellingDiagnostics, service.SyntaxFacts, cancellationToken) .ConfigureAwait(false); results.AddRange(symbolResults); if (allIgnored) { break; } if (Options.DryRun) { break; } project = CurrentSolution.GetProject(project.Id); previousPreviousDiagnostics = previousDiagnostics; previousDiagnostics = diagnostics; } return(results.ToImmutableArray()); }
private async Task <FixResult> FixProjectAsync(Project project, CancellationToken cancellationToken = default) { string language = project.Language; ImmutableArray <Assembly> assemblies = (Options.IgnoreAnalyzerReferences) ? ImmutableArray <Assembly> .Empty : project.AnalyzerReferences .Distinct() .OfType <AnalyzerFileReference>() .Select(f => f.GetAssembly()) .Where(f => !_analyzerFiles.Contains(f.FullName)) .ToImmutableArray(); ImmutableArray <DiagnosticAnalyzer> analyzers = _analyzerFiles .GetAnalyzers(language) .AddRange(_analyzerFileCache.GetAnalyzers(assemblies, language)); if (!analyzers.Any()) { return(FixResult.NoAnalyzers); } ImmutableArray <CodeFixProvider> fixers = _analyzerFiles .GetFixers(language) .AddRange(_analyzerFileCache.GetFixers(assemblies, language)); if (!fixers.Any()) { return(FixResult.NoFixers); } Dictionary <string, ImmutableArray <DiagnosticAnalyzer> > analyzersById = analyzers .SelectMany(f => f.SupportedDiagnostics.Select(id => (id.Id, analyzer: f))) .GroupBy(f => f.Id) .ToDictionary(f => f.Key, g => g.Select(f => f.analyzer).Distinct().ToImmutableArray()); Dictionary <string, ImmutableArray <CodeFixProvider> > fixersById = fixers .Where(f => f.GetFixAllProvider() != null) .SelectMany(f => f.FixableDiagnosticIds.Select(id => (id, fixer: f))) .GroupBy((f) => f.id) .ToDictionary(f => f.Key, g => g.Select(f => f.fixer).ToImmutableArray()); ImmutableArray <Diagnostic> previousDiagnostics = ImmutableArray <Diagnostic> .Empty; int iterationCount = 1; while (true) { cancellationToken.ThrowIfCancellationRequested(); project = CurrentSolution.GetProject(project.Id); WriteLine($" Compile '{project.Name}'{((iterationCount > 1) ? $" iteration {iterationCount}" : "")}"); Compilation compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); if (!VerifyCompilerDiagnostics(compilation, cancellationToken)) { return(FixResult.CompilerError); } var compilationWithAnalyzers = new CompilationWithAnalyzers(compilation, analyzers, DefaultCompilationWithAnalyzersOptions); WriteLine($" Analyze '{project.Name}'"); ImmutableArray <Diagnostic> diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false); foreach (string message in diagnostics .Where(f => f.Id.StartsWith("AD", StringComparison.Ordinal)) .Select(f => f.ToString()) .Distinct()) { WriteLine(message, ConsoleColor.Yellow); } diagnostics = diagnostics .Where(f => f.Severity != DiagnosticSeverity.Hidden && analyzersById.ContainsKey(f.Id) && fixersById.ContainsKey(f.Id) && !Options.IgnoredDiagnosticIds.Contains(f.Id)) .ToImmutableArray(); int length = diagnostics.Length; if (length == 0) { break; } if (length == previousDiagnostics.Length && !diagnostics.Except(previousDiagnostics, DiagnosticDeepEqualityComparer.Instance).Any()) { break; } WriteLine($" Found {length} {((length == 1) ? "diagnostic" : "diagnostics")} in '{project.Name}'"); foreach (string diagnosticId in diagnostics .Select(f => f.Id) .Distinct() .OrderBy(f => f)) { cancellationToken.ThrowIfCancellationRequested(); FixResult result = await FixDiagnosticsAsync( diagnosticId, CurrentSolution.GetProject(project.Id), analyzersById[diagnosticId], fixersById[diagnosticId], cancellationToken).ConfigureAwait(false); if (result == FixResult.CompilerError) { return(result); } } previousDiagnostics = diagnostics; iterationCount++; } return(FixResult.Success); }
private async Task <ProjectAnalysisResult> AnalyzeProjectCoreAsync(Project project, ImmutableArray <DiagnosticAnalyzer> analyzers, CancellationToken cancellationToken = default) { LogHelpers.WriteUsedAnalyzers(analyzers, null, Options, ConsoleColors.DarkGray, Verbosity.Diagnostic); cancellationToken.ThrowIfCancellationRequested(); Compilation compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); ImmutableArray <Diagnostic> compilerDiagnostics = (Options.IgnoreCompilerDiagnostics) ? ImmutableArray <Diagnostic> .Empty : compilation.GetDiagnostics(cancellationToken); compilerDiagnostics = FilterDiagnostics(compilerDiagnostics, project, cancellationToken).ToImmutableArray(); ImmutableArray <Diagnostic> diagnostics = ImmutableArray <Diagnostic> .Empty; ImmutableDictionary <DiagnosticAnalyzer, AnalyzerTelemetryInfo> telemetry = ImmutableDictionary <DiagnosticAnalyzer, AnalyzerTelemetryInfo> .Empty; if (analyzers.Any()) { var compilationWithAnalyzersOptions = new CompilationWithAnalyzersOptions( options: project.AnalyzerOptions, onAnalyzerException: default(Action <Exception, DiagnosticAnalyzer, Diagnostic>), concurrentAnalysis: Options.ConcurrentAnalysis, logAnalyzerExecutionTime: Options.LogAnalyzerExecutionTime, reportSuppressedDiagnostics: Options.ReportSuppressedDiagnostics); var compilationWithAnalyzers = new CompilationWithAnalyzers(compilation, analyzers, compilationWithAnalyzersOptions); if (Options.LogAnalyzerExecutionTime) { AnalysisResult analysisResult = await compilationWithAnalyzers.GetAnalysisResultAsync(cancellationToken).ConfigureAwait(false); diagnostics = analysisResult.GetAllDiagnostics(); telemetry = analysisResult.AnalyzerTelemetryInfo; } else { diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false); } } string projectDirectoryPath = Path.GetDirectoryName(project.FilePath); LogHelpers.WriteDiagnostics(FilterDiagnostics(diagnostics.Where(f => f.IsAnalyzerExceptionDiagnostic()), project, cancellationToken).ToImmutableArray(), baseDirectoryPath: projectDirectoryPath, formatProvider: FormatProvider, indentation: " ", verbosity: Verbosity.Detailed); #if DEBUG if (ConsoleOut.Verbosity >= Verbosity.Detailed && diagnostics.Any(f => f.IsAnalyzerExceptionDiagnostic())) { Console.Write("Stop (Y/N)? "); if (char.ToUpperInvariant((char)Console.Read()) == 'Y') { throw new OperationCanceledException(); } } #endif diagnostics = FilterDiagnostics(diagnostics.Where(f => !f.IsAnalyzerExceptionDiagnostic()), project, cancellationToken).ToImmutableArray(); LogHelpers.WriteDiagnostics(compilerDiagnostics, baseDirectoryPath: projectDirectoryPath, formatProvider: FormatProvider, indentation: " ", verbosity: Verbosity.Normal); LogHelpers.WriteDiagnostics(diagnostics, baseDirectoryPath: projectDirectoryPath, formatProvider: FormatProvider, indentation: " ", verbosity: Verbosity.Normal); return(ProjectAnalysisResult.Create(project, compilerDiagnostics, diagnostics, telemetry)); }
static void Main(string[] args) { SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@" using System; namespace RoslynCompileSample { public class Writer { public void Write(string message) { var prefix = GetMessagePrefix(); Console.WriteLine(prefix + ""-"" + message); } public string GetMessagePrefix() { return ""pre""; } } }"); string assemblyName = Path.GetRandomFileName(); MetadataReference[] references = new MetadataReference[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location) }; string analyzerAssemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\lib\DotNetDoodle.Analyzers.dll"); ImmutableArray <DiagnosticAnalyzer> diagnosticAnalyzers = new AnalyzerFileReference(analyzerAssemblyPath).GetAnalyzers(LanguageNames.CSharp); CompilationWithAnalyzers compilationWithAnalyzers = CSharpCompilation.Create( assemblyName, syntaxTrees: new[] { syntaxTree }, references: references, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)).WithAnalyzers(diagnosticAnalyzers); ImmutableArray <Diagnostic> diagsnostics = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result; using (var ms = new MemoryStream()) { EmitResult result = compilationWithAnalyzers.Compilation.Emit(ms); ImmutableArray <Diagnostic> allDiagsnostics = result.Diagnostics.Concat(diagsnostics).ToImmutableArray(); if (!result.Success) { IEnumerable <Diagnostic> failures = allDiagsnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error); foreach (Diagnostic diagnostic in failures) { Console.Error.WriteLine("ERROR: {0}: {1}", diagnostic.Id, diagnostic.GetMessage()); } WriteWarnings(allDiagsnostics); } else { WriteWarnings(allDiagsnostics); ms.Seek(0, SeekOrigin.Begin); Assembly assembly = Assembly.Load(ms.ToArray()); Type type = assembly.GetType("RoslynCompileSample.Writer"); object obj = Activator.CreateInstance(type); type.InvokeMember("Write", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, new object[] { "Hello World" }); } } Console.ReadLine(); }
/// <summary> /// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it. /// The returned diagnostics are then ordered by location in the source document. /// </summary> /// <param name="analyzer">The analyzer to run on the documents</param> /// <param name="documents">The Documents that the analyzer will be run on</param> /// <returns>An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location</returns> protected static async Task <IReadOnlyList <Diagnostic> > GetSortedDiagnosticsFromDocumentsAsync(DiagnosticAnalyzer analyzer, Document[] documents) { HashSet <Project> projects = new(); foreach (Document document in documents) { projects.Add(document.Project); } List <Diagnostic> diagnostics = new(); foreach (Project project in projects) { Compilation?compilation = await project.GetCompilationAsync(); if (compilation == null) { continue; } ImmutableArray <Diagnostic> compilerErrors = compilation.GetDiagnostics(); if (compilerErrors.Length != 0) { StringBuilder errors = compilerErrors.Where(IsReportableCSharpError) .Aggregate(new StringBuilder(), func: (current, compilerError) => current.Append(compilerError)); if (errors.Length != 0) { throw new UnitTestSourceException("Please correct following compiler errors in your unit test source:" + errors); } } CompilationWithAnalyzers compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer)); ImmutableArray <Diagnostic> diags = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(); foreach (Diagnostic diag in diags) { if (diag.Location == Location.None || diag.Location.IsInMetadata) { diagnostics.Add(diag); } else { foreach (Document document in documents) { SyntaxTree?tree = await document.GetSyntaxTreeAsync(); if (tree != null && tree == diag.Location.SourceTree) { diagnostics.Add(diag); } } } } } IReadOnlyList <Diagnostic> results = SortDiagnostics(diagnostics); diagnostics.Clear(); return(results); }