private static async Task<IEnumerable<DiagnosticData>> GetSyntaxDiagnosticsAsync(ProviderId providerId, DiagnosticAnalyzer provider, DiagnosticAnalyzerDriver userDiagnosticDriver) { using (Logger.LogBlock(FunctionId.Diagnostics_SyntaxDiagnostic, GetSyntaxLogMessage, userDiagnosticDriver.Document, userDiagnosticDriver.Span, providerId, userDiagnosticDriver.CancellationToken)) { try { Contract.ThrowIfNull(provider); var diagnostics = await userDiagnosticDriver.GetSyntaxDiagnosticsAsync(provider).ConfigureAwait(false); return GetDiagnosticData(userDiagnosticDriver.Document, userDiagnosticDriver.Span, diagnostics); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } }
private static IEnumerable<Diagnostic> GetDiagnostics(DiagnosticAnalyzer analyzerOpt, Document document, TextSpan span, Project project, bool getDocumentDiagnostics, bool getProjectDiagnostics, bool donotCatchAnalyzerExceptions) { var documentDiagnostics = SpecializedCollections.EmptyEnumerable<Diagnostic>(); var projectDiagnostics = SpecializedCollections.EmptyEnumerable<Diagnostic>(); // If no user diagnostic analyzer, then test compiler diagnostics. var analyzer = analyzerOpt ?? DiagnosticExtensions.GetCompilerDiagnosticAnalyzer(project.Language); if (getDocumentDiagnostics) { var tree = document.GetSyntaxTreeAsync().Result; var root = document.GetSyntaxRootAsync().Result; var semanticModel = document.GetSemanticModelAsync().Result; var builder = new List<Diagnostic>(); var nodeInBodyAnalyzerService = document.Project.Language == LanguageNames.CSharp ? (ISyntaxNodeAnalyzerService)new CSharpSyntaxNodeAnalyzerService() : new VisualBasicSyntaxNodeAnalyzerService(); // Lets replicate the IDE diagnostic incremental analyzer behavior to determine span to test: // (a) If the span is contained within a method level member and analyzer supports semantic in span: analyze in member span. // (b) Otherwise, analyze entire syntax tree span. var spanToTest = root.FullSpan; var driver = new DiagnosticAnalyzerDriver(document, spanToTest, root, syntaxNodeAnalyzerService: nodeInBodyAnalyzerService, cancellationToken: CancellationToken.None, testOnly_DonotCatchAnalyzerExceptions: donotCatchAnalyzerExceptions); var diagnosticAnalyzerCategory = analyzer.GetDiagnosticAnalyzerCategory(driver); bool supportsSemanticInSpan = (diagnosticAnalyzerCategory & DiagnosticAnalyzerCategory.SemanticSpanAnalysis) != 0; if (supportsSemanticInSpan) { var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>(); if (syntaxFacts != null) { var member = syntaxFacts.GetContainingMemberDeclaration(root, span.Start); if (member != null && syntaxFacts.IsMethodLevelMember(member) && member.FullSpan.Contains(span)) { spanToTest = member.FullSpan; } } } if ((diagnosticAnalyzerCategory & DiagnosticAnalyzerCategory.SyntaxAnalysis) != 0) { builder.AddRange(driver.GetSyntaxDiagnosticsAsync(analyzer).Result ?? SpecializedCollections.EmptyEnumerable<Diagnostic>()); } if (supportsSemanticInSpan || (diagnosticAnalyzerCategory & DiagnosticAnalyzerCategory.SemanticDocumentAnalysis) != 0) { builder.AddRange(driver.GetSemanticDiagnosticsAsync(analyzer).Result ?? SpecializedCollections.EmptyEnumerable<Diagnostic>()); } documentDiagnostics = builder.Where(d => d.Location == Location.None || (d.Location.SourceTree == tree && d.Location.SourceSpan.IntersectsWith(span))); } if (getProjectDiagnostics) { var nodeInBodyAnalyzerService = project.Language == LanguageNames.CSharp ? (ISyntaxNodeAnalyzerService)new CSharpSyntaxNodeAnalyzerService() : new VisualBasicSyntaxNodeAnalyzerService(); var driver = new DiagnosticAnalyzerDriver(project, nodeInBodyAnalyzerService, CancellationToken.None); if (analyzer.SupportsProjectDiagnosticAnalysis(driver)) { projectDiagnostics = driver.GetProjectDiagnosticsAsync(analyzer, null).Result ?? SpecializedCollections.EmptyEnumerable<Diagnostic>(); } } return documentDiagnostics.Concat(projectDiagnostics); }