protected static void AnalyzeDocumentCore(IDiagnosticAnalyzer analyzer, Document document, Action <Diagnostic> addDiagnostic, TextSpan?span = null, bool continueOnError = false) { TextSpan spanToTest = span.HasValue ? span.Value : document.GetSyntaxRootAsync().Result.FullSpan; var semanticModel = document.GetSemanticModelAsync().Result; AnalyzerDriver.RunAnalyzers(semanticModel, spanToTest, ImmutableArray.Create(analyzer), addDiagnostic, continueOnError: continueOnError); }
private static TCompilation GetCompilationWithAnalyzerDiagnostics <TCompilation>( this TCompilation c, DiagnosticAnalyzer[] analyzers, AnalyzerOptions options, Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException, bool reportSuppressedDiagnostics, bool includeCompilerDiagnostics, out ImmutableArray <Diagnostic> diagnostics) where TCompilation : Compilation { var analyzersArray = analyzers.ToImmutableArray(); if (reportSuppressedDiagnostics != c.Options.ReportSuppressedDiagnostics) { c = (TCompilation)c.WithOptions(c.Options.WithReportSuppressedDiagnostics(reportSuppressedDiagnostics)); } var analyzerManager = new AnalyzerManager(analyzersArray); var driver = AnalyzerDriver.CreateAndAttachToCompilation(c, analyzersArray, options, analyzerManager, onAnalyzerException, null, false, out var newCompilation, CancellationToken.None); var compilerDiagnostics = newCompilation.GetDiagnostics(); var analyzerDiagnostics = driver.GetDiagnosticsAsync(newCompilation).Result; var allDiagnostics = includeCompilerDiagnostics ? compilerDiagnostics.AddRange(analyzerDiagnostics) : analyzerDiagnostics; diagnostics = driver.ApplyProgrammaticSuppressions(allDiagnostics, newCompilation); if (!reportSuppressedDiagnostics) { Assert.True(diagnostics.All(d => !d.IsSuppressed)); } return((TCompilation)newCompilation); // note this is a new compilation }
private void GenerateSimulatedCompilationSourceEvents( SyntaxTree tree, Compilation compilation, Func <SyntaxTree, Compilation, CancellationToken, SemanticModel> getCachedSemanticModel, AnalyzerDriver driver, CancellationToken cancellationToken) { using (_gate.DisposableWait(cancellationToken)) { if (_treesWithGeneratedSourceEvents.Contains(tree)) { return; } } var globalNs = compilation.Assembly.GlobalNamespace; var symbols = GetDeclaredSymbolsInTree(tree, compilation, getCachedSemanticModel, cancellationToken); var compilationEvents = CreateCompilationEventsForTree(symbols.Concat(globalNs), tree, compilation); using (_gate.DisposableWait(cancellationToken)) { if (_treesWithGeneratedSourceEvents.Contains(tree)) { return; } OnCompilationEventsGenerated_NoLock(compilationEvents, tree, driver, cancellationToken); var added = _treesWithGeneratedSourceEvents.Add(tree); Debug.Assert(added); } }
void TestDisabledDiagnostics() { var disabledDiagDescriptor = new DiagnosticDescriptor("XX001", "DummyDescription", "DummyMessage", "DummyCategory", DiagnosticSeverity.Warning, isEnabledByDefault: false); var enabledDiagDescriptor = new DiagnosticDescriptor("XX002", "DummyDescription", "DummyMessage", "DummyCategory", DiagnosticSeverity.Warning, isEnabledByDefault: true); var disabledDiag = CodeAnalysis.Diagnostic.Create(disabledDiagDescriptor, Location.None); var enabledDiag = CodeAnalysis.Diagnostic.Create(enabledDiagDescriptor, Location.None); var diags = new[] { disabledDiag, enabledDiag }; // Verify that only the enabled diag shows up after filtering. var options = TestOptions.Dll; var comp = CreateCompilationWithMscorlib45("", compOptions: options); var effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray(); Assert.Equal(1, effectiveDiags.Length); Assert.Contains(enabledDiag, effectiveDiags); // If the disabled diag was enabled through options, then it should show up. var specificDiagOptions = new Dictionary <string, ReportDiagnostic>(); specificDiagOptions.Add(disabledDiagDescriptor.Id, ReportDiagnostic.Warn); specificDiagOptions.Add(enabledDiagDescriptor.Id, ReportDiagnostic.Suppress); options = TestOptions.Dll.WithSpecificDiagnosticOptions(specificDiagOptions); comp = CreateCompilationWithMscorlib45("", compOptions: options); effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray(); Assert.Equal(1, effectiveDiags.Length); Assert.Contains(disabledDiag, effectiveDiags); }
static void FieldNameAnalyzerTest() { // // Construct a syntax tree and a compilation. // var tree = CSharpSyntaxTree.ParseText(@" class Person { private int _age; }"); var mscorlib = new MetadataFileReference(typeof(object).Assembly.Location); var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); var comp = CSharpCompilation.Create("Demo") .AddSyntaxTrees(tree) .AddReferences(mscorlib) .WithOptions(options); // // Get diagnostics. // var diags = AnalyzerDriver.GetDiagnostics(comp, new[] { new FieldNameAnalyzer() }, null, CancellationToken.None); foreach (var diag in diags) { Console.WriteLine(diag); } }
private static TCompilation GetCompilationWithAnalyzerDiagnostics <TCompilation>( this TCompilation c, DiagnosticAnalyzer[] analyzers, AnalyzerOptions options, Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException, bool logAnalyzerExceptionAsDiagnostics, bool reportSuppressedDiagnostics, bool includeCompilerDiagnostics, out ImmutableArray <Diagnostic> diagnostics) where TCompilation : Compilation { var analyzersArray = analyzers.ToImmutableArray(); var exceptionDiagnostics = new ConcurrentSet <Diagnostic>(); if (onAnalyzerException == null) { if (logAnalyzerExceptionAsDiagnostics) { onAnalyzerException = (ex, analyzer, diagnostic) => { exceptionDiagnostics.Add(diagnostic); }; } else { // We want unit tests to throw if any analyzer OR the driver throws, unless the test explicitly provides a delegate. onAnalyzerException = FailFastOnAnalyzerException; } } if (reportSuppressedDiagnostics != c.Options.ReportSuppressedDiagnostics) { c = (TCompilation)c.WithOptions(c.Options.WithReportSuppressedDiagnostics(reportSuppressedDiagnostics)); } var analyzerManager = new AnalyzerManager(analyzersArray); var driver = AnalyzerDriver.CreateAndAttachToCompilation(c, analyzersArray, options, analyzerManager, onAnalyzerException, null, false, out var newCompilation, CancellationToken.None); var compilerDiagnostics = newCompilation.GetDiagnostics(); var analyzerDiagnostics = driver.GetDiagnosticsAsync(newCompilation).Result; var allDiagnostics = includeCompilerDiagnostics ? compilerDiagnostics.AddRange(analyzerDiagnostics) : analyzerDiagnostics; diagnostics = driver.ApplyProgrammaticSuppressions(allDiagnostics, newCompilation).AddRange(exceptionDiagnostics); if (!reportSuppressedDiagnostics) { Assert.True(diagnostics.All(d => !d.IsSuppressed)); } return((TCompilation)newCompilation); // note this is a new compilation }
public IEnumerable <Diagnostic> GetDiagnostics(SyntaxTree syntaxTree) { var cancellationToken = new CancellationTokenSource().Token; Compilation compilation = CSharpCompilation.Create(null, ImmutableArray.Create(syntaxTree)); var driver = AnalyzerDriver.Create(compilation, DiagnosticAnalyzers, null, out compilation, cancellationToken); compilation.GetDiagnostics(cancellationToken); return(driver.GetDiagnosticsAsync().Result); }
void TestGetEffectiveDiagnosticsGlobal() { var noneDiagDesciptor = new DiagnosticDescriptor("XX0001", "DummyDescription", "DummyMessage", "DummyCategory", DiagnosticSeverity.Hidden, isEnabledByDefault: true); var infoDiagDesciptor = new DiagnosticDescriptor("XX0002", "DummyDescription", "DummyMessage", "DummyCategory", DiagnosticSeverity.Info, isEnabledByDefault: true); var warningDiagDesciptor = new DiagnosticDescriptor("XX0003", "DummyDescription", "DummyMessage", "DummyCategory", DiagnosticSeverity.Warning, isEnabledByDefault: true); var errorDiagDesciptor = new DiagnosticDescriptor("XX0004", "DummyDescription", "DummyMessage", "DummyCategory", DiagnosticSeverity.Error, isEnabledByDefault: true); var noneDiag = Microsoft.CodeAnalysis.Diagnostic.Create(noneDiagDesciptor, Location.None); var infoDiag = Microsoft.CodeAnalysis.Diagnostic.Create(infoDiagDesciptor, Location.None); var warningDiag = Microsoft.CodeAnalysis.Diagnostic.Create(warningDiagDesciptor, Location.None); var errorDiag = Microsoft.CodeAnalysis.Diagnostic.Create(errorDiagDesciptor, Location.None); var diags = new [] { noneDiag, infoDiag, warningDiag, errorDiag }; var options = OptionsDll.WithGeneralDiagnosticOption(ReportDiagnostic.Default); var comp = CreateCompilationWithMscorlib45("", compOptions: options); var effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray(); Assert.Equal(4, effectiveDiags.Length); options = OptionsDll.WithGeneralDiagnosticOption(ReportDiagnostic.Error); comp = CreateCompilationWithMscorlib45("", compOptions: options); effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray(); Assert.Equal(4, effectiveDiags.Length); Assert.Equal(1, effectiveDiags.Count(d => d.IsWarningAsError)); options = OptionsDll.WithGeneralDiagnosticOption(ReportDiagnostic.Warn); comp = CreateCompilationWithMscorlib45("", compOptions: options); effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray(); Assert.Equal(4, effectiveDiags.Length); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Error)); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Warning)); options = OptionsDll.WithGeneralDiagnosticOption(ReportDiagnostic.Info); comp = CreateCompilationWithMscorlib45("", compOptions: options); effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray(); Assert.Equal(4, effectiveDiags.Length); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Error)); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Info)); options = OptionsDll.WithGeneralDiagnosticOption(ReportDiagnostic.Hidden); comp = CreateCompilationWithMscorlib45("", compOptions: options); effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray(); Assert.Equal(4, effectiveDiags.Length); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Error)); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Hidden)); options = OptionsDll.WithGeneralDiagnosticOption(ReportDiagnostic.Suppress); comp = CreateCompilationWithMscorlib45("", compOptions: options); effectiveDiags = AnalyzerDriver.GetEffectiveDiagnostics(diags, comp).ToArray(); Assert.Equal(2, effectiveDiags.Length); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Error)); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Hidden)); }
public IEnumerable <Diagnostic> GetDiagnostics(SyntaxTree syntaxTree) { var cancellationToken = new CancellationTokenSource().Token; // FIXME Cannot dispose() because of violation of invariant in // http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis/DiagnosticAnalyzer/AsyncQueue.cs,187 var driver = new AnalyzerDriver <SyntaxKind>(DiagnosticAnalyzers, n => n.CSharpKind(), null, cancellationToken, null); Compilation compilation = CSharpCompilation.Create(null, ImmutableArray.Create(syntaxTree)); compilation = compilation.WithEventQueue(driver.CompilationEventQueue); compilation.GetDiagnostics(cancellationToken); return(driver.GetDiagnosticsAsync().Result); }
private async Task EnsureAnalyzerActionCountsInitializedAsync(AnalyzerDriver driver, CancellationToken cancellationToken) { if (_lazyAnalyzerActionCountsMap == null) { var builder = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, AnalyzerActionCounts>(); foreach (var(analyzer, _) in _analyzerStateMap) { var actionCounts = await driver.GetAnalyzerActionCountsAsync(analyzer, _compilationOptions, cancellationToken).ConfigureAwait(false); builder.Add(analyzer, actionCounts); } Interlocked.CompareExchange(ref _lazyAnalyzerActionCountsMap, builder.ToImmutable(), null); } }
static void ConfigureAwaitAnalyzerTest() { // // Construct a syntax tree and a compilation. // var tree = CSharpSyntaxTree.ParseText(@" using System.Threading.Tasks; class Foo { async Task Bar(Task t) { await t; } async Task<int> Baz(Task<int> t) { return await t; } async Task Qux(Task t) { await t.ConfigureAwait(false); } }"); var mscorlib = new MetadataFileReference(typeof(object).Assembly.Location); var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); var comp = CSharpCompilation.Create("Demo") .AddSyntaxTrees(tree) .AddReferences(mscorlib) .WithOptions(options); // // Get diagnostics. // var diags = AnalyzerDriver.GetDiagnostics(comp, new[] { new ConfigureAwaitAnalyzer() }, null, CancellationToken.None); foreach (var diag in diags) { Console.WriteLine(diag); } }
protected static async Task <IReadOnlyCollection <Diagnostic> > GetDiagnosticsFromDocumentsAsync(DiagnosticAnalyzer analyzer, Document document) { var compilation = await document.Project.GetCompilationAsync(); var tree = await document.GetSyntaxTreeAsync(); var driver = AnalyzerDriver.Create(compilation, ImmutableArray.Create(analyzer), null, out compilation, CancellationToken.None); compilation.GetDiagnostics(); var diagnostics = (await driver.GetDiagnosticsAsync()) .Where(d => d.Location == Location.None || d.Location.IsInMetadata || d.Location.SourceTree == tree) .OrderBy(d => d.Location.SourceSpan.Start) .ToList(); return(new ReadOnlyCollection <Diagnostic>(diagnostics)); }
internal void StoreAnalysisResult(AnalysisScope analysisScope, AnalyzerDriver driver, Compilation compilation, Func <DiagnosticAnalyzer, AnalyzerActionCounts> getAnalyzerActionCounts, bool fullAnalysisResultForAnalyzersInScope) { Debug.Assert(!fullAnalysisResultForAnalyzersInScope || analysisScope.FilterTreeOpt == null, "Full analysis result cannot come from partial (tree) analysis."); foreach (var analyzer in analysisScope.Analyzers) { // Dequeue reported analyzer diagnostics from the driver and store them in our maps. var syntaxDiagnostics = driver.DequeueLocalDiagnostics(analyzer, syntax: true, compilation: compilation); var semanticDiagnostics = driver.DequeueLocalDiagnostics(analyzer, syntax: false, compilation: compilation); var compilationDiagnostics = driver.DequeueNonLocalDiagnostics(analyzer, compilation); lock (_gate) { if (_completedAnalyzers.Contains(analyzer)) { // Already stored full analysis result for this analyzer. continue; } if (syntaxDiagnostics.Length > 0 || semanticDiagnostics.Length > 0 || compilationDiagnostics.Length > 0 || fullAnalysisResultForAnalyzersInScope) { UpdateLocalDiagnostics_NoLock(analyzer, syntaxDiagnostics, fullAnalysisResultForAnalyzersInScope, ref _localSyntaxDiagnosticsOpt); UpdateLocalDiagnostics_NoLock(analyzer, semanticDiagnostics, fullAnalysisResultForAnalyzersInScope, ref _localSemanticDiagnosticsOpt); UpdateNonLocalDiagnostics_NoLock(analyzer, compilationDiagnostics, fullAnalysisResultForAnalyzersInScope); } if (_analyzerExecutionTimeOpt != null) { var timeSpan = driver.ResetAnalyzerExecutionTime(analyzer); _analyzerExecutionTimeOpt[analyzer] = fullAnalysisResultForAnalyzersInScope ? timeSpan : _analyzerExecutionTimeOpt[analyzer] + timeSpan; } if (!_analyzerActionCounts.ContainsKey(analyzer)) { _analyzerActionCounts.Add(analyzer, getAnalyzerActionCounts(analyzer)); } if (fullAnalysisResultForAnalyzersInScope) { _completedAnalyzers.Add(analyzer); } } } }
/// <summary> /// Given an analyzer and a collection of documents to apply it to, run the analyzer and gather an array of /// diagnostics found. The returned diagnostics are then ordered by location in the source documents. /// </summary> /// <param name="analyzer">The analyzer to run on the documents.</param> /// <param name="documents">The <see cref="Document"/>s that the analyzer will be run on.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that the task will observe.</param> /// <returns>A collection of <see cref="Diagnostic"/>s that surfaced in the source code, sorted by /// <see cref="Diagnostic.Location"/>.</returns> protected static async Task <ImmutableArray <Diagnostic> > GetSortedDiagnosticsFromDocumentsAsync(DiagnosticAnalyzer analyzer, Document[] documents, CancellationToken cancellationToken) { var projects = new HashSet <Project>(); foreach (var document in documents) { projects.Add(document.Project); } var diagnostics = ImmutableArray.CreateBuilder <Diagnostic>(); foreach (var project in projects) { var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var driver = AnalyzerDriver.Create(compilation, ImmutableArray.Create(analyzer), null, out compilation, cancellationToken); var discarded = compilation.GetDiagnostics(cancellationToken); var diags = await driver.GetDiagnosticsAsync().ConfigureAwait(false); foreach (var diag in diags) { if (diag.Location == Location.None || diag.Location.IsInMetadata) { diagnostics.Add(diag); } else { for (int i = 0; i < documents.Length; i++) { var document = documents[i]; var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (tree == diag.Location.SourceTree) { diagnostics.Add(diag); } } } } } var results = SortDiagnostics(diagnostics); return(results.ToImmutableArray()); }
/// <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> /// <param name="spans">Optional TextSpan indicating where a Diagnostic will be found</param> /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns> protected async static Task <Diagnostic[]> GetSortedDiagnosticsFromDocumentsAsync(DiagnosticAnalyzer analyzer, Document[] documents) { var projects = new HashSet <Project>(); foreach (var document in documents) { projects.Add(document.Project); } var diagnostics = new List <Diagnostic>(); foreach (var project in projects) { var compilation = await project.GetCompilationAsync(); var driver = AnalyzerDriver.Create(compilation, ImmutableArray.Create(analyzer), null, out compilation, CancellationToken.None); var discarded = compilation.GetDiagnostics(); var diags = await driver.GetDiagnosticsAsync(); foreach (var diag in diags) { if (diag.Location == Location.None || diag.Location.IsInMetadata) { diagnostics.Add(diag); } else { foreach (var document in documents) { var tree = await document.GetSyntaxTreeAsync(); if (tree == diag.Location.SourceTree) { diagnostics.Add(diag); } } } } } var results = SortDiagnostics(diagnostics); diagnostics.Clear(); return(results); }
private static TCompilation GetAnalyzerDiagnostics <TCompilation>( this TCompilation c, DiagnosticAnalyzer[] analyzers, AnalyzerOptions options, Func <Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException, out ImmutableArray <Diagnostic> diagnostics) where TCompilation : Compilation { // We want unit tests to throw if any analyzer OR the driver throws, unless the test explicitly provides a delegate. continueOnAnalyzerException = continueOnAnalyzerException ?? DonotCatchAnalyzerExceptions; Compilation newCompilation; var driver = AnalyzerDriver.Create(c, analyzers.ToImmutableArray(), options, out newCompilation, continueOnAnalyzerException, CancellationToken.None); var discarded = newCompilation.GetDiagnostics(); diagnostics = driver.GetDiagnosticsAsync().Result; return((TCompilation)newCompilation); // note this is a new compilation }
/// <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> /// <param name="spans">Optional TextSpan indicating where a Diagnostic will be found</param> /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns> protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(IDiagnosticAnalyzer analyzer, Document[] documents) { var projects = new HashSet <Project>(); foreach (var document in documents) { projects.Add(document.Project); } var diagnostics = new List <Diagnostic>(); foreach (var project in projects) { var compilation = project.GetCompilationAsync().Result; var driver = new AnalyzerDriver <SyntaxKind>((new[] { analyzer }).ToImmutableArray(), n => n.CSharpKind(), null, CancellationToken.None); compilation = compilation.WithEventQueue(driver.CompilationEventQueue); var discarded = compilation.GetDiagnostics(); var diags = driver.GetDiagnosticsAsync().Result; foreach (var diag in diags) { if (diag.Location == Location.None || diag.Location.IsInMetadata) { diagnostics.Add(diag); } else { for (int i = 0; i < documents.Length; i++) { var document = documents[i]; var tree = document.GetSyntaxTreeAsync().Result; if (tree == diag.Location.SourceTree) { diagnostics.Add(diag); } } } } } var results = SortDiagnostics(diagnostics); diagnostics.Clear(); return(results); }
void TestDisabledAnalyzers() { var fullyDisabledAnalyzer = new FullyDisabledAnalyzer(); var partiallyDisabledAnalyzer = new PartiallyDisabledAnalyzer(); var options = TestOptions.Dll; Assert.True(AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(fullyDisabledAnalyzer, options)); Assert.False(AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(partiallyDisabledAnalyzer, options)); var specificDiagOptions = new Dictionary <string, ReportDiagnostic>(); specificDiagOptions.Add(FullyDisabledAnalyzer.desc1.Id, ReportDiagnostic.Warn); specificDiagOptions.Add(PartiallyDisabledAnalyzer.desc2.Id, ReportDiagnostic.Suppress); options = TestOptions.Dll.WithSpecificDiagnosticOptions(specificDiagOptions); Assert.False(AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(fullyDisabledAnalyzer, options)); Assert.True(AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(partiallyDisabledAnalyzer, options)); }
private static TCompilation GetAnalyzerDiagnostics <TCompilation>( this TCompilation c, DiagnosticAnalyzer[] analyzers, AnalyzerOptions options, Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException, bool logAnalyzerExceptionAsDiagnostics, bool reportDiagnosticsWithSourceSuppressions, out ImmutableArray <Diagnostic> diagnostics) where TCompilation : Compilation { var analyzersArray = analyzers.ToImmutableArray(); var exceptionDiagnostics = new ConcurrentSet <Diagnostic>(); if (onAnalyzerException == null) { if (logAnalyzerExceptionAsDiagnostics) { onAnalyzerException = (ex, analyzer, diagnostic) => { exceptionDiagnostics.Add(diagnostic); }; } else { // We want unit tests to throw if any analyzer OR the driver throws, unless the test explicitly provides a delegate. onAnalyzerException = FailFastOnAnalyzerException; } } Compilation newCompilation; var driver = AnalyzerDriver.CreateAndAttachToCompilation(c, analyzersArray, options, AnalyzerManager.Instance, onAnalyzerException, false, reportDiagnosticsWithSourceSuppressions, out newCompilation, CancellationToken.None); var discarded = newCompilation.GetDiagnostics(); diagnostics = driver.GetDiagnosticsAsync(newCompilation).Result.AddRange(exceptionDiagnostics); if (!reportDiagnosticsWithSourceSuppressions) { Assert.True(diagnostics.All(d => !d.IsSuppressed)); } return((TCompilation)newCompilation); // note this is a new compilation }
/// <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> /// <param name="spans">Optional TextSpan indicating where a Diagnostic will be found</param> /// <returns>An IEnumerable of Diagnostics that surfaced in teh source code, sorted by Location</returns> protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, Document[] documents) { var projects = new HashSet <Project>(); foreach (var document in documents) { projects.Add(document.Project); } var diagnostics = new List <Diagnostic>(); foreach (var project in projects) { var compilation = project.GetCompilationAsync().Result; var diags = AnalyzerDriver.GetAnalyzerDiagnosticsAsync(compilation, ImmutableArray.Create(analyzer)).Result; foreach (var diag in diags) { if (diag.Location == Location.None || diag.Location.IsInMetadata) { diagnostics.Add(diag); } else { for (int i = 0; i < documents.Length; i++) { var document = documents[i]; var tree = document.GetSyntaxTreeAsync().Result; if (tree == diag.Location.SourceTree) { diagnostics.Add(diag); } } } } } var results = SortDiagnostics(diagnostics); diagnostics.Clear(); return(results); }
public static ImmutableArray <Diagnostic> GetAnalyzerDiagnostics <TCompilation>( this TCompilation c, DiagnosticAnalyzer[] analyzers, TestValidationMode validationMode, AnalyzerOptions options = null, Action <Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null, bool logAnalyzerExceptionAsDiagnostics = true) where TCompilation : Compilation { ImmutableArray <DiagnosticAnalyzer> analyzersArray = analyzers.ToImmutableArray(); var exceptionDiagnostics = new ConcurrentSet <Diagnostic>(); if (onAnalyzerException == null) { if (logAnalyzerExceptionAsDiagnostics) { onAnalyzerException = (ex, analyzer, diagnostic) => { exceptionDiagnostics.Add(diagnostic); }; } else { // We want unit tests to throw if any analyzer OR the driver throws, unless the test explicitly provides a delegate. onAnalyzerException = FailFastOnAnalyzerException; } } Compilation newCompilation; AnalyzerDriver driver = AnalyzerDriver.CreateAndAttachToCompilation(c, analyzersArray, options, AnalyzerManager.Instance, onAnalyzerException, null, false, out newCompilation, CancellationToken.None); ImmutableArray <Diagnostic> diagnostics = newCompilation.GetDiagnostics(); if (validationMode != TestValidationMode.AllowCompileErrors) { ValidateNoCompileErrors(diagnostics); } return(driver.GetDiagnosticsAsync(newCompilation).Result.AddRange(exceptionDiagnostics)); }
private static TCompilation GetAnalyzerDiagnostics <TCompilation, TLanguageKindEnum>( this TCompilation c, Func <SyntaxNode, TLanguageKindEnum> getKind, DiagnosticAnalyzer[] analyzers, AnalyzerOptions options, Func <Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException, out ImmutableArray <Diagnostic> diagnostics) where TCompilation : Compilation where TLanguageKindEnum : struct { // We want unit tests to throw if any analyzer OR the driver throws, unless the test explicitly provides a delegate. continueOnAnalyzerException = continueOnAnalyzerException ?? DonotCatchAnalyzerExceptions; var driver = new AnalyzerDriver <TLanguageKindEnum>(analyzers.ToImmutableArray(), getKind, options, CancellationToken.None, continueOnAnalyzerException); c = (TCompilation)c.WithEventQueue(driver.CompilationEventQueue); var discarded = c.GetDiagnostics(); diagnostics = driver.GetDiagnosticsAsync().Result; return(c); // note this is a new compilation }
public void Verify() { Assert.AreEqual(descriptors.Count, locations.Count, "Source code specifies {0} locations; {1} diagnostics provided", locations.Count, descriptors.Count); var project = CreateProject(); var compilation = project.GetCompilationAsync().Result; var driver = AnalyzerDriver.Create(compilation, ImmutableArray.Create(analyzer), null, out compilation, CancellationToken.None); // TODO: Work out why this is needed. var discarded = compilation.GetDiagnostics(); var diags = driver.GetDiagnosticsAsync().Result; // TODO: Work out what the code in DiagnosticVerifier was doing here... it seems unnecessarily complicated. // TODO: Handle diagnostics with no location? var actual = diags .Select(SimplifiedDiagnostic.FromDiagnostic) .OrderBy(sd => sd.Location) .ToList(); var expected = descriptors.Zip(locations, (d, l) => d.WithLocation(l)).ToList(); CollectionAssert.AreEqual(expected, actual); }
public async Task GenerateSimulatedCompilationEventsAsync( AnalysisScope analysisScope, Compilation compilation, Func <SyntaxTree, Compilation, CancellationToken, SemanticModel> getCachedSemanticModel, AnalyzerDriver driver, CancellationToken cancellationToken) { await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken).ConfigureAwait(false); // Compilation started event. GenerateSimulatedCompilationNonSourceEvent(compilation, driver, started: true, cancellationToken: cancellationToken); // Symbol declared and compilation unit completed events. foreach (var tree in analysisScope.SyntaxTrees) { GenerateSimulatedCompilationSourceEvents(tree, compilation, getCachedSemanticModel, driver, cancellationToken); } // Compilation ended event. if (analysisScope.FilterTreeOpt == null) { GenerateSimulatedCompilationNonSourceEvent(compilation, driver, started: false, cancellationToken: cancellationToken); } }
private static void ReportAnalyzerExecutionTime(TextWriter consoleOutput, AnalyzerDriver analyzerDriver, CultureInfo culture, bool isConcurrentBuild) { Debug.Assert(analyzerDriver.AnalyzerExecutionTimes != null); if (analyzerDriver.AnalyzerExecutionTimes.IsEmpty) { return; } var totalAnalyzerExecutionTime = analyzerDriver.AnalyzerExecutionTimes.Sum(kvp => kvp.Value.TotalSeconds); Func <double, string> getFormattedTime = d => d.ToString("##0.000", culture); consoleOutput.WriteLine(); consoleOutput.WriteLine(string.Format(CodeAnalysisResources.AnalyzerTotalExecutionTime, getFormattedTime(totalAnalyzerExecutionTime))); if (isConcurrentBuild) { consoleOutput.WriteLine(CodeAnalysisResources.MultithreadedAnalyzerExecutionNote); } var analyzersByAssembly = analyzerDriver.AnalyzerExecutionTimes .GroupBy(kvp => kvp.Key.GetType().GetTypeInfo().Assembly) .OrderByDescending(kvp => kvp.Sum(entry => entry.Value.Ticks)); consoleOutput.WriteLine(); getFormattedTime = d => d < 0.001 ? string.Format(culture, "{0,8:<0.000}", 0.001) : string.Format(culture, "{0,8:##0.000}", d); Func <int, string> getFormattedPercentage = i => string.Format("{0,5}", i < 1 ? "<1" : i.ToString()); Func <string, string> getFormattedAnalyzerName = s => " " + s; // Table header var analyzerTimeColumn = string.Format("{0,8}", CodeAnalysisResources.AnalyzerExecutionTimeColumnHeader); var analyzerPercentageColumn = string.Format("{0,5}", "%"); var analyzerNameColumn = getFormattedAnalyzerName(CodeAnalysisResources.AnalyzerNameColumnHeader); consoleOutput.WriteLine(analyzerTimeColumn + analyzerPercentageColumn + analyzerNameColumn); // Table rows grouped by assembly. foreach (var analyzerGroup in analyzersByAssembly) { var executionTime = analyzerGroup.Sum(kvp => kvp.Value.TotalSeconds); var percentage = (int)(executionTime * 100 / totalAnalyzerExecutionTime); analyzerTimeColumn = getFormattedTime(executionTime); analyzerPercentageColumn = getFormattedPercentage(percentage); analyzerNameColumn = getFormattedAnalyzerName(analyzerGroup.Key.FullName); consoleOutput.WriteLine(analyzerTimeColumn + analyzerPercentageColumn + analyzerNameColumn); // Rows for each diagnostic analyzer in the assembly. foreach (var kvp in analyzerGroup.OrderByDescending(kvp => kvp.Value)) { executionTime = kvp.Value.TotalSeconds; percentage = (int)(executionTime * 100 / totalAnalyzerExecutionTime); analyzerTimeColumn = getFormattedTime(executionTime); analyzerPercentageColumn = getFormattedPercentage(percentage); analyzerNameColumn = getFormattedAnalyzerName(" " + kvp.Key.ToString()); consoleOutput.WriteLine(analyzerTimeColumn + analyzerPercentageColumn + analyzerNameColumn); } consoleOutput.WriteLine(); } }
private int RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, CancellationToken cancellationToken) { Debug.Assert(!Arguments.IsScriptRunner); cancellationToken.ThrowIfCancellationRequested(); if (Arguments.DisplayLogo) { PrintLogo(consoleOutput); } if (Arguments.DisplayHelp) { PrintHelp(consoleOutput); return(Succeeded); } if (ReportErrors(Arguments.Errors, consoleOutput, errorLogger)) { return(Failed); } var touchedFilesLogger = (Arguments.TouchedFilesPath != null) ? new TouchedFileLogger() : null; Compilation compilation = CreateCompilation(consoleOutput, touchedFilesLogger, errorLogger); if (compilation == null) { return(Failed); } var diagnostics = new List <DiagnosticInfo>(); ImmutableArray <DiagnosticAnalyzer> analyzers; ImmutableArray <SourceGenerator> sourceGenerators; ResolveAnalyzersAndGeneratorsFromArguments(diagnostics, MessageProvider, out analyzers, out sourceGenerators); var additionalTextFiles = ResolveAdditionalFilesFromArguments(diagnostics, MessageProvider, touchedFilesLogger); if (ReportErrors(diagnostics, consoleOutput, errorLogger)) { return(Failed); } bool reportAnalyzer = false; CancellationTokenSource analyzerCts = null; AnalyzerManager analyzerManager = null; AnalyzerDriver analyzerDriver = null; try { // Print the diagnostics produced during the parsing stage and exit if there were any errors. if (ReportErrors(compilation.GetParseDiagnostics(), consoleOutput, errorLogger)) { return(Failed); } if (!sourceGenerators.IsEmpty) { var trees = compilation.GenerateSource(sourceGenerators, this.Arguments.OutputDirectory, writeToDisk: true, cancellationToken: cancellationToken); if (!trees.IsEmpty) { compilation = compilation.AddSyntaxTrees(trees); if (ReportErrors(compilation.GetParseDiagnostics(), consoleOutput, errorLogger)) { return(Failed); } } } ConcurrentSet <Diagnostic> analyzerExceptionDiagnostics = null; if (!analyzers.IsEmpty) { analyzerCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); analyzerManager = new AnalyzerManager(); analyzerExceptionDiagnostics = new ConcurrentSet <Diagnostic>(); Action <Diagnostic> addExceptionDiagnostic = diagnostic => analyzerExceptionDiagnostics.Add(diagnostic); var analyzerOptions = new AnalyzerOptions(ImmutableArray <AdditionalText> .CastUp(additionalTextFiles)); analyzerDriver = AnalyzerDriver.CreateAndAttachToCompilation(compilation, analyzers, analyzerOptions, analyzerManager, addExceptionDiagnostic, Arguments.ReportAnalyzer, out compilation, analyzerCts.Token); reportAnalyzer = Arguments.ReportAnalyzer && !analyzers.IsEmpty; } if (ReportErrors(compilation.GetDeclarationDiagnostics(), consoleOutput, errorLogger)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); string outputName = GetOutputFileName(compilation, cancellationToken); var finalPeFilePath = Path.Combine(Arguments.OutputDirectory, outputName); var finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalPeFilePath, ".pdb"); var finalXmlFilePath = Arguments.DocumentationPath; var diagnosticBag = DiagnosticBag.GetInstance(); try { // NOTE: Unlike the PDB path, the XML doc path is not embedded in the assembly, so we don't need to pass it to emit. var emitOptions = Arguments.EmitOptions. WithOutputNameOverride(outputName). WithPdbFilePath(finalPdbFilePath); // The PDB path is emitted in it's entirety into the PE. This makes it impossible to have deterministic // builds that occur in different source directories. To enable this we shave all path information from // the PDB when specified by the user. // // This is a temporary work around to allow us to make progress with determinism. The following issue // tracks getting an official solution here. // // https://github.com/dotnet/roslyn/issues/9813 if (Arguments.ParseOptions.Features.ContainsKey("pdb-path-determinism") && !string.IsNullOrEmpty(emitOptions.PdbFilePath)) { emitOptions = emitOptions.WithPdbFilePath(Path.GetFileName(emitOptions.PdbFilePath)); } var moduleBeingBuilt = compilation.CheckOptionsAndCreateModuleBuilder( diagnosticBag, Arguments.ManifestResources, emitOptions, debugEntryPoint: null, testData: null, cancellationToken: cancellationToken); if (moduleBeingBuilt != null) { bool success; try { success = compilation.CompileMethods( moduleBeingBuilt, Arguments.EmitPdb, diagnosticBag, filterOpt: null, cancellationToken: cancellationToken); if (success) { // NOTE: as native compiler does, we generate the documentation file // NOTE: 'in place', replacing the contents of the file if it exists Stream xmlStreamOpt = null; if (finalXmlFilePath != null) { xmlStreamOpt = OpenFile(finalXmlFilePath, consoleOutput, PortableShim.FileMode.OpenOrCreate, PortableShim.FileAccess.Write, PortableShim.FileShare.ReadWriteBitwiseOrDelete); if (xmlStreamOpt == null) { return(Failed); } xmlStreamOpt.SetLength(0); } using (xmlStreamOpt) { IEnumerable <DiagnosticInfo> errors; using (var win32ResourceStreamOpt = GetWin32Resources(Arguments, compilation, out errors)) { if (ReportErrors(errors, consoleOutput, errorLogger)) { return(Failed); } success = compilation.GenerateResourcesAndDocumentationComments( moduleBeingBuilt, xmlStreamOpt, win32ResourceStreamOpt, diagnosticBag, cancellationToken); } // only report unused usings if we have success. if (success) { compilation.ReportUnusedImports(null, diagnosticBag, cancellationToken); } } } compilation.CompleteTrees(null); if (analyzerDriver != null) { // GetDiagnosticsAsync is called after ReportUnusedImports // since that method calls EventQueue.TryComplete. Without // TryComplete, we may miss diagnostics. var hostDiagnostics = analyzerDriver.GetDiagnosticsAsync(compilation).Result; diagnosticBag.AddRange(hostDiagnostics); if (hostDiagnostics.Any(IsReportedError)) { success = false; } } } finally { moduleBeingBuilt.CompilationFinished(); } if (success) { using (var peStreamProvider = new CompilerEmitStreamProvider(this, finalPeFilePath)) using (var pdbStreamProviderOpt = Arguments.EmitPdb ? new CompilerEmitStreamProvider(this, finalPdbFilePath) : null) { success = compilation.SerializeToPeStream( moduleBeingBuilt, peStreamProvider, pdbStreamProviderOpt, testSymWriterFactory: null, diagnostics: diagnosticBag, metadataOnly: emitOptions.EmitMetadataOnly, cancellationToken: cancellationToken); if (success && touchedFilesLogger != null) { if (pdbStreamProviderOpt != null) { touchedFilesLogger.AddWritten(finalPdbFilePath); } touchedFilesLogger.AddWritten(finalPeFilePath); } } } } var compileAndEmitDiagnostics = diagnosticBag.ToReadOnly(); GenerateSqmData(Arguments.CompilationOptions, compileAndEmitDiagnostics); if (ReportErrors(compileAndEmitDiagnostics, consoleOutput, errorLogger)) { return(Failed); } } finally { diagnosticBag.Free(); } cancellationToken.ThrowIfCancellationRequested(); if (analyzerExceptionDiagnostics != null && ReportErrors(analyzerExceptionDiagnostics, consoleOutput, errorLogger)) { return(Failed); } bool errorsReadingAdditionalFiles = false; foreach (var additionalFile in additionalTextFiles) { if (ReportErrors(additionalFile.Diagnostics, consoleOutput, errorLogger)) { errorsReadingAdditionalFiles = true; } } if (errorsReadingAdditionalFiles) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (Arguments.TouchedFilesPath != null) { Debug.Assert(touchedFilesLogger != null); if (finalXmlFilePath != null) { touchedFilesLogger.AddWritten(finalXmlFilePath); } var readStream = OpenFile(Arguments.TouchedFilesPath + ".read", consoleOutput, mode: PortableShim.FileMode.OpenOrCreate); if (readStream == null) { return(Failed); } using (var writer = new StreamWriter(readStream)) { touchedFilesLogger.WriteReadPaths(writer); } var writtenStream = OpenFile(Arguments.TouchedFilesPath + ".write", consoleOutput, mode: PortableShim.FileMode.OpenOrCreate); if (writtenStream == null) { return(Failed); } using (var writer = new StreamWriter(writtenStream)) { touchedFilesLogger.WriteWrittenPaths(writer); } } } finally { // At this point analyzers are already complete in which case this is a no-op. Or they are // still running because the compilation failed before all of the compilation events were // raised. In the latter case the driver, and all its associated state, will be waiting around // for events that are never coming. Cancel now and let the clean up process begin. if (analyzerCts != null) { analyzerCts.Cancel(); if (analyzerManager != null) { // Clear cached analyzer descriptors and unregister exception handlers hooked up to the LocalizableString fields of the associated descriptors. analyzerManager.ClearAnalyzerState(analyzers); } if (reportAnalyzer) { ReportAnalyzerExecutionTime(consoleOutput, analyzerDriver, Culture, compilation.Options.ConcurrentBuild); } } } return(Succeeded); }
private int RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, CancellationToken cancellationToken) { Debug.Assert(!Arguments.IsInteractive); cancellationToken.ThrowIfCancellationRequested(); if (Arguments.DisplayLogo) { PrintLogo(consoleOutput); } if (Arguments.DisplayHelp) { PrintHelp(consoleOutput); return(Succeeded); } if (ReportErrors(Arguments.Errors, consoleOutput, errorLogger)) { return(Failed); } var touchedFilesLogger = (Arguments.TouchedFilesPath != null) ? new TouchedFileLogger() : null; Compilation compilation = CreateCompilation(consoleOutput, touchedFilesLogger, errorLogger); if (compilation == null) { return(Failed); } var diagnostics = new List <DiagnosticInfo>(); var analyzers = ResolveAnalyzersFromArguments(diagnostics, MessageProvider, touchedFilesLogger); var additionalTextFiles = ResolveAdditionalFilesFromArguments(diagnostics, MessageProvider, touchedFilesLogger); if (ReportErrors(diagnostics, consoleOutput, errorLogger)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); CancellationTokenSource analyzerCts = null; AnalyzerManager analyzerManager = null; AnalyzerDriver analyzerDriver = null; try { Func <ImmutableArray <Diagnostic> > getAnalyzerDiagnostics = null; ConcurrentSet <Diagnostic> analyzerExceptionDiagnostics = null; if (!analyzers.IsDefaultOrEmpty) { analyzerCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); analyzerManager = new AnalyzerManager(); analyzerExceptionDiagnostics = new ConcurrentSet <Diagnostic>(); Action <Diagnostic> addExceptionDiagnostic = diagnostic => analyzerExceptionDiagnostics.Add(diagnostic); var analyzerOptions = new AnalyzerOptions(ImmutableArray <AdditionalText> .CastUp(additionalTextFiles)); analyzerDriver = AnalyzerDriver.Create(compilation, analyzers, analyzerOptions, analyzerManager, addExceptionDiagnostic, Arguments.ReportAnalyzer, out compilation, analyzerCts.Token); getAnalyzerDiagnostics = () => analyzerDriver.GetDiagnosticsAsync().Result; } // Print the diagnostics produced during the parsing stage and exit if there were any errors. if (ReportErrors(compilation.GetParseDiagnostics(), consoleOutput, errorLogger)) { return(Failed); } if (ReportErrors(compilation.GetDeclarationDiagnostics(), consoleOutput, errorLogger)) { return(Failed); } EmitResult emitResult; // NOTE: as native compiler does, we generate the documentation file // NOTE: 'in place', replacing the contents of the file if it exists string finalPeFilePath; string finalPdbFilePath; string finalXmlFilePath; Stream xmlStreamOpt = null; cancellationToken.ThrowIfCancellationRequested(); finalXmlFilePath = Arguments.DocumentationPath; if (finalXmlFilePath != null) { xmlStreamOpt = OpenFile(finalXmlFilePath, consoleOutput, PortableShim.FileMode.OpenOrCreate, PortableShim.FileAccess.Write, PortableShim.FileShare.ReadWriteBitwiseOrDelete); if (xmlStreamOpt == null) { return(Failed); } xmlStreamOpt.SetLength(0); } cancellationToken.ThrowIfCancellationRequested(); IEnumerable <DiagnosticInfo> errors; using (var win32ResourceStreamOpt = GetWin32Resources(Arguments, compilation, out errors)) using (xmlStreamOpt) { if (ReportErrors(errors, consoleOutput, errorLogger)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); string outputName = GetOutputFileName(compilation, cancellationToken); finalPeFilePath = Path.Combine(Arguments.OutputDirectory, outputName); finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalPeFilePath, ".pdb"); // NOTE: Unlike the PDB path, the XML doc path is not embedded in the assembly, so we don't need to pass it to emit. var emitOptions = Arguments.EmitOptions. WithOutputNameOverride(outputName). WithPdbFilePath(finalPdbFilePath); using (var peStreamProvider = new CompilerEmitStreamProvider(this, finalPeFilePath)) using (var pdbStreamProviderOpt = Arguments.EmitPdb ? new CompilerEmitStreamProvider(this, finalPdbFilePath) : null) { emitResult = compilation.Emit( peStreamProvider, pdbStreamProviderOpt, (xmlStreamOpt != null) ? new Compilation.SimpleEmitStreamProvider(xmlStreamOpt) : null, (win32ResourceStreamOpt != null) ? new Compilation.SimpleEmitStreamProvider(win32ResourceStreamOpt) : null, Arguments.ManifestResources, emitOptions, getAnalyzerDiagnostics, cancellationToken); if (emitResult.Success && touchedFilesLogger != null) { if (pdbStreamProviderOpt != null) { touchedFilesLogger.AddWritten(finalPdbFilePath); } touchedFilesLogger.AddWritten(finalPeFilePath); } } } GenerateSqmData(Arguments.CompilationOptions, emitResult.Diagnostics); if (ReportErrors(emitResult.Diagnostics, consoleOutput, errorLogger)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (analyzerExceptionDiagnostics != null && ReportErrors(analyzerExceptionDiagnostics, consoleOutput, errorLogger)) { return(Failed); } bool errorsReadingAdditionalFiles = false; foreach (var additionalFile in additionalTextFiles) { if (ReportErrors(additionalFile.Diagnostics, consoleOutput, errorLogger)) { errorsReadingAdditionalFiles = true; } } if (errorsReadingAdditionalFiles) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (Arguments.TouchedFilesPath != null) { Debug.Assert(touchedFilesLogger != null); if (finalXmlFilePath != null) { touchedFilesLogger.AddWritten(finalXmlFilePath); } var readStream = OpenFile(Arguments.TouchedFilesPath + ".read", consoleOutput, mode: PortableShim.FileMode.OpenOrCreate); if (readStream == null) { return(Failed); } using (var writer = new StreamWriter(readStream)) { touchedFilesLogger.WriteReadPaths(writer); } var writtenStream = OpenFile(Arguments.TouchedFilesPath + ".write", consoleOutput, mode: PortableShim.FileMode.OpenOrCreate); if (writtenStream == null) { return(Failed); } using (var writer = new StreamWriter(writtenStream)) { touchedFilesLogger.WriteWrittenPaths(writer); } } } finally { // At this point analyzers are already complete in which case this is a no-op. Or they are // still running because the compilation failed before all of the compilation events were // raised. In the latter case the driver, and all its associated state, will be waiting around // for events that are never coming. Cancel now and let the clean up process begin. if (analyzerCts != null) { analyzerCts.Cancel(); if (analyzerManager != null) { // Clear cached analyzer descriptors and unregister exception handlers hooked up to the LocalizableString fields of the associated descriptors. analyzerManager.ClearAnalyzerState(analyzers); } if (Arguments.ReportAnalyzer && analyzerDriver != null && compilation != null) { ReportAnalyzerExecutionTime(consoleOutput, analyzerDriver, Culture, compilation.Options.ConcurrentBuild); } } } return(Succeeded); }
/// <summary> /// csc.exe and vbc.exe entry point. /// </summary> public virtual int Run(TextWriter consoleOutput, CancellationToken cancellationToken) { Debug.Assert(!Arguments.IsInteractive); cancellationToken.ThrowIfCancellationRequested(); if (Arguments.DisplayLogo) { PrintLogo(consoleOutput); } if (Arguments.DisplayHelp) { PrintHelp(consoleOutput); return(Succeeded); } if (PrintErrors(Arguments.Errors, consoleOutput)) { return(Failed); } var touchedFilesLogger = (Arguments.TouchedFilesPath != null) ? new TouchedFileLogger() : null; Compilation compilation = CreateCompilation(consoleOutput, touchedFilesLogger); if (compilation == null) { return(Failed); } var diagnostics = new List <DiagnosticInfo>(); var analyzers = Arguments.ResolveAnalyzersFromArguments(diagnostics, MessageProvider, touchedFilesLogger); if (PrintErrors(diagnostics, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); EmitResult emitResult; // EDMAURER: Don't yet know if there are method body errors. don't overwrite // any existing output files until the compilation is known to be successful. string tempExeFilename = null; string tempPdbFilename = null; // NOTE: as native compiler does, we generate the documentation file // NOTE: 'in place', replacing the contents of the file if it exists try { tempExeFilename = CreateTempFile(consoleOutput); // Can happen when temp directory is "full" if (tempExeFilename == null) { return(Failed); } FileStream output = OpenFile(tempExeFilename, consoleOutput); if (output == null) { return(Failed); } string finalOutputPath; string finalPdbFilePath; string finalXmlFilePath; using (output) { FileStream pdb = null; FileStream xml = null; cancellationToken.ThrowIfCancellationRequested(); if (Arguments.CompilationOptions.DebugInformationKind != DebugInformationKind.None) { tempPdbFilename = CreateTempFile(consoleOutput); if (tempPdbFilename == null) { return(Failed); } pdb = OpenFile(tempPdbFilename, consoleOutput); if (pdb == null) { return(Failed); } } cancellationToken.ThrowIfCancellationRequested(); finalXmlFilePath = Arguments.DocumentationPath; if (finalXmlFilePath != null) { xml = OpenFile(finalXmlFilePath, consoleOutput, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete); if (xml == null) { return(Failed); } xml.SetLength(0); } cancellationToken.ThrowIfCancellationRequested(); IEnumerable <DiagnosticInfo> errors; using (var win32Res = GetWin32Resources(Arguments, compilation, out errors)) using (pdb) using (xml) { if (PrintErrors(errors, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); string outputName = GetOutputFileName(compilation, cancellationToken); finalOutputPath = Path.Combine(Arguments.OutputDirectory, outputName); finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalOutputPath, ".pdb"); // NOTE: Unlike the PDB path, the XML doc path is not embedded in the assembly, so we don't need to pass it to emit. emitResult = compilation.Emit(output, outputName, finalPdbFilePath, pdb, xml, cancellationToken, win32Res, Arguments.ManifestResources); } } GenerateSqmData(Arguments.CompilationOptions, emitResult.Diagnostics); if (PrintErrors(emitResult.Diagnostics, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); var analyzerDiagnostics = AnalyzerDriver.GetDiagnostics(compilation, analyzers, default(CancellationToken)); if (PrintErrors(analyzerDiagnostics, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (!TryDeleteFile(finalOutputPath, consoleOutput) || !TryMoveFile(tempExeFilename, finalOutputPath, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (tempPdbFilename != null) { if (!TryDeleteFile(finalPdbFilePath, consoleOutput) || !TryMoveFile(tempPdbFilename, finalPdbFilePath, consoleOutput)) { return(Failed); } } cancellationToken.ThrowIfCancellationRequested(); if (Arguments.TouchedFilesPath != null) { Debug.Assert(touchedFilesLogger != null); touchedFilesLogger.AddWritten(tempExeFilename); touchedFilesLogger.AddWritten(finalOutputPath); if (tempPdbFilename != null) { touchedFilesLogger.AddWritten(tempPdbFilename); touchedFilesLogger.AddWritten(finalPdbFilePath); } if (finalXmlFilePath != null) { touchedFilesLogger.AddWritten(finalXmlFilePath); } var readStream = OpenFile(Arguments.TouchedFilesPath + ".read", consoleOutput, FileMode.OpenOrCreate); if (readStream == null) { return(Failed); } using (var writer = new StreamWriter(readStream)) { touchedFilesLogger.WriteReadPaths(writer); } var writtenStream = OpenFile(Arguments.TouchedFilesPath + ".write", consoleOutput, FileMode.OpenOrCreate); if (writtenStream == null) { return(Failed); } using (var writer = new StreamWriter(writtenStream)) { touchedFilesLogger.WriteWrittenPaths(writer); } } return(Succeeded); } finally { if (tempExeFilename != null) { TryDeleteFile(tempExeFilename, consoleOutput: null); } if (tempPdbFilename != null) { TryDeleteFile(tempPdbFilename, consoleOutput: null); } } }
static void SingleStatementBodyAnalyzerTest() { // // Construct a syntax tree and a compilation. // var tree = CSharpSyntaxTree.ParseText(@" using System; class Foo { void If(int x) { if (x > 0) Console.WriteLine(x); else if (x == 0) Console.WriteLine(0); else if (x < 0) Console.WriteLine(-x); } void For() { for (int i = 0; i < 10; i++) Console.WriteLine(i); } void ForEach() { foreach (var x in new[] { 1, 2, 3 }) Console.WriteLine(x); } void While() { while (true) Console.Write('.'); } }"); var mscorlib = new MetadataFileReference(typeof(object).Assembly.Location); var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); var comp = CSharpCompilation.Create("Demo") .AddSyntaxTrees(tree) .AddReferences(mscorlib) .WithOptions(options); // // Get diagnostics. // var diags = AnalyzerDriver.GetDiagnostics(comp, new[] { new SingleStatementBodyAnalyzer() }, null, CancellationToken.None); foreach (var diag in diags) { Console.WriteLine(diag); } }
public void AnalyzerDriverIsSafeAgainstAnalyzerExceptions() { var compilation = CreateCompilationWithMscorlib45(TestResource.AllInOneCSharpCode); ThrowingDiagnosticAnalyzer <SyntaxKind> .VerifyAnalyzerEngineIsSafeAgainstExceptions(analyzer => AnalyzerDriver.GetDiagnostics(compilation, new[] { analyzer }, CancellationToken.None), typeof(AnalyzerDriver).Name); }