/// <summary>
            /// Return all local diagnostics (syntax, semantic) that belong to given document for the given StateSet (analyzer) either from cache or by calculating them
            /// </summary>
            public async Task<DocumentAnalysisData> GetDocumentAnalysisDataAsync(
                CompilationWithAnalyzers analyzerDriverOpt, Document document, StateSet stateSet, AnalysisKind kind, CancellationToken cancellationToken)
            {
                try
                {
                    var version = await GetDiagnosticVersionAsync(document.Project, cancellationToken).ConfigureAwait(false);
                    var state = stateSet.GetActiveFileState(document.Id);
                    var existingData = state.GetAnalysisData(kind);

                    if (existingData.Version == version)
                    {
                        return existingData;
                    }

                    // perf optimization. check whether analyzer is suppressed and avoid getting diagnostics if suppressed.
                    // REVIEW: IsAnalyzerSuppressed call seems can be quite expensive in certain condition. is there any other way to do this?
                    if (_owner.Owner.IsAnalyzerSuppressed(stateSet.Analyzer, document.Project))
                    {
                        return new DocumentAnalysisData(version, existingData.Items, ImmutableArray<DiagnosticData>.Empty);
                    }

                    var nullFilterSpan = (TextSpan?)null;
                    var diagnostics = await ComputeDiagnosticsAsync(analyzerDriverOpt, document, stateSet.Analyzer, kind, nullFilterSpan, cancellationToken).ConfigureAwait(false);

                    // we only care about local diagnostics
                    return new DocumentAnalysisData(version, existingData.Items, diagnostics.ToImmutableArrayOrEmpty());
                }
                catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
                {
                    throw ExceptionUtilities.Unreachable;
                }
            }
            public DocumentAnalysisData GetAnalysisData(AnalysisKind kind)
            {
                switch (kind)
                {
                    case AnalysisKind.Syntax:
                        return _syntax;

                    case AnalysisKind.Semantic:
                        return _semantic;

                    default:
                        return Contract.FailWithReturn<DocumentAnalysisData>("Shouldn't reach here");
                }
            }
        private bool SupportAnalysisKind(DiagnosticAnalyzer analyzer, string language, AnalysisKind kind)
        {
            // compiler diagnostic analyzer always support all kinds
            if (HostAnalyzerManager.IsCompilerDiagnosticAnalyzer(language, analyzer))
            {
                return true;
            }

            switch (kind)
            {
                case AnalysisKind.Syntax:
                    return analyzer.SupportsSyntaxDiagnosticAnalysis();
                case AnalysisKind.Semantic:
                    return analyzer.SupportsSemanticDiagnosticAnalysis();
                default:
                    return Contract.FailWithReturn<bool>("shouldn't reach here");
            }
        }
            public void Save(AnalysisKind kind, DocumentAnalysisData data)
            {
                Contract.ThrowIfFalse(data.OldItems.IsDefault);

                switch (kind)
                {
                    case AnalysisKind.Syntax:
                        _syntax = data;
                        return;

                    case AnalysisKind.Semantic:
                        _semantic = data;
                        return;

                    default:
                        Contract.Fail("Shouldn't reach here");
                        return;
                }
            }
        private async Task AnalyzeDocumentForKindAsync(Document document, AnalysisKind kind, CancellationToken cancellationToken)
        {
            try
            {
                if (!AnalysisEnabled(document))
                {
                    // to reduce allocations, here, we don't clear existing diagnostics since it is dealt by other entry point such as
                    // DocumentReset or DocumentClosed.
                    return;
                }

                var stateSets = _stateManager.GetOrUpdateStateSets(document.Project);
                var analyzerDriverOpt = await _compilationManager.GetAnalyzerDriverAsync(document.Project, stateSets, cancellationToken).ConfigureAwait(false);

                foreach (var stateSet in stateSets)
                {
                    var analyzer = stateSet.Analyzer;

                    var result = await _executor.GetDocumentAnalysisDataAsync(analyzerDriverOpt, document, stateSet, kind, cancellationToken).ConfigureAwait(false);
                    if (result.FromCache)
                    {
                        RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, result.Items);
                        continue;
                    }

                    // no cancellation after this point.
                    var state = stateSet.GetActiveFileState(document.Id);
                    state.Save(kind, result.ToPersistData());

                    RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, result.OldItems, result.Items);
                }
            }
            catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }
Exemple #6
0
            /// <summary>
            /// Return all local diagnostics (syntax, semantic) that belong to given document for the given StateSet (analyzer) by calculating them
            /// </summary>
            public async Task<IEnumerable<DiagnosticData>> ComputeDiagnosticsAsync(
                CompilationWithAnalyzers analyzerDriverOpt, Document document, DiagnosticAnalyzer analyzer, AnalysisKind kind, TextSpan? spanOpt, CancellationToken cancellationToken)
            {
                var documentAnalyzer = analyzer as DocumentDiagnosticAnalyzer;
                if (documentAnalyzer != null)
                {
                    var diagnostics = await ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(document, documentAnalyzer, kind, analyzerDriverOpt?.Compilation, cancellationToken).ConfigureAwait(false);
                    return ConvertToLocalDiagnostics(document, diagnostics);
                }

                var documentDiagnostics = await ComputeDiagnosticAnalyzerDiagnosticsAsync(analyzerDriverOpt, document, analyzer, kind, spanOpt, cancellationToken).ConfigureAwait(false);
                return ConvertToLocalDiagnostics(document, documentDiagnostics);
            }
Exemple #7
0
            private async Task<IEnumerable<Diagnostic>> ComputeDiagnosticAnalyzerDiagnosticsAsync(
                CompilationWithAnalyzers analyzerDriverOpt, Document document, DiagnosticAnalyzer analyzer, AnalysisKind kind, TextSpan? spanOpt, CancellationToken cancellationToken)
            {
                // quick optimization to reduce allocations.
                if (analyzerDriverOpt == null || !_owner.SupportAnalysisKind(analyzer, document.Project.Language, kind))
                {
                    return ImmutableArray<Diagnostic>.Empty;
                }

                // REVIEW: more unnecessary allocations just to get diagnostics per analyzer
                var oneAnalyzers = ImmutableArray.Create(analyzer);

                switch (kind)
                {
                    case AnalysisKind.Syntax:
                        var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
                        var diagnostics = await analyzerDriverOpt.GetAnalyzerSyntaxDiagnosticsAsync(tree, oneAnalyzers, cancellationToken).ConfigureAwait(false);

                        Contract.Requires(diagnostics.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, analyzerDriverOpt.Compilation).Count());
                        return diagnostics.ToImmutableArrayOrEmpty();
                    case AnalysisKind.Semantic:
                        var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
                        diagnostics = await analyzerDriverOpt.GetAnalyzerSemanticDiagnosticsAsync(model, spanOpt, oneAnalyzers, cancellationToken).ConfigureAwait(false);

                        Contract.Requires(diagnostics.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, analyzerDriverOpt.Compilation).Count());
                        return diagnostics.ToImmutableArrayOrEmpty();
                    default:
                        return Contract.FailWithReturn<ImmutableArray<Diagnostic>>("shouldn't reach here");
                }
            }
Exemple #8
0
            protected override async Task <ImmutableArray <DiagnosticData> > GetDiagnosticsAsync(StateSet stateSet, Project project, DocumentId?documentId, AnalysisKind kind, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var stateSets = SpecializedCollections.SingletonCollection(stateSet);

                // Here, we don't care what kind of analyzer (StateSet) is given.
                var forceAnalyzerRun = true;
                var compilation      = await Owner.CreateCompilationWithAnalyzersAsync(project, stateSets, IncludeSuppressedDiagnostics, cancellationToken).ConfigureAwait(false);

                if (documentId != null)
                {
                    var document = project.Solution.GetDocument(documentId);
                    Contract.ThrowIfNull(document);

                    switch (kind)
                    {
                    case AnalysisKind.Syntax:
                    case AnalysisKind.Semantic:
                        return((await Owner.GetDocumentAnalysisDataAsync(compilation, document, stateSet, kind, cancellationToken).ConfigureAwait(false)).Items);

                    case AnalysisKind.NonLocal:
                        var nonLocalDocumentResult = await Owner.GetProjectAnalysisDataAsync(compilation, project, stateSets, forceAnalyzerRun, cancellationToken).ConfigureAwait(false);

                        var analysisResult = nonLocalDocumentResult.GetResult(stateSet.Analyzer);
                        return(analysisResult.GetDocumentDiagnostics(documentId, AnalysisKind.NonLocal));

                    default:
                        throw ExceptionUtilities.UnexpectedValue(kind);
                    }
                }

                Contract.ThrowIfFalse(kind == AnalysisKind.NonLocal);
                var projectResult = await Owner.GetProjectAnalysisDataAsync(compilation, project, stateSets, forceAnalyzerRun, cancellationToken).ConfigureAwait(false);

                return(projectResult.GetResult(stateSet.Analyzer).GetOtherDiagnostics());
            }
Exemple #9
0
            public async Task <ImmutableArray <DiagnosticData> > GetSpecificDiagnosticsAsync(DiagnosticAnalyzer analyzer, AnalysisKind analysisKind, CancellationToken cancellationToken)
            {
                var project = Solution.GetProject(ProjectId);

                if (project == null)
                {
                    // when we return cached result, make sure we at least return something that exist in current solution
                    return(ImmutableArray <DiagnosticData> .Empty);
                }

                var stateSet = StateManager.GetOrCreateStateSet(project, analyzer);

                if (stateSet == null)
                {
                    return(ImmutableArray <DiagnosticData> .Empty);
                }

                var diagnostics = await GetDiagnosticsAsync(stateSet, project, DocumentId, analysisKind, cancellationToken).ConfigureAwait(false);

                return(IncludeSuppressedDiagnostics ? diagnostics : diagnostics.WhereAsArray(d => !d.IsSuppressed));
            }
            private async Task<ImmutableArray<DiagnosticData>?> GetProjectStateDiagnosticsAsync(
                StateSet stateSet, Project project, DocumentId documentId, AnalysisKind kind, CancellationToken cancellationToken)
            {
                if (!stateSet.TryGetProjectState(project.Id, out var state))
                {
                    // never analyzed this project yet.
                    return null;
                }

                if (documentId != null)
                {
                    // file doesn't exist in current solution
                    var document = project.Solution.GetDocument(documentId);
                    if (document == null)
                    {
                        return null;
                    }

                    var result = await state.GetAnalysisDataAsync(document, avoidLoadingData: false, cancellationToken: cancellationToken).ConfigureAwait(false);
                    return GetResult(result, kind, documentId);
                }

                Contract.ThrowIfFalse(kind == AnalysisKind.NonLocal);
                var nonLocalResult = await state.GetProjectAnalysisDataAsync(project, avoidLoadingData: false, cancellationToken: cancellationToken).ConfigureAwait(false);
                return nonLocalResult.Others;
            }
Exemple #11
0
 private void RaiseDocumentDiagnosticsIfNeeded(
     Document document, StateSet stateSet, AnalysisKind kind, ImmutableArray <DiagnosticData> oldItems, ImmutableArray <DiagnosticData> newItems)
 {
     RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, oldItems, newItems, AnalyzerService.RaiseDiagnosticsUpdated, forceUpdate: false);
 }
            /// <summary>
            /// Return all local diagnostics (syntax, semantic) that belong to given document for the given StateSet (analyzer) either from cache or by calculating them
            /// </summary>
            public async Task <DocumentAnalysisData> GetDocumentAnalysisDataAsync(
                CompilationWithAnalyzers analyzerDriverOpt, Document document, StateSet stateSet, AnalysisKind kind, CancellationToken cancellationToken)
            {
                try
                {
                    var version = await GetDiagnosticVersionAsync(document.Project, cancellationToken).ConfigureAwait(false);

                    var state        = stateSet.GetActiveFileState(document.Id);
                    var existingData = state.GetAnalysisData(kind);

                    if (existingData.Version == version)
                    {
                        return(existingData);
                    }

                    // perf optimization. check whether analyzer is suppressed and avoid getting diagnostics if suppressed.
                    // REVIEW: IsAnalyzerSuppressed call seems can be quite expensive in certain condition. is there any other way to do this?
                    if (_owner.Owner.IsAnalyzerSuppressed(stateSet.Analyzer, document.Project))
                    {
                        return(new DocumentAnalysisData(version, existingData.Items, ImmutableArray <DiagnosticData> .Empty));
                    }

                    var nullFilterSpan = (TextSpan?)null;
                    var diagnostics    = await ComputeDiagnosticsAsync(analyzerDriverOpt, document, stateSet.Analyzer, kind, nullFilterSpan, cancellationToken).ConfigureAwait(false);

                    // we only care about local diagnostics
                    return(new DocumentAnalysisData(version, existingData.Items, diagnostics.ToImmutableArrayOrEmpty()));
                }
                catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
                {
                    throw ExceptionUtilities.Unreachable;
                }
            }
        private static ImmutableArray<DiagnosticData> GetResult(DiagnosticAnalysisResult result, AnalysisKind kind, DocumentId id)
        {
            if (result.IsEmpty || !result.DocumentIds.Contains(id) || result.IsAggregatedForm)
            {
                return ImmutableArray<DiagnosticData>.Empty;
            }

            switch (kind)
            {
                case AnalysisKind.Syntax:
                    return result.GetResultOrEmpty(result.SyntaxLocals, id);
                case AnalysisKind.Semantic:
                    return result.GetResultOrEmpty(result.SemanticLocals, id);
                case AnalysisKind.NonLocal:
                    return result.GetResultOrEmpty(result.NonLocals, id);
                default:
                    return Contract.FailWithReturn<ImmutableArray<DiagnosticData>>("shouldn't reach here");
            }
        }
            /// <summary>
            /// Return all local diagnostics (syntax, semantic) that belong to given document for the given StateSet (analyzer) by calculating them
            /// </summary>
            public async Task <IEnumerable <DiagnosticData> > ComputeDiagnosticsAsync(
                CompilationWithAnalyzers analyzerDriverOpt, Document document, DiagnosticAnalyzer analyzer, AnalysisKind kind, TextSpan?spanOpt, CancellationToken cancellationToken)
            {
                var documentAnalyzer = analyzer as DocumentDiagnosticAnalyzer;

                if (documentAnalyzer != null)
                {
                    var diagnostics = await ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(document, documentAnalyzer, kind, analyzerDriverOpt?.Compilation, cancellationToken).ConfigureAwait(false);

                    return(ConvertToLocalDiagnostics(document, diagnostics));
                }

                var documentDiagnostics = await ComputeDiagnosticAnalyzerDiagnosticsAsync(analyzerDriverOpt, document, analyzer, kind, spanOpt, cancellationToken).ConfigureAwait(false);

                return(ConvertToLocalDiagnostics(document, documentDiagnostics));
            }
            private async Task <IEnumerable <Diagnostic> > ComputeDiagnosticAnalyzerDiagnosticsAsync(
                CompilationWithAnalyzers analyzerDriverOpt, Document document, DiagnosticAnalyzer analyzer, AnalysisKind kind, TextSpan?spanOpt, CancellationToken cancellationToken)
            {
                // quick optimization to reduce allocations.
                if (analyzerDriverOpt == null || !_owner.SupportAnalysisKind(analyzer, document.Project.Language, kind))
                {
                    return(ImmutableArray <Diagnostic> .Empty);
                }

                // REVIEW: more unnecessary allocations just to get diagnostics per analyzer
                var oneAnalyzers = ImmutableArray.Create(analyzer);

                switch (kind)
                {
                case AnalysisKind.Syntax:
                    var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                    var diagnostics = await analyzerDriverOpt.GetAnalyzerSyntaxDiagnosticsAsync(tree, oneAnalyzers, cancellationToken).ConfigureAwait(false);

                    Contract.Requires(diagnostics.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, analyzerDriverOpt.Compilation).Count());
                    return(diagnostics.ToImmutableArrayOrEmpty());

                case AnalysisKind.Semantic:
                    var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    diagnostics = await analyzerDriverOpt.GetAnalyzerSemanticDiagnosticsAsync(model, spanOpt, oneAnalyzers, cancellationToken).ConfigureAwait(false);

                    Contract.Requires(diagnostics.Count() == CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, analyzerDriverOpt.Compilation).Count());
                    return(diagnostics.ToImmutableArrayOrEmpty());

                default:
                    return(Contract.FailWithReturn <ImmutableArray <Diagnostic> >("shouldn't reach here"));
                }
            }
Exemple #16
0
 private static object CreateId(StateSet stateSet, ProjectId projectId, AnalysisKind kind)
 => new LiveDiagnosticUpdateArgsId(stateSet.Analyzer, projectId, (int)kind, stateSet.ErrorSourceName);
Exemple #17
0
            private static async Task <ImmutableArray <DiagnosticData> > GetProjectStateDiagnosticsAsync(StateSet stateSet, Project project, DocumentId?documentId, AnalysisKind kind, CancellationToken cancellationToken)
            {
                if (!stateSet.TryGetProjectState(project.Id, out var state))
                {
                    // never analyzed this project yet.
                    return(ImmutableArray <DiagnosticData> .Empty);
                }

                if (documentId != null)
                {
                    // file doesn't exist in current solution
                    var document = await project.Solution.GetDocumentAsync(
                        documentId,
                        includeSourceGenerated : project.Solution.Workspace.Services.GetService <ISyntaxTreeConfigurationService>() is { EnableOpeningSourceGeneratedFilesInWorkspace : true },
Exemple #18
0
 public AggregatedKey(ImmutableArray <DocumentId> documentIds, DiagnosticAnalyzer analyzer, AnalysisKind kind)
 {
     DocumentIds = documentIds;
     Analyzer    = analyzer;
     Kind        = kind;
 }
        private void RaiseDiagnosticsCreated(
            Document document, StateSet stateSet, AnalysisKind kind, ImmutableArray<DiagnosticData> items, Action<DiagnosticsUpdatedArgs> raiseEvents)
        {
            Contract.ThrowIfFalse(document.Project.Solution.Workspace == Workspace);

            raiseEvents(DiagnosticsUpdatedArgs.DiagnosticsCreated(
                CreateId(stateSet.Analyzer, document.Id, kind, stateSet.ErrorSourceName),
                document.Project.Solution.Workspace,
                document.Project.Solution,
                document.Project.Id,
                document.Id,
                items));
        }
 private void RaiseDocumentDiagnosticsIfNeeded(Document document, StateSet stateSet, AnalysisKind kind, ImmutableArray <DiagnosticData> items)
 {
     RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, ImmutableArray <DiagnosticData> .Empty, items);
 }
 private object CreateId(DiagnosticAnalyzer analyzer, ProjectId key, AnalysisKind kind, string errorSourceName)
 {
     return CreateIdInternal(analyzer, key, kind, errorSourceName);
 }
 private void RaiseDocumentDiagnosticsIfNeeded(
     Document document, StateSet stateSet, AnalysisKind kind, ImmutableArray <DiagnosticData> oldItems, ImmutableArray <DiagnosticData> newItems)
 {
     RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, oldItems, newItems, Owner.RaiseDiagnosticsUpdated);
 }
            protected override async Task<ImmutableArray<DiagnosticData>?> GetDiagnosticsAsync(StateSet stateSet, Project project, DocumentId documentId, AnalysisKind kind, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var activeFileDiagnostics = GetActiveFileDiagnostics(stateSet, documentId, kind);
                if (activeFileDiagnostics.HasValue)
                {
                    return activeFileDiagnostics.Value;
                }

                var projectDiagnostics = await GetProjectStateDiagnosticsAsync(stateSet, project, documentId, kind, cancellationToken).ConfigureAwait(false);
                if (projectDiagnostics.HasValue)
                {
                    return projectDiagnostics.Value;
                }

                return null;
            }
 private ImmutableDictionary <DocumentId, ImmutableArray <DiagnosticData> >?GetMap(
     AnalysisKind kind
     ) =>
 kind switch
 {
 protected abstract Task<ImmutableArray<DiagnosticData>?> GetDiagnosticsAsync(StateSet stateSet, Project project, DocumentId documentId, AnalysisKind kind, CancellationToken cancellationToken);
        public bool SupportAnalysisKind(DiagnosticAnalyzer analyzer, string language, AnalysisKind kind)
        {
            // compiler diagnostic analyzer always supports all kinds:
            if (IsCompilerDiagnosticAnalyzer(language, analyzer))
            {
                return(true);
            }

            return(kind switch
            {
                AnalysisKind.Syntax => analyzer.SupportsSyntaxDiagnosticAnalysis(),
                AnalysisKind.Semantic => analyzer.SupportsSemanticDiagnosticAnalysis(),
                _ => throw ExceptionUtilities.UnexpectedValue(kind)
            });
Exemple #27
0
        private async Task <DocumentAnalysisData> GetDocumentAnalysisDataAsync(
            CompilationWithAnalyzers?compilation, Document document, StateSet stateSet, AnalysisKind kind, CancellationToken cancellationToken)
        {
            // get log title and functionId
            GetLogFunctionIdAndTitle(kind, out var functionId, out var title);

            using (Logger.LogBlock(functionId, GetDocumentLogMessage, title, document, stateSet.Analyzer, cancellationToken))
            {
                try
                {
                    var version = await GetDiagnosticVersionAsync(document.Project, cancellationToken).ConfigureAwait(false);

                    var state        = stateSet.GetOrCreateActiveFileState(document.Id);
                    var existingData = state.GetAnalysisData(kind);

                    if (existingData.Version == version)
                    {
                        return(existingData);
                    }

                    // perf optimization. check whether analyzer is suppressed and avoid getting diagnostics if suppressed.
                    if (AnalyzerService.IsAnalyzerSuppressed(stateSet.Analyzer, document.Project))
                    {
                        return(new DocumentAnalysisData(version, existingData.Items, ImmutableArray <DiagnosticData> .Empty));
                    }

                    var diagnostics = await AnalyzerService.ComputeDiagnosticsAsync(compilation, document, stateSet.Analyzer, kind, span : null, DiagnosticLogAggregator, cancellationToken).ConfigureAwait(false);

                    // this is no-op in product. only run in test environment
                    Logger.Log(functionId, (t, d, a, ds) => $"{GetDocumentLogMessage(t, d, a)}, {string.Join(Environment.NewLine, ds)}",
                               title, document, stateSet.Analyzer, diagnostics);

                    // we only care about local diagnostics
                    return(new DocumentAnalysisData(version, existingData.Items, diagnostics.ToImmutableArrayOrEmpty()));
                }
                catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
                {
                    throw ExceptionUtilities.Unreachable;
                }
            }
        }
 private void RaiseEmptyDiagnosticUpdated(AnalysisKind kind, DocumentId documentId)
 {
     _service.RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs.DiagnosticsRemoved(
                                          new DefaultUpdateArgsId(_workspace.Kind, kind, documentId), _workspace, null, documentId.ProjectId, documentId));
 }
Exemple #29
0
 protected abstract Task <ImmutableArray <DiagnosticData> > GetDiagnosticsAsync(StateSet stateSet, Project project, DocumentId?documentId, AnalysisKind kind, CancellationToken cancellationToken);
 public DefaultUpdateArgsId(string workspaceKind, AnalysisKind kind, DocumentId documentId) : base((int)kind, documentId)
     => _workspaceKind = workspaceKind;
Exemple #31
0
            protected override async Task <ImmutableArray <DiagnosticData>?> GetDiagnosticsAsync(StateSet stateSet, Project project, DocumentId documentId, AnalysisKind kind, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var activeFileDiagnostics = GetActiveFileDiagnostics(stateSet, documentId, kind);

                if (activeFileDiagnostics.HasValue)
                {
                    return(activeFileDiagnostics.Value);
                }

                var projectDiagnostics = await GetProjectStateDiagnosticsAsync(stateSet, project, documentId, kind, cancellationToken).ConfigureAwait(false);

                if (projectDiagnostics.HasValue)
                {
                    return(projectDiagnostics.Value);
                }

                return(null);
            }
Exemple #32
0
            private ImmutableArray <DiagnosticData>?GetActiveFileDiagnostics(StateSet stateSet, DocumentId documentId, AnalysisKind kind)
            {
                if (documentId == null || kind == AnalysisKind.NonLocal)
                {
                    return(null);
                }

                if (!stateSet.TryGetActiveFileState(documentId, out var state))
                {
                    return(null);
                }

                return(state.GetAnalysisData(kind).Items);
            }
Exemple #33
0
            private async Task<IEnumerable<Diagnostic>> ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(
                Document document, DocumentDiagnosticAnalyzer analyzer, AnalysisKind kind, Compilation compilationOpt, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    Task<ImmutableArray<Diagnostic>> analyzeAsync;

                    switch (kind)
                    {
                        case AnalysisKind.Syntax:
                            analyzeAsync = analyzer.AnalyzeSyntaxAsync(document, cancellationToken);
                            break;

                        case AnalysisKind.Semantic:
                            analyzeAsync = analyzer.AnalyzeSemanticsAsync(document, cancellationToken);
                            break;

                        default:
                            throw ExceptionUtilities.UnexpectedValue(kind);
                    }

                    var diagnostics = (await analyzeAsync.ConfigureAwait(false)).NullToEmpty();
                    if (compilationOpt != null)
                    {
                        return CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, compilationOpt);
                    }

                    return diagnostics;
                }
                catch (Exception e) when (!IsCanceled(e, cancellationToken))
                {
                    OnAnalyzerException(analyzer, document.Project.Id, compilationOpt, e);
                    return ImmutableArray<Diagnostic>.Empty;
                }
            }
Exemple #34
0
            protected override async Task <ImmutableArray <DiagnosticData>?> GetDiagnosticsAsync(StateSet stateSet, Project project, DocumentId documentId, AnalysisKind kind, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var stateSets = SpecializedCollections.SingletonCollection(stateSet);

                // Here, we don't care what kind of analyzer (StateSet) is given.
                // We just create and use AnalyzerDriver with the given analyzer (StateSet).
                var forceAnalyzerRun  = true;
                var analyzerDriverOpt = await Owner._compilationManager.CreateAnalyzerDriverAsync(project, stateSets, IncludeSuppressedDiagnostics, cancellationToken).ConfigureAwait(false);

                if (documentId != null)
                {
                    var document = project.Solution.GetDocument(documentId);
                    Contract.ThrowIfNull(document);

                    switch (kind)
                    {
                    case AnalysisKind.Syntax:
                    case AnalysisKind.Semantic:
                    {
                        var result = await Owner._executor.GetDocumentAnalysisDataAsync(analyzerDriverOpt, document, stateSet, kind, cancellationToken).ConfigureAwait(false);

                        return(result.Items);
                    }

                    case AnalysisKind.NonLocal:
                    {
                        var nonLocalDocumentResult = await Owner._executor.GetProjectAnalysisDataAsync(analyzerDriverOpt, project, stateSets, forceAnalyzerRun, cancellationToken).ConfigureAwait(false);

                        var analysisResult = nonLocalDocumentResult.GetResult(stateSet.Analyzer);
                        return(GetResult(analysisResult, AnalysisKind.NonLocal, documentId));
                    }

                    default:
                        return(Contract.FailWithReturn <ImmutableArray <DiagnosticData>?>("shouldn't reach here"));
                    }
                }

                Contract.ThrowIfFalse(kind == AnalysisKind.NonLocal);
                var projectResult = await Owner._executor.GetProjectAnalysisDataAsync(analyzerDriverOpt, project, stateSets, forceAnalyzerRun, cancellationToken).ConfigureAwait(false);

                return(projectResult.GetResult(stateSet.Analyzer).Others);
            }
Exemple #35
0
 private static void GetLogFunctionIdAndTitle(AnalysisKind kind, out FunctionId functionId, out string title)
 {
     switch (kind)
     {
         case AnalysisKind.Syntax:
             functionId = FunctionId.Diagnostics_SyntaxDiagnostic;
             title = "syntax";
             break;
         case AnalysisKind.Semantic:
             functionId = FunctionId.Diagnostics_SemanticDiagnostic;
             title = "semantic";
             break;
         default:
             functionId = FunctionId.Diagnostics_ProjectDiagnostic;
             title = "nonLocal";
             Contract.Fail("shouldn't reach here");
             break;
     }
 }
Exemple #36
0
        private async Task AnalyzeDocumentForKindAsync(
            TextDocument document,
            AnalysisKind kind,
            CancellationToken cancellationToken
            )
        {
            try
            {
                if (!AnalysisEnabled(document))
                {
                    // to reduce allocations, here, we don't clear existing diagnostics since it is dealt by other entry point such as
                    // DocumentReset or DocumentClosed.
                    return;
                }

                var stateSets = _stateManager.GetOrUpdateStateSets(document.Project);
                var compilationWithAnalyzers = await GetOrCreateCompilationWithAnalyzersAsync(
                    document.Project,
                    stateSets,
                    cancellationToken
                    )
                                               .ConfigureAwait(false);

                // We split the diagnostic computation for document into following steps:
                //  1. Try to get cached diagnostics for each analyzer, while computing the set of analyzers that do not have cached diagnostics.
                //  2. Execute all the non-cached analyzers with a single invocation into CompilationWithAnalyzers.
                //  3. Fetch computed diagnostics per-analyzer from the above invocation, and cache and raise diagnostic reported events.
                // In near future, the diagnostic computation invocation into CompilationWithAnalyzers will be moved to OOP.
                // This should help simplify and/or remove the IDE layer diagnostic caching in devenv process.

                // First attempt to fetch diagnostics from the cache, while computing the state sets for analyzers that are not cached.
                using var _ = ArrayBuilder <StateSet> .GetInstance(out var nonCachedStateSets);

                foreach (var stateSet in stateSets)
                {
                    var data = await TryGetCachedDocumentAnalysisDataAsync(
                        document,
                        stateSet,
                        kind,
                        cancellationToken
                        )
                               .ConfigureAwait(false);

                    if (data.HasValue)
                    {
                        // We need to persist and raise diagnostics for suppressed analyzer.
                        PersistAndRaiseDiagnosticsIfNeeded(data.Value, stateSet);
                    }
                    else
                    {
                        nonCachedStateSets.Add(stateSet);
                    }
                }

                // Then, compute the diagnostics for non-cached state sets, and cache and raise diagnostic reported events for these diagnostics.
                if (nonCachedStateSets.Count > 0)
                {
                    var analysisScope = new DocumentAnalysisScope(
                        document,
                        span: null,
                        nonCachedStateSets.SelectAsArray(s => s.Analyzer),
                        kind
                        );
                    var executor = new DocumentAnalysisExecutor(
                        analysisScope,
                        compilationWithAnalyzers,
                        _diagnosticAnalyzerRunner,
                        logPerformanceInfo: true,
                        onAnalysisException: OnAnalysisException
                        );
                    foreach (var stateSet in nonCachedStateSets)
                    {
                        var computedData = await ComputeDocumentAnalysisDataAsync(
                            executor,
                            stateSet,
                            cancellationToken
                            )
                                           .ConfigureAwait(false);

                        PersistAndRaiseDiagnosticsIfNeeded(computedData, stateSet);
                    }
                }
            }
            catch (Exception e)
                when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken))
                {
                    throw ExceptionUtilities.Unreachable;
                }

            void PersistAndRaiseDiagnosticsIfNeeded(DocumentAnalysisData result, StateSet stateSet)
            {
                if (result.FromCache == true)
                {
                    RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, result.Items);
                    return;
                }

                // no cancellation after this point.
                var state = stateSet.GetOrCreateActiveFileState(document.Id);

                state.Save(kind, result.ToPersistData());

                RaiseDocumentDiagnosticsIfNeeded(
                    document,
                    stateSet,
                    kind,
                    result.OldItems,
                    result.Items
                    );
            }

            void OnAnalysisException()
            {
                // Do not re-use cached CompilationWithAnalyzers instance in presence of an exception, as the underlying analysis state might be corrupt.
                ClearCompilationsWithAnalyzersCache(document.Project);
            }
        }
        private void RaiseDiagnosticsRemoved(
            DocumentId documentId, Solution solution, StateSet stateSet, AnalysisKind kind, Action<DiagnosticsUpdatedArgs> raiseEvents)
        {
            Contract.ThrowIfFalse(solution == null || solution.Workspace == Workspace);

            raiseEvents(DiagnosticsUpdatedArgs.DiagnosticsRemoved(
                CreateId(stateSet.Analyzer, documentId, kind, stateSet.ErrorSourceName),
                Workspace,
                solution,
                documentId.ProjectId,
                documentId));
        }
Exemple #38
0
 private object CreateId(DiagnosticAnalyzer analyzer, ProjectId key, AnalysisKind kind, string errorSourceName)
 {
     return(CreateIdInternal(analyzer, key, kind, errorSourceName));
 }
 private static object CreateIdInternal(DiagnosticAnalyzer analyzer, object key, AnalysisKind kind, string errorSourceName)
 {
     return new LiveDiagnosticUpdateArgsId(analyzer, key, (int)kind, errorSourceName);
 }
Exemple #40
0
 private static object CreateIdInternal(DiagnosticAnalyzer analyzer, object key, AnalysisKind kind, string errorSourceName)
 {
     return(new LiveDiagnosticUpdateArgsId(analyzer, key, (int)kind, errorSourceName));
 }
 public DocumentAnalysisData GetAnalysisData(AnalysisKind kind) =>
 kind switch
 {
        private static ImmutableArray <DiagnosticData> GetResult(DiagnosticAnalysisResult result, AnalysisKind kind, DocumentId id)
        {
            if (result.IsEmpty || !result.DocumentIds.Contains(id) || result.IsAggregatedForm)
            {
                return(ImmutableArray <DiagnosticData> .Empty);
            }

            return(kind switch
            {
                AnalysisKind.Syntax => result.GetResultOrEmpty(result.SyntaxLocals, id),
                AnalysisKind.Semantic => result.GetResultOrEmpty(result.SemanticLocals, id),
                AnalysisKind.NonLocal => result.GetResultOrEmpty(result.NonLocals, id),
                _ => Contract.FailWithReturn <ImmutableArray <DiagnosticData> >("shouldn't reach here"),
            });
            private ImmutableArray<DiagnosticData>? GetActiveFileDiagnostics(StateSet stateSet, DocumentId documentId, AnalysisKind kind)
            {
                if (documentId == null || kind == AnalysisKind.NonLocal)
                {
                    return null;
                }

                if (!stateSet.TryGetActiveFileState(documentId, out var state))
                {
                    return null;
                }

                return state.GetAnalysisData(kind).Items;
            }
 private void RaiseDocumentDiagnosticsIfNeeded(Document document, StateSet stateSet, AnalysisKind kind, ImmutableArray<DiagnosticData> items)
 {
     RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, ImmutableArray<DiagnosticData>.Empty, items);
 }
            protected override async Task<ImmutableArray<DiagnosticData>?> GetDiagnosticsAsync(StateSet stateSet, Project project, DocumentId documentId, AnalysisKind kind, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var stateSets = SpecializedCollections.SingletonCollection(stateSet);

                // Here, we don't care what kind of analyzer (StateSet) is given. 
                // We just create and use AnalyzerDriver with the given analyzer (StateSet). 
                var ignoreFullAnalysisOptions = true;
                var analyzerDriverOpt = await Owner._compilationManager.CreateAnalyzerDriverAsync(project, stateSets, IncludeSuppressedDiagnostics, cancellationToken).ConfigureAwait(false);

                if (documentId != null)
                {
                    var document = project.Solution.GetDocument(documentId);
                    Contract.ThrowIfNull(document);

                    switch (kind)
                    {
                        case AnalysisKind.Syntax:
                        case AnalysisKind.Semantic:
                            {
                                var result = await Owner._executor.GetDocumentAnalysisDataAsync(analyzerDriverOpt, document, stateSet, kind, cancellationToken).ConfigureAwait(false);
                                return result.Items;
                            }
                        case AnalysisKind.NonLocal:
                            {
                                var nonLocalDocumentResult = await Owner._executor.GetProjectAnalysisDataAsync(analyzerDriverOpt, project, stateSets, ignoreFullAnalysisOptions, cancellationToken).ConfigureAwait(false);
                                var analysisResult = nonLocalDocumentResult.GetResult(stateSet.Analyzer);
                                return GetResult(analysisResult, AnalysisKind.NonLocal, documentId);
                            }
                        default:
                            return Contract.FailWithReturn<ImmutableArray<DiagnosticData>?>("shouldn't reach here");
                    }
                }

                Contract.ThrowIfFalse(kind == AnalysisKind.NonLocal);
                var projectResult = await Owner._executor.GetProjectAnalysisDataAsync(analyzerDriverOpt, project, stateSets, ignoreFullAnalysisOptions, cancellationToken).ConfigureAwait(false);
                return projectResult.GetResult(stateSet.Analyzer).Others;
            }
        private void RaiseDocumentDiagnosticsIfNeeded(
            Document document, StateSet stateSet, AnalysisKind kind,
            DiagnosticAnalysisResult oldResult, DiagnosticAnalysisResult newResult,
            Action<DiagnosticsUpdatedArgs> raiseEvents)
        {
            var oldItems = GetResult(oldResult, kind, document.Id);
            var newItems = GetResult(newResult, kind, document.Id);

            RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, oldItems, newItems, raiseEvents);
        }
Exemple #47
0
        private static ImmutableArray <DiagnosticData> GetResult(DiagnosticAnalysisResult result, AnalysisKind kind, DocumentId id)
        {
            if (result.IsEmpty || !result.DocumentIds.Contains(id) || result.IsAggregatedForm)
            {
                return(ImmutableArray <DiagnosticData> .Empty);
            }

            switch (kind)
            {
            case AnalysisKind.Syntax:
                return(result.GetResultOrEmpty(result.SyntaxLocals, id));

            case AnalysisKind.Semantic:
                return(result.GetResultOrEmpty(result.SemanticLocals, id));

            case AnalysisKind.NonLocal:
                return(result.GetResultOrEmpty(result.NonLocals, id));

            default:
                return(Contract.FailWithReturn <ImmutableArray <DiagnosticData> >("shouldn't reach here"));
            }
        }
Exemple #48
0
        private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKind kind, CancellationToken cancellationToken)
        {
            try
            {
                if (!document.SupportsDiagnostics())
                {
                    return;
                }

                var isActiveDocument         = _documentTrackingService.TryGetActiveDocument() == document.Id;
                var isOpenDocument           = document.IsOpen();
                var isGeneratedRazorDocument = document.IsRazorDocument();

                // Only analyze open/active documents, unless it is a generated Razor document.
                if (!isActiveDocument && !isOpenDocument && !isGeneratedRazorDocument)
                {
                    return;
                }

                var stateSets = _stateManager.GetOrUpdateStateSets(document.Project);
                var compilationWithAnalyzers = await GetOrCreateCompilationWithAnalyzersAsync(document.Project, stateSets, cancellationToken).ConfigureAwait(false);

                var version = await GetDiagnosticVersionAsync(document.Project, cancellationToken).ConfigureAwait(false);

                var backgroundAnalysisScope  = GlobalOptions.GetBackgroundAnalysisScope(document.Project.Language);
                var compilerDiagnosticsScope = GlobalOptions.GetOption(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, document.Project.Language);

                // TODO: Switch to a more reliable service to determine visible documents.
                //       DocumentTrackingService is known be unreliable at times.
                var isVisibleDocument = _documentTrackingService.GetVisibleDocuments().Contains(document.Id);

                // We split the diagnostic computation for document into following steps:
                //  1. Try to get cached diagnostics for each analyzer, while computing the set of analyzers that do not have cached diagnostics.
                //  2. Execute all the non-cached analyzers with a single invocation into CompilationWithAnalyzers.
                //  3. Fetch computed diagnostics per-analyzer from the above invocation, and cache and raise diagnostic reported events.
                // In near future, the diagnostic computation invocation into CompilationWithAnalyzers will be moved to OOP.
                // This should help simplify and/or remove the IDE layer diagnostic caching in devenv process.

                // First attempt to fetch diagnostics from the cache, while computing the state sets for analyzers that are not cached.
                using var _ = ArrayBuilder <StateSet> .GetInstance(out var nonCachedStateSets);

                foreach (var stateSet in stateSets)
                {
                    var data = TryGetCachedDocumentAnalysisData(document, stateSet, kind, version,
                                                                backgroundAnalysisScope, compilerDiagnosticsScope, isActiveDocument, isVisibleDocument,
                                                                isOpenDocument, isGeneratedRazorDocument, cancellationToken);
                    if (data.HasValue)
                    {
                        // We need to persist and raise diagnostics for suppressed analyzer.
                        PersistAndRaiseDiagnosticsIfNeeded(data.Value, stateSet);
                    }
                    else
                    {
                        nonCachedStateSets.Add(stateSet);
                    }
                }

                // Then, compute the diagnostics for non-cached state sets, and cache and raise diagnostic reported events for these diagnostics.
                if (nonCachedStateSets.Count > 0)
                {
                    var analysisScope = new DocumentAnalysisScope(document, span: null, nonCachedStateSets.SelectAsArray(s => s.Analyzer), kind);
                    var executor      = new DocumentAnalysisExecutor(analysisScope, compilationWithAnalyzers, _diagnosticAnalyzerRunner, logPerformanceInfo: true, onAnalysisException: OnAnalysisException);
                    var logTelemetry  = GlobalOptions.GetOption(DiagnosticOptions.LogTelemetryForBackgroundAnalyzerExecution);
                    foreach (var stateSet in nonCachedStateSets)
                    {
                        var computedData = await ComputeDocumentAnalysisDataAsync(executor, stateSet, logTelemetry, cancellationToken).ConfigureAwait(false);

                        PersistAndRaiseDiagnosticsIfNeeded(computedData, stateSet);
                    }
                }
            }
            catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken))
            {
                throw ExceptionUtilities.Unreachable;
            }

            void PersistAndRaiseDiagnosticsIfNeeded(DocumentAnalysisData result, StateSet stateSet)
            {
                if (result.FromCache == true)
                {
                    RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, result.Items);
                    return;
                }

                // no cancellation after this point.
                var state = stateSet.GetOrCreateActiveFileState(document.Id);

                state.Save(kind, result.ToPersistData());

                RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, result.OldItems, result.Items);
            }

            void OnAnalysisException()
            {
                // Do not re-use cached CompilationWithAnalyzers instance in presence of an exception, as the underlying analysis state might be corrupt.
                ClearCompilationsWithAnalyzersCache(document.Project);
            }
        }
Exemple #49
0
        private bool SupportAnalysisKind(DiagnosticAnalyzer analyzer, string language, AnalysisKind kind)
        {
            // compiler diagnostic analyzer always support all kinds
            if (HostAnalyzerManager.IsCompilerDiagnosticAnalyzer(language, analyzer))
            {
                return(true);
            }

            switch (kind)
            {
            case AnalysisKind.Syntax:
                return(analyzer.SupportsSyntaxDiagnosticAnalysis());

            case AnalysisKind.Semantic:
                return(analyzer.SupportsSemanticDiagnosticAnalysis());

            default:
                return(Contract.FailWithReturn <bool>("shouldn't reach here"));
            }
        }
Exemple #50
0
            protected override async Task <ImmutableArray <DiagnosticData> > GetDiagnosticsAsync(StateSet stateSet, Project project, DocumentId?documentId, AnalysisKind kind, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                // active file diagnostics:
                if (documentId != null && kind != AnalysisKind.NonLocal && stateSet.TryGetActiveFileState(documentId, out var state))
                {
                    return(state.GetAnalysisData(kind).Items);
                }

                // project diagnostics:
                return(await GetProjectStateDiagnosticsAsync(stateSet, project, documentId, kind, cancellationToken).ConfigureAwait(false));
            }
 private void RaiseDocumentDiagnosticsIfNeeded(
     Document document, StateSet stateSet, AnalysisKind kind, ImmutableArray<DiagnosticData> oldItems, ImmutableArray<DiagnosticData> newItems)
 {
     RaiseDocumentDiagnosticsIfNeeded(document, stateSet, kind, oldItems, newItems, Owner.RaiseDiagnosticsUpdated);
 }
Exemple #52
0
            private async Task <ImmutableArray <DiagnosticData> > GetProjectStateDiagnosticsAsync(StateSet stateSet, Project project, DocumentId?documentId, AnalysisKind kind, CancellationToken cancellationToken)
            {
                if (!stateSet.TryGetProjectState(project.Id, out var state))
                {
                    // never analyzed this project yet.
                    return(ImmutableArray <DiagnosticData> .Empty);
                }

                if (documentId != null)
                {
                    // file doesn't exist in current solution
                    var document = project.Solution.GetDocument(documentId);
                    if (document == null)
                    {
                        return(ImmutableArray <DiagnosticData> .Empty);
                    }

                    var result = await state.GetAnalysisDataAsync(Owner.PersistentStorageService, document, avoidLoadingData : false, cancellationToken : cancellationToken).ConfigureAwait(false);

                    return(result.GetDocumentDiagnostics(documentId, kind));
                }

                Contract.ThrowIfFalse(kind == AnalysisKind.NonLocal);
                var nonLocalResult = await state.GetProjectAnalysisDataAsync(Owner.PersistentStorageService, project, avoidLoadingData : false, cancellationToken : cancellationToken).ConfigureAwait(false);

                return(nonLocalResult.GetOtherDiagnostics());
            }
        private void RaiseDocumentDiagnosticsIfNeeded(
            Document document, StateSet stateSet, AnalysisKind kind,
            ImmutableArray<DiagnosticData> oldItems, ImmutableArray<DiagnosticData> newItems,
            Action<DiagnosticsUpdatedArgs> raiseEvents)
        {
            if (oldItems.IsEmpty && newItems.IsEmpty)
            {
                // there is nothing to update
                return;
            }

            RaiseDiagnosticsCreated(document, stateSet, kind, newItems, raiseEvents);
        }
            private async Task<IEnumerable<Diagnostic>> ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(
                Document document, DocumentDiagnosticAnalyzer analyzer, AnalysisKind kind, Compilation compilationOpt, CancellationToken cancellationToken)
            {
                using (var pooledObject = SharedPools.Default<List<Diagnostic>>().GetPooledObject())
                {
                    var diagnostics = pooledObject.Object;
                    cancellationToken.ThrowIfCancellationRequested();

                    try
                    {
                        switch (kind)
                        {
                            case AnalysisKind.Syntax:
                                await analyzer.AnalyzeSyntaxAsync(document, diagnostics.Add, cancellationToken).ConfigureAwait(false);
                                return compilationOpt == null ? diagnostics.ToImmutableArrayOrEmpty() : CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, compilationOpt);
                            case AnalysisKind.Semantic:
                                await analyzer.AnalyzeSemanticsAsync(document, diagnostics.Add, cancellationToken).ConfigureAwait(false);
                                return compilationOpt == null ? diagnostics.ToImmutableArrayOrEmpty() : CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, compilationOpt);
                            default:
                                return Contract.FailWithReturn<ImmutableArray<Diagnostic>>("shouldn't reach here");
                        }
                    }
                    catch (Exception e) when (!IsCanceled(e, cancellationToken))
                    {
                        OnAnalyzerException(analyzer, document.Project.Id, compilationOpt, e);
                        return ImmutableArray<Diagnostic>.Empty;
                    }
                }
            }