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;
                    }
                }
Exemple #17
0
                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"));
                    }
                }
Exemple #18
0
                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);
                }
Exemple #19
0
 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");
     }
 }