Exemple #1
0
        /// <summary>
        /// Return list of <see cref="StateSet"/> to be used for full solution analysis.
        /// </summary>
        private ImmutableArray <StateSet> GetStateSetsForFullSolutionAnalysis(ImmutableArray <StateSet> stateSets, Project project)
        {
            // If full analysis is off, remove state that is created from build.
            // this will make sure diagnostics from build (converted from build to live) will never be cleared
            // until next build.
            _ = GlobalOptions.IsFullSolutionAnalysisEnabled(project.Language, out var compilerFullSolutionAnalysisEnabled, out var analyzersFullSolutionAnalysisEnabled);
            if (!compilerFullSolutionAnalysisEnabled)
            {
                // Full solution analysis is not enabled for compiler diagnostics,
                // so we remove the compiler analyzer state sets that are from build.
                // We do so by retaining only those state sets that are
                // either not for compiler analyzer or those which are for compiler
                // analyzer, but not from build.
                stateSets = stateSets.WhereAsArray(s => !s.Analyzer.IsCompilerAnalyzer() || !s.FromBuild(project.Id));
            }

            if (!analyzersFullSolutionAnalysisEnabled)
            {
                // Full solution analysis is not enabled for analyzer diagnostics,
                // so we remove the analyzer state sets that are from build.
                // We do so by retaining only those state sets that are
                // either for the special compiler/workspace analyzers or those which are for
                // other analyzers, but not from build.
                stateSets = stateSets.WhereAsArray(s => s.Analyzer.IsCompilerAnalyzer() || s.Analyzer.IsWorkspaceDiagnosticAnalyzer() || !s.FromBuild(project.Id));
            }

            // Include only analyzers we want to run for full solution analysis.
            // Analyzers not included here will never be saved because result is unknown.
            return(stateSets.WhereAsArray(s => IsCandidateForFullSolutionAnalysis(s.Analyzer, project)));
        }
Exemple #2
0
        private void RaiseDiagnosticsRemovedIfRequiredForClosedOrResetDocument(TextDocument document, IEnumerable <StateSet> stateSets, bool documentHadDiagnostics)
        {
            // If there was no diagnostic reported for this document, nothing to clean up
            // This is done for Perf to reduce raising events unnecessarily.
            if (!documentHadDiagnostics)
            {
                return;
            }

            // If full solution analysis is enabled for both compiler diagnostics and analyzers,
            // we don't need to clear diagnostics for individual documents on document close/reset.
            // This is done for Perf to reduce raising events unnecessarily.
            var _ = GlobalOptions.IsFullSolutionAnalysisEnabled(document.Project.Language, out var compilerFullAnalysisEnabled, out var analyzersFullAnalysisEnabled);

            if (compilerFullAnalysisEnabled && analyzersFullAnalysisEnabled)
            {
                return;
            }

            var removeDiagnosticsOnDocumentClose = GlobalOptions.GetOption(SolutionCrawlerOptionsStorage.RemoveDocumentDiagnosticsOnDocumentClose, document.Project.Language);

            if (!removeDiagnosticsOnDocumentClose)
            {
                return;
            }

            RaiseDiagnosticsRemovedForDocument(document.Id, stateSets);
        }
Exemple #3
0
        private async Task AnalyzeProjectAsync(Project project, bool forceAnalyzerRun, CancellationToken cancellationToken)
        {
            try
            {
                var stateSets = GetStateSetsForFullSolutionAnalysis(_stateManager.GetOrUpdateStateSets(project), project);

                // get driver only with active analyzers.
                var ideOptions = AnalyzerService.GlobalOptions.GetIdeAnalyzerOptions(project);

                // PERF: get analyzers that are not suppressed and marked as open file only
                // this is perf optimization. we cache these result since we know the result. (no diagnostics)
                var activeAnalyzers = stateSets
                                      .Select(s => s.Analyzer)
                                      .Where(a => DocumentAnalysisExecutor.IsAnalyzerEnabledForProject(a, project, GlobalOptions) && !a.IsOpenFileOnly(ideOptions.CleanupOptions?.SimplifierOptions));

                CompilationWithAnalyzers?compilationWithAnalyzers = null;

                if (forceAnalyzerRun || GlobalOptions.IsFullSolutionAnalysisEnabled(project.Language))
                {
                    compilationWithAnalyzers = await DocumentAnalysisExecutor.CreateCompilationWithAnalyzersAsync(project, ideOptions, activeAnalyzers, includeSuppressedDiagnostics : true, cancellationToken).ConfigureAwait(false);
                }

                var result = await GetProjectAnalysisDataAsync(compilationWithAnalyzers, project, ideOptions, stateSets, forceAnalyzerRun, cancellationToken).ConfigureAwait(false);

                if (result.OldResult == null)
                {
                    RaiseProjectDiagnosticsIfNeeded(project, stateSets, result.Result);
                    return;
                }

                // no cancellation after this point.
                // any analyzer that doesn't have result will be treated as returned empty set
                // which means we will remove those from error list
                foreach (var stateSet in stateSets)
                {
                    var state = stateSet.GetOrCreateProjectState(project.Id);

                    await state.SaveToInMemoryStorageAsync(project, result.GetResult(stateSet.Analyzer)).ConfigureAwait(false);
                }

                RaiseProjectDiagnosticsIfNeeded(project, stateSets, result.OldResult, result.Result);
            }
            catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken))
            {
                throw ExceptionUtilities.Unreachable;
            }
        }
Exemple #4
0
        public async ValueTask SynchronizeWithBuildAsync(
            ImmutableDictionary <ProjectId,
                                 ImmutableArray <DiagnosticData> > buildDiagnostics,
            TaskQueue postBuildAndErrorListRefreshTaskQueue,
            bool onBuildCompleted,
            CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.DiagnosticIncrementalAnalyzer_SynchronizeWithBuildAsync, LogSynchronizeWithBuild, buildDiagnostics, cancellationToken))
            {
                DebugVerifyDiagnosticLocations(buildDiagnostics);

                var solution = Workspace.CurrentSolution;

                foreach (var(projectId, diagnostics) in buildDiagnostics)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var project = solution.GetProject(projectId);
                    if (project == null)
                    {
                        continue;
                    }

                    var stateSets = _stateManager.CreateBuildOnlyProjectStateSet(project);
                    var newResult = CreateAnalysisResults(project, stateSets, diagnostics);

                    // PERF: Save the diagnostics into in-memory cache on the main thread.
                    //       Saving them into persistent storage is expensive, so we invoke that operation on a separate task queue
                    //       to ensure faster error list refresh.
                    foreach (var stateSet in stateSets)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        var state  = stateSet.GetOrCreateProjectState(project.Id);
                        var result = GetResultOrEmpty(newResult, stateSet.Analyzer, project.Id, VersionStamp.Default);

                        await state.SaveToInMemoryStorageAsync(project, result).ConfigureAwait(false);
                    }

                    // Raise diagnostic updated events after the new diagnostics have been stored into the in-memory cache.
                    if (diagnostics.IsEmpty)
                    {
                        ClearAllDiagnostics(stateSets, projectId);
                    }
                    else
                    {
                        RaiseProjectDiagnosticsIfNeeded(project, stateSets, newResult);
                    }
                }

                // Refresh live diagnostics after solution build completes.
                if (onBuildCompleted)
                {
                    // Enqueue re-analysis of active document with high-priority right away.
                    if (_documentTrackingService.GetActiveDocument(solution) is { } activeDocument)
                    {
                        AnalyzerService.Reanalyze(Workspace, documentIds: ImmutableArray.Create(activeDocument.Id), highPriority: true);
                    }

                    // Enqueue remaining re-analysis with normal priority on a separate task queue
                    // that will execute at the end of all the post build and error list refresh tasks.
                    _ = postBuildAndErrorListRefreshTaskQueue.ScheduleTask(nameof(SynchronizeWithBuildAsync), () =>
                    {
                        // Enqueue re-analysis of open documents.
                        AnalyzerService.Reanalyze(Workspace, documentIds: Workspace.GetOpenDocumentIds());

                        // Enqueue re-analysis of projects, if required.
                        foreach (var projectsByLanguage in solution.Projects.GroupBy(p => p.Language))
                        {
                            if (GlobalOptions.IsFullSolutionAnalysisEnabled(projectsByLanguage.Key))
                            {
                                AnalyzerService.Reanalyze(Workspace, projectsByLanguage.Select(p => p.Id));
                            }
                        }
                    }, cancellationToken);
                }
            }
        }