public static DiagnosticAnalyzerCategory GetDiagnosticAnalyzerCategory(this DiagnosticAnalyzer analyzer, DiagnosticAnalyzerDriver driver) { var category = DiagnosticAnalyzerCategory.None; if (analyzer is DocumentDiagnosticAnalyzer) { category |= DiagnosticAnalyzerCategory.SyntaxAnalysis | DiagnosticAnalyzerCategory.SemanticDocumentAnalysis; } else if (analyzer is ProjectDiagnosticAnalyzer) { category |= DiagnosticAnalyzerCategory.ProjectAnalysis; } else if (driver != null) { // If an analyzer requires or might require the entire document, then it cannot promise // to be able to operate on a limited span of the document. In practical terms, no analyzer // can have both SemanticDocumentAnalysis and SemanticSpanAnalysis as categories. bool cantSupportSemanticSpanAnalysis = false; var analyzerActions = driver.GetSessionAnalyzerActions(analyzer); if (analyzerActions != null) { if (analyzerActions.SyntaxTreeActionsCount > 0) { category |= DiagnosticAnalyzerCategory.SyntaxAnalysis; } if (analyzerActions.SemanticModelActionsCount > 0) { category |= DiagnosticAnalyzerCategory.SemanticDocumentAnalysis; cantSupportSemanticSpanAnalysis = true; } if (analyzerActions.CompilationStartActionsCount > 0) { // It is not possible to know what actions a compilation start action will register without executing it, // so return a worst-case categorization. category |= DiagnosticAnalyzerCategory.SyntaxAnalysis | DiagnosticAnalyzerCategory.SemanticDocumentAnalysis | DiagnosticAnalyzerCategory.ProjectAnalysis; cantSupportSemanticSpanAnalysis = true; } if (analyzerActions.CompilationEndActionsCount > 0 || analyzerActions.CompilationStartActionsCount > 0) { category |= DiagnosticAnalyzerCategory.ProjectAnalysis; } if (!cantSupportSemanticSpanAnalysis) { if (analyzerActions.SymbolActionsCount > 0 || analyzerActions.CodeBlockStartActionsCount > 0 || analyzerActions.CodeBlockEndActionsCount > 0 || analyzerActions.SyntaxNodeActionsCount > 0) { category |= DiagnosticAnalyzerCategory.SemanticSpanAnalysis; } } } } return category; }
private static bool CheckTelemetry(DiagnosticAnalyzerService service, DiagnosticAnalyzer analyzer) { if (DiagnosticAnalyzerDriver.IsCompilerAnalyzer(analyzer)) { return(true); } ImmutableArray <DiagnosticDescriptor> diagDescriptors; try { // SupportedDiagnostics is potentially user code and can throw an exception. diagDescriptors = service != null?service.GetDiagnosticDescriptors(analyzer) : analyzer.SupportedDiagnostics; } catch (Exception) { return(false); } if (diagDescriptors == null) { return(false); } // find if the first diagnostic in this analyzer allows telemetry DiagnosticDescriptor diagnostic = diagDescriptors.Length > 0 ? diagDescriptors[0] : null; return(diagnostic == null ? false : diagnostic.CustomTags.Any(t => t == WellKnownDiagnosticTags.Telemetry)); }
public async Task<AnalysisData> GetDocumentBodyAnalysisDataAsync( DiagnosticAnalyzer provider, ProviderId providerId, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDriver, SyntaxNode root, SyntaxNode member, int memberId, bool supportsSemanticInSpan, MemberRangeMap.MemberRanges ranges) { try { var document = analyzerDriver.Document; var cancellationToken = analyzerDriver.CancellationToken; var state = AnalyzersAndState.GetOrCreateDiagnosticState(StateType.Document, providerId, provider, document.Project.Id, document.Project.Language); var existingData = await state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false); ImmutableArray<DiagnosticData> diagnosticData; if (supportsSemanticInSpan && CanUseDocumentState(existingData, ranges.TextVersion, versions.DataVersion)) { var memberDxData = await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDriver).ConfigureAwait(false); diagnosticData = _owner.UpdateDocumentDiagnostics(existingData, ranges.Ranges, memberDxData.AsImmutableOrEmpty(), root.SyntaxTree, member, memberId); ValidateMemberDiagnostics(providerId, provider, document, root, diagnosticData); } else { // if we can't re-use existing document state, only option we have is updating whole document state here. var dx = await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDriver).ConfigureAwait(false); diagnosticData = dx.AsImmutableOrEmpty(); } return new AnalysisData(versions.TextVersion, versions.DataVersion, GetExistingItems(existingData), diagnosticData); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
public static bool SupportsSemanticDiagnosticAnalysis(this DiagnosticAnalyzer analyzer, DiagnosticAnalyzerDriver driver, out bool supportsSemanticSpanAnalysis) { var category = analyzer.GetDiagnosticAnalyzerCategory(driver); supportsSemanticSpanAnalysis = (category & DiagnosticAnalyzerCategory.SemanticSpanAnalysis) != 0; return supportsSemanticSpanAnalysis || (category & DiagnosticAnalyzerCategory.SemanticDocumentAnalysis) != 0; }
private void ValidateMemberDiagnostics(ProviderId providerId, DiagnosticAnalyzer provider, Document document, SyntaxNode root, ImmutableArray <DiagnosticData> diagnostics) { #if RANGE var documentBasedDriver = new DiagnosticAnalyzerDriver(document, root.FullSpan, root, CancellationToken.None); var expected = GetSemanticDiagnosticsAsync(providerId, provider, documentBasedDriver).WaitAndGetResult(documentBasedDriver.CancellationToken) ?? SpecializedCollections.EmptyEnumerable <DiagnosticData>(); Contract.Requires(diagnostics.SetEquals(expected)); #endif }
public async Task<AnalysisData> GetDocumentAnalysisDataAsync( DiagnosticAnalyzer provider, ProviderId providerId, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDrvier) { try { var document = analyzerDrvier.Document; var cancellationToken = analyzerDrvier.CancellationToken; var state = AnalyzersAndState.GetOrCreateDiagnosticState(StateType.Document, providerId, provider, document.Project.Id, document.Project.Language); var existingData = await state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false); if (CheckSemanticVersions(document, existingData, versions)) { return existingData; } var diagnosticData = await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDrvier).ConfigureAwait(false); return new AnalysisData(versions.TextVersion, versions.DataVersion, GetExistingItems(existingData), diagnosticData.AsImmutableOrEmpty()); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private async Task AnalyzeBodyDocumentAsync(Document document, SyntaxNode member, VersionArgument versions, CancellationToken cancellationToken) { try { // syntax facts service must exist, otherwise, this method won't have called. var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>(); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var memberId = syntaxFacts.GetMethodLevelMemberId(root, member); var spanBasedDriver = new DiagnosticAnalyzerDriver(document, member.FullSpan, root, _diagnosticLogAggregator, cancellationToken); var documentBasedDriver = new DiagnosticAnalyzerDriver(document, root.FullSpan, root, _diagnosticLogAggregator, cancellationToken); var options = document.Project.CompilationOptions; foreach (var providerAndId in await _analyzersAndState.GetAllProviderAndIdsAsync(document.Project, cancellationToken).ConfigureAwait(false)) { var provider = providerAndId.Key; var providerId = providerAndId.Value; bool supportsSemanticInSpan; if (IsAnalyzerSuppressed(provider, options, spanBasedDriver)) { await HandleSuppressedAnalyzerAsync(document, StateType.Document, providerId, provider, cancellationToken).ConfigureAwait(false); } else if (ShouldRunProviderForStateType(StateType.Document, provider, spanBasedDriver, out supportsSemanticInSpan)) { var userDiagnosticDriver = supportsSemanticInSpan ? spanBasedDriver : documentBasedDriver; var ranges = _memberRangeMap.GetSavedMemberRange(providerId, document); var data = await _executor.GetDocumentBodyAnalysisDataAsync( provider, providerId, versions, userDiagnosticDriver, root, member, memberId, supportsSemanticInSpan, ranges).ConfigureAwait(false); _memberRangeMap.UpdateMemberRange(providerId, document, versions.TextVersion, memberId, member.FullSpan, ranges); var state = _analyzersAndState.GetOrCreateDiagnosticState(StateType.Document, providerId, provider, document.Project.Id, document.Project.Language); await state.PersistAsync(document, data.ToPersistData(), cancellationToken).ConfigureAwait(false); if (data.FromCache) { RaiseDiagnosticsUpdated(StateType.Document, document.Id, providerId, new SolutionArgument(document), data.Items); continue; } RaiseDiagnosticsUpdatedIfNeeded(StateType.Document, document, providerId, data.OldItems, data.Items); } } } 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); }
public static bool SupportsProjectDiagnosticAnalysis(this DiagnosticAnalyzer analyzer, DiagnosticAnalyzerDriver driver) { var category = analyzer.GetDiagnosticAnalyzerCategory(driver); return (category & DiagnosticAnalyzerCategory.ProjectAnalysis) != 0; }
public async Task<AnalysisData> GetProjectAnalysisDataAsync( DiagnosticAnalyzer provider, ProviderId providerId, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDriver) { try { var project = analyzerDriver.Project; var cancellationToken = analyzerDriver.CancellationToken; var state = AnalyzersAndState.GetOrCreateDiagnosticState(StateType.Project, providerId, provider, project.Id, project.Language); var existingData = await state.TryGetExistingDataAsync(project, cancellationToken).ConfigureAwait(false); if (CheckSemanticVersions(project, existingData, versions)) { return existingData; } // TODO: remove ForceAnalyzeAllDocuments at some point var diagnosticData = await GetProjectDiagnosticsAsync(providerId, provider, analyzerDriver, _owner.ForceAnalyzeAllDocuments).ConfigureAwait(false); return new AnalysisData(VersionStamp.Default, versions.DataVersion, GetExistingItems(existingData), diagnosticData.AsImmutableOrEmpty()); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private static async Task<IEnumerable<DiagnosticData>> GetProjectDiagnosticsAsync(ProviderId providerId, DiagnosticAnalyzer provider, DiagnosticAnalyzerDriver userDiagnosticDriver, Action<Project, DiagnosticAnalyzer, CancellationToken> forceAnalyzeAllDocuments) { using (Logger.LogBlock(FunctionId.Diagnostics_ProjectDiagnostic, GetProjectLogMessage, userDiagnosticDriver.Project, providerId, userDiagnosticDriver.CancellationToken)) { try { Contract.ThrowIfNull(provider); var diagnostics = await userDiagnosticDriver.GetProjectDiagnosticsAsync(provider, forceAnalyzeAllDocuments).ConfigureAwait(false); return GetDiagnosticData(userDiagnosticDriver.Project, diagnostics); } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } } }
private static bool ShouldRunProviderForStateType(StateType stateTypeId, DiagnosticAnalyzer provider, DiagnosticAnalyzerDriver driver, out bool supportsSemanticInSpan, ImmutableHashSet<string> diagnosticIds = null, Func<DiagnosticAnalyzer, ImmutableArray<DiagnosticDescriptor>> getDescriptor = null) { Debug.Assert(!IsAnalyzerSuppressed(provider, driver.Project.CompilationOptions, driver)); supportsSemanticInSpan = false; if (diagnosticIds != null && getDescriptor(provider).All(d => !diagnosticIds.Contains(d.Id))) { return false; } switch (stateTypeId) { case StateType.Syntax: return provider.SupportsSyntaxDiagnosticAnalysis(driver); case StateType.Document: return provider.SupportsSemanticDiagnosticAnalysis(driver, out supportsSemanticInSpan); case StateType.Project: return provider.SupportsProjectDiagnosticAnalysis(driver); default: throw ExceptionUtilities.Unreachable; } }
private bool ShouldRunProviderForStateType(StateType stateTypeId, DiagnosticAnalyzer provider, DiagnosticAnalyzerDriver driver, ImmutableHashSet<string> diagnosticIds) { return ShouldRunProviderForStateType(stateTypeId, provider, driver, diagnosticIds, _owner.GetDiagnosticDescriptors); }
private async Task<bool> TryGetLatestDiagnosticsAsync( StateType stateType, Document document, TextSpan range, SyntaxNode root, List<DiagnosticData> diagnostics, bool requireUpToDateDocumentDiagnostic, Func<VersionStamp, VersionStamp, bool> versionCheck, Func<ProviderId, DiagnosticAnalyzer, DiagnosticAnalyzerDriver, Task<IEnumerable<DiagnosticData>>> getDiagnostics, CancellationToken cancellationToken) { try { bool result = true; var fullSpan = root == null ? null : (TextSpan?)root.FullSpan; // Share the diagnostic analyzer driver across all analyzers. var spanBasedDriver = new DiagnosticAnalyzerDriver(document, range, root, _diagnosticLogAggregator, cancellationToken); var documentBasedDriver = new DiagnosticAnalyzerDriver(document, fullSpan, root, _diagnosticLogAggregator, cancellationToken); var options = document.Project.CompilationOptions; foreach (var providerAndId in await _analyzersAndState.GetAllProviderAndIdsAsync(document.Project, cancellationToken).ConfigureAwait(false)) { var provider = providerAndId.Key; var providerId = providerAndId.Value; bool supportsSemanticInSpan; if (!IsAnalyzerSuppressed(provider, options, spanBasedDriver) && ShouldRunProviderForStateType(stateType, provider, spanBasedDriver, out supportsSemanticInSpan)) { var userDiagnosticDriver = supportsSemanticInSpan ? spanBasedDriver : documentBasedDriver; result &= await TryGetLatestDiagnosticsAsync( provider, providerId, stateType, document, range, root, diagnostics, requireUpToDateDocumentDiagnostic, versionCheck, getDiagnostics, supportsSemanticInSpan, userDiagnosticDriver, cancellationToken).ConfigureAwait(false); } } return result; } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private async Task AnalyzeDocumentAsync(Document document, VersionArgument versions, ImmutableHashSet<string> diagnosticIds, bool skipClosedFileChecks, CancellationToken cancellationToken) { try { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var fullSpan = root == null ? null : (TextSpan?)root.FullSpan; var userDiagnosticDriver = new DiagnosticAnalyzerDriver(document, fullSpan, root, _diagnosticLogAggregator, cancellationToken); bool openedDocument = document.IsOpen(); var options = document.Project.CompilationOptions; foreach (var providerAndId in await _analyzersAndState.GetAllProviderAndIdsAsync(document.Project, cancellationToken).ConfigureAwait(false)) { var provider = providerAndId.Key; var providerId = providerAndId.Value; if (IsAnalyzerSuppressed(provider, options, userDiagnosticDriver)) { await HandleSuppressedAnalyzerAsync(document, StateType.Document, providerId, provider, cancellationToken).ConfigureAwait(false); } else if (ShouldRunProviderForStateType(StateType.Document, provider, userDiagnosticDriver, diagnosticIds) && (skipClosedFileChecks || ShouldRunProviderForClosedFile(openedDocument, provider))) { var data = await _executor.GetDocumentAnalysisDataAsync(provider, providerId, versions, userDiagnosticDriver).ConfigureAwait(false); if (data.FromCache) { RaiseDiagnosticsUpdated(StateType.Document, document.Id, providerId, new SolutionArgument(document), data.Items); continue; } if (openedDocument) { _memberRangeMap.Touch(providerId, document, versions.TextVersion); } var state = _analyzersAndState.GetOrCreateDiagnosticState(StateType.Document, providerId, provider, document.Project.Id, document.Project.Language); await state.PersistAsync(document, data.ToPersistData(), cancellationToken).ConfigureAwait(false); RaiseDiagnosticsUpdatedIfNeeded(StateType.Document, document, providerId, data.OldItems, data.Items); } } } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
public async Task <AnalysisData> GetProjectAnalysisDataAsync( DiagnosticAnalyzer provider, ProviderId providerId, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDriver) { try { var project = analyzerDriver.Project; var cancellationToken = analyzerDriver.CancellationToken; var state = AnalyzersAndState.GetOrCreateDiagnosticState(StateType.Project, providerId, provider, project.Id, project.Language); var existingData = await state.TryGetExistingDataAsync(project, cancellationToken).ConfigureAwait(false); if (CheckSemanticVersions(project, existingData, versions)) { return(existingData); } // TODO: remove ForceAnalyzeAllDocuments at some point var diagnosticData = await GetProjectDiagnosticsAsync(providerId, provider, analyzerDriver, _owner.ForceAnalyzeAllDocuments).ConfigureAwait(false); return(new AnalysisData(VersionStamp.Default, versions.DataVersion, GetExistingItems(existingData), diagnosticData.AsImmutableOrEmpty())); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
protected override Task <AnalysisData> GetSpecificDiagnosticsAsync( Solution solution, DiagnosticAnalyzer provider, ProviderId providerId, StateType stateType, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDriver) { switch (stateType) { case StateType.Syntax: return(this.AnalyzerExecutor.GetSyntaxAnalysisDataAsync(provider, providerId, versions, analyzerDriver)); case StateType.Document: return(this.AnalyzerExecutor.GetDocumentAnalysisDataAsync(provider, providerId, versions, analyzerDriver)); case StateType.Project: return(this.AnalyzerExecutor.GetProjectAnalysisDataAsync(provider, providerId, versions, analyzerDriver)); default: return(Contract.FailWithReturn <Task <AnalysisData> >("Can't reach here")); } }
protected override async Task <AnalysisData> GetSpecificDiagnosticsAsync( Solution solution, DiagnosticAnalyzer provider, int providerId, StateType stateType, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDriver) { // we don't care about result switch (stateType) { case StateType.Syntax: await GetSyntaxDiagnosticsAsync(providerId, provider, analyzerDriver).ConfigureAwait(false); break; case StateType.Document: await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDriver).ConfigureAwait(false); break; case StateType.Project: default: return(Contract.FailWithReturn <AnalysisData>("Can't reach here")); } return(AnalysisData.Empty); }
protected abstract Task <AnalysisData> GetSpecificDiagnosticsAsync(Solution solution, DiagnosticAnalyzer provider, ProviderId providerId, StateType stateType, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDriver);
private void ValidateMemberDiagnostics(ProviderId providerId, DiagnosticAnalyzer provider, Document document, SyntaxNode root, ImmutableArray<DiagnosticData> diagnostics) { #if RANGE var documentBasedDriver = new DiagnosticAnalyzerDriver(document, root.FullSpan, root, CancellationToken.None); var expected = GetSemanticDiagnosticsAsync(providerId, provider, documentBasedDriver).WaitAndGetResult(documentBasedDriver.CancellationToken) ?? SpecializedCollections.EmptyEnumerable<DiagnosticData>(); Contract.Requires(diagnostics.SetEquals(expected)); #endif }
private async Task AnalyzeProjectAsync(Project project, ImmutableHashSet<string> diagnosticIds, bool skipClosedFileChecks, CancellationToken cancellationToken) { try { if (!skipClosedFileChecks && !CheckOption(project.Solution.Workspace, project.Language, documentOpened: project.Documents.Any(d => d.IsOpen()))) { return; } var projectVersion = await project.GetDependentVersionAsync(cancellationToken).ConfigureAwait(false); var semanticVersion = await project.GetDependentSemanticVersionAsync(cancellationToken).ConfigureAwait(false); var userDiagnosticDriver = new DiagnosticAnalyzerDriver(project, _diagnosticLogAggregator, cancellationToken); var options = project.CompilationOptions; var versions = new VersionArgument(VersionStamp.Default, semanticVersion, projectVersion); foreach (var providerAndId in await _analyzersAndState.GetAllProviderAndIdsAsync(project, cancellationToken).ConfigureAwait(false)) { var provider = providerAndId.Key; var providerId = providerAndId.Value; if (IsAnalyzerSuppressed(provider, options, userDiagnosticDriver)) { await HandleSuppressedAnalyzerAsync(project, providerId, provider, cancellationToken).ConfigureAwait(false); } else if (ShouldRunProviderForStateType(StateType.Project, provider, userDiagnosticDriver, diagnosticIds) && (skipClosedFileChecks || ShouldRunProviderForClosedFile(openedDocument: false, provider: provider))) { var data = await _executor.GetProjectAnalysisDataAsync(provider, providerId, versions, userDiagnosticDriver).ConfigureAwait(false); if (data.FromCache) { RaiseDiagnosticsUpdated(StateType.Project, project.Id, providerId, new SolutionArgument(project), data.Items); continue; } var state = _analyzersAndState.GetOrCreateDiagnosticState(StateType.Project, providerId, provider, project.Id, project.Language); await state.PersistAsync(project, data.ToPersistData(), cancellationToken).ConfigureAwait(false); RaiseDiagnosticsUpdatedIfNeeded(project, providerId, data.OldItems, data.Items); } } } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
public async Task <AnalysisData> GetDocumentAnalysisDataAsync( DiagnosticAnalyzer provider, ProviderId providerId, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDrvier) { try { var document = analyzerDrvier.Document; var cancellationToken = analyzerDrvier.CancellationToken; var state = AnalyzersAndState.GetOrCreateDiagnosticState(StateType.Document, providerId, provider, document.Project.Id, document.Project.Language); var existingData = await state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false); if (CheckSemanticVersions(document, existingData, versions)) { return(existingData); } var diagnosticData = await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDrvier).ConfigureAwait(false); return(new AnalysisData(versions.TextVersion, versions.DataVersion, GetExistingItems(existingData), diagnosticData.AsImmutableOrEmpty())); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private async Task<bool> TryGetLatestDiagnosticsAsync( DiagnosticAnalyzer provider, ProviderId providerId, StateType stateType, Document document, TextSpan range, SyntaxNode root, List<DiagnosticData> diagnostics, bool requireUpToDateDocumentDiagnostic, Func<VersionStamp, VersionStamp, bool> versionCheck, Func<ProviderId, DiagnosticAnalyzer, DiagnosticAnalyzerDriver, Task<IEnumerable<DiagnosticData>>> getDiagnostics, bool supportsSemanticInSpan, DiagnosticAnalyzerDriver userDiagnosticDriver, CancellationToken cancellationToken) { try { var shouldInclude = (Func<DiagnosticData, bool>)(d => range.IntersectsWith(d.TextSpan)); // make sure we get state even when none of our analyzer has ran yet. // but this shouldn't create analyzer that doesnt belong to this project (language) var state = _analyzersAndState.GetOrCreateDiagnosticState(stateType, providerId, provider, document.Project.Id, document.Project.Language); if (state == null) { if (!requireUpToDateDocumentDiagnostic) { // the provider never ran yet. return true; } } else { // see whether we can use existing info var existingData = await state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false); if (existingData != null && versionCheck(existingData.TextVersion, existingData.DataVersion)) { if (existingData.Items == null) { return true; } diagnostics.AddRange(existingData.Items.Where(shouldInclude)); return true; } } // check whether we want up-to-date document wide diagnostics if (stateType == StateType.Document && !supportsSemanticInSpan && !requireUpToDateDocumentDiagnostic) { return false; } var dx = await getDiagnostics(providerId, provider, userDiagnosticDriver).ConfigureAwait(false); if (dx != null) { // no state yet diagnostics.AddRange(dx.Where(shouldInclude)); } return true; } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
public async Task <AnalysisData> GetDocumentBodyAnalysisDataAsync( DiagnosticAnalyzer provider, ProviderId providerId, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDriver, SyntaxNode root, SyntaxNode member, int memberId, bool supportsSemanticInSpan, MemberRangeMap.MemberRanges ranges) { try { var document = analyzerDriver.Document; var cancellationToken = analyzerDriver.CancellationToken; var state = AnalyzersAndState.GetOrCreateDiagnosticState(StateType.Document, providerId, provider, document.Project.Id, document.Project.Language); var existingData = await state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false); ImmutableArray <DiagnosticData> diagnosticData; if (supportsSemanticInSpan && CanUseDocumentState(existingData, ranges.TextVersion, versions.DataVersion)) { var memberDxData = await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDriver).ConfigureAwait(false); diagnosticData = _owner.UpdateDocumentDiagnostics(existingData, ranges.Ranges, memberDxData.AsImmutableOrEmpty(), root.SyntaxTree, member, memberId); ValidateMemberDiagnostics(providerId, provider, document, root, diagnosticData); } else { // if we can't re-use existing document state, only option we have is updating whole document state here. var dx = await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDriver).ConfigureAwait(false); diagnosticData = dx.AsImmutableOrEmpty(); } return(new AnalysisData(versions.TextVersion, versions.DataVersion, GetExistingItems(existingData), diagnosticData)); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private static bool ShouldRunProviderForStateType(StateType stateTypeId, DiagnosticAnalyzer provider, DiagnosticAnalyzerDriver driver, ImmutableHashSet<string> diagnosticIds, Func<DiagnosticAnalyzer, ImmutableArray<DiagnosticDescriptor>> getDescriptor) { bool discarded; return ShouldRunProviderForStateType(stateTypeId, provider, driver, out discarded, diagnosticIds, getDescriptor); }
protected override async Task<AnalysisData> GetSpecificDiagnosticsAsync( Solution solution, DiagnosticAnalyzer provider, int providerId, StateType stateType, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDriver) { // we don't care about result switch (stateType) { case StateType.Syntax: await GetSyntaxDiagnosticsAsync(providerId, provider, analyzerDriver).ConfigureAwait(false); break; case StateType.Document: await GetSemanticDiagnosticsAsync(providerId, provider, analyzerDriver).ConfigureAwait(false); break; case StateType.Project: default: return Contract.FailWithReturn<AnalysisData>("Can't reach here"); } return AnalysisData.Empty; }
private static bool IsAnalyzerSuppressed(DiagnosticAnalyzer provider, CompilationOptions options, DiagnosticAnalyzerDriver driver) { if (options != null && CompilationWithAnalyzers.IsDiagnosticAnalyzerSuppressed(provider, options, driver.CatchAnalyzerExceptionHandler)) { // All diagnostics that are generated by this DiagnosticAnalyzer will be suppressed, so we need not run the analyzer. return true; } return false; }
public static bool SupportsSemanticDiagnosticAnalysis(this DiagnosticAnalyzer analyzer, DiagnosticAnalyzerDriver driver) { bool discarded; return analyzer.SupportsSemanticDiagnosticAnalysis(driver, out discarded); }
protected abstract Task<AnalysisData> GetSpecificDiagnosticsAsync(Solution solution, DiagnosticAnalyzer provider, ProviderId providerId, StateType stateType, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDriver);
protected override Task<AnalysisData> GetSpecificDiagnosticsAsync( Solution solution, DiagnosticAnalyzer provider, ProviderId providerId, StateType stateType, VersionArgument versions, DiagnosticAnalyzerDriver analyzerDriver) { switch (stateType) { case StateType.Syntax: return this.AnalyzerExecutor.GetSyntaxAnalysisDataAsync(provider, providerId, versions, analyzerDriver); case StateType.Document: return this.AnalyzerExecutor.GetDocumentAnalysisDataAsync(provider, providerId, versions, analyzerDriver); case StateType.Project: return this.AnalyzerExecutor.GetProjectAnalysisDataAsync(provider, providerId, versions, analyzerDriver); default: return Contract.FailWithReturn<Task<AnalysisData>>("Can't reach here"); } }