Ejemplo n.º 1
0
            /// <summary>
            /// Return all diagnostics that belong to given project for the given StateSets (analyzers) either from cache or by calculating them
            /// </summary>
            public async Task <ProjectAnalysisData> GetProjectAnalysisDataAsync(
                CompilationWithAnalyzers analyzerDriverOpt, Project project, IEnumerable <StateSet> stateSets, bool ignoreFullAnalysisOptions, CancellationToken cancellationToken)
            {
                using (Logger.LogBlock(FunctionId.Diagnostics_ProjectDiagnostic, GetProjectLogMessage, project, stateSets, cancellationToken))
                {
                    try
                    {
                        // PERF: we need to flip this to false when we do actual diffing.
                        var avoidLoadingData = true;
                        var version          = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

                        var existingData = await ProjectAnalysisData.CreateAsync(project, stateSets, avoidLoadingData, cancellationToken).ConfigureAwait(false);

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

                        // perf optimization. check whether we want to analyze this project or not.
                        if (!await FullAnalysisEnabledAsync(project, ignoreFullAnalysisOptions, cancellationToken).ConfigureAwait(false))
                        {
                            return(new ProjectAnalysisData(project.Id, VersionStamp.Default, existingData.Result, ImmutableDictionary <DiagnosticAnalyzer, AnalysisResult> .Empty));
                        }

                        var result = await ComputeDiagnosticsAsync(analyzerDriverOpt, project, stateSets, existingData.Result, cancellationToken).ConfigureAwait(false);

                        return(new ProjectAnalysisData(project.Id, version, existingData.Result, result));
                    }
                    catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
                    {
                        throw ExceptionUtilities.Unreachable;
                    }
                }
            }
Ejemplo n.º 2
0
        public async Task SynchronizeWithBuildAsync(ImmutableDictionary <ProjectId, ImmutableArray <DiagnosticData> > buildDiagnostics, bool onBuildCompleted)
        {
            var options = Workspace.Options;

            using (Logger.LogBlock(FunctionId.DiagnosticIncrementalAnalyzer_SynchronizeWithBuildAsync, LogSynchronizeWithBuild, options, buildDiagnostics, CancellationToken.None))
            {
                DebugVerifyDiagnosticLocations(buildDiagnostics);

                if (!PreferBuildErrors(options))
                {
                    // Prefer live errors over build errors
                    return;
                }

                var solution = Workspace.CurrentSolution;

                foreach (var(projectId, diagnostics) in buildDiagnostics)
                {
                    var project = solution.GetProject(projectId);
                    if (project == null)
                    {
                        continue;
                    }

                    // REVIEW: do build diagnostics include suppressed diagnostics?
                    var stateSets = _stateManager.CreateBuildOnlyProjectStateSet(project);

                    // We load data since we don't know right version.
                    var oldAnalysisData = await ProjectAnalysisData.CreateAsync(PersistentStorageService, project, stateSets, avoidLoadingData : false, CancellationToken.None).ConfigureAwait(false);

                    var newResult = CreateAnalysisResults(project, stateSets, oldAnalysisData, diagnostics);

                    foreach (var stateSet in stateSets)
                    {
                        var state  = stateSet.GetOrCreateProjectState(project.Id);
                        var result = GetResultOrEmpty(newResult, stateSet.Analyzer, project.Id, VersionStamp.Default);
                        await state.SaveAsync(PersistentStorageService, project, result).ConfigureAwait(false);
                    }

                    // REVIEW: this won't handle active files. might need to tweak it later.
                    RaiseProjectDiagnosticsIfNeeded(project, stateSets, oldAnalysisData.Result, newResult);
                }

                // Refresh diagnostics for open files after solution build completes.
                if (onBuildCompleted && PreferLiveErrorsOnOpenedFiles(options))
                {
                    // Enqueue re-analysis of active document.
                    if (_documentTrackingService?.GetActiveDocument(solution) is { } activeDocument)
                    {
                        AnalyzerService.Reanalyze(Workspace, documentIds: ImmutableArray.Create(activeDocument.Id), highPriority: true);
                    }

                    // Enqueue re-analysis of open documents.
                    AnalyzerService.Reanalyze(Workspace, documentIds: Workspace.GetOpenDocumentIds(), highPriority: true);
                }
            }
        }
Ejemplo n.º 3
0
        public async Task InitializeSynchronizationStateWithBuildAsync(Solution solution, CancellationToken cancellationToken)
        {
            foreach (var project in solution.Projects)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var stateSets = _stateManager.CreateBuildOnlyProjectStateSet(project);
                _ = await ProjectAnalysisData.CreateAsync(PersistentStorageService, project, stateSets, avoidLoadingData : false, cancellationToken).ConfigureAwait(false);
            }
        }
        private async Task <ProjectAnalysisData> CreateProjectAnalysisDataAsync(Project project, ImmutableArray <StateSet> stateSets, ImmutableArray <DiagnosticData> diagnostics)
        {
            // we always load data sicne we don't know right version.
            var avoidLoadingData = false;
            var oldAnalysisData  = await ProjectAnalysisData.CreateAsync(project, stateSets, avoidLoadingData, CancellationToken.None).ConfigureAwait(false);

            var newResult = CreateAnalysisResults(project, stateSets, oldAnalysisData, diagnostics);

            return(new ProjectAnalysisData(project.Id, VersionStamp.Default, oldAnalysisData.Result, newResult));
        }
Ejemplo n.º 5
0
        public async Task SynchronizeWithBuildAsync(Workspace workspace, ImmutableDictionary <ProjectId, ImmutableArray <DiagnosticData> > buildDiagnostics)
        {
            using (Logger.LogBlock(FunctionId.DiagnosticIncrementalAnalyzer_SynchronizeWithBuildAsync, (w, m) => LogSynchronizeWithBuild(w, m), workspace, buildDiagnostics, CancellationToken.None))
            {
                DebugVerifyDiagnosticLocations(buildDiagnostics);

                if (!PreferBuildErrors(workspace))
                {
                    // prefer live errors over build errors
                    return;
                }

                var solution = workspace.CurrentSolution;
                foreach (var(projectId, diagnostics) in buildDiagnostics)
                {
                    var project = solution.GetProject(projectId);
                    if (project == null)
                    {
                        continue;
                    }

                    // REVIEW: do build diagnostics include suppressed diagnostics?
                    var stateSets = _stateManager.CreateBuildOnlyProjectStateSet(project);

                    // we load data since we don't know right version.
                    var oldAnalysisData = await ProjectAnalysisData.CreateAsync(project, stateSets, avoidLoadingData : false, CancellationToken.None).ConfigureAwait(false);

                    var newResult = CreateAnalysisResults(project, stateSets, oldAnalysisData, diagnostics);

                    foreach (var stateSet in stateSets)
                    {
                        var state  = stateSet.GetOrCreateProjectState(project.Id);
                        var result = GetResultOrEmpty(newResult, stateSet.Analyzer, project.Id, VersionStamp.Default);
                        await state.SaveAsync(project, result).ConfigureAwait(false);
                    }

                    // REVIEW: this won't handle active files. might need to tweak it later.
                    RaiseProjectDiagnosticsIfNeeded(project, stateSets, oldAnalysisData.Result, newResult);
                }

                // if we have updated errors, refresh open files
                if (buildDiagnostics.Count > 0 && PreferLiveErrorsOnOpenedFiles(workspace))
                {
                    // enqueue re-analysis of open documents.
                    AnalyzerService.Reanalyze(workspace, documentIds: workspace.GetOpenDocumentIds(), highPriority: true);
                }
            }
        }
Ejemplo n.º 6
0
        private async Task <ProjectAnalysisData> GetProjectAnalysisDataAsync(
            CompilationWithAnalyzers?compilationWithAnalyzers, Project project, IEnumerable <StateSet> stateSets, bool forceAnalyzerRun, CancellationToken cancellationToken)
        {
            using (Logger.LogBlock(FunctionId.Diagnostics_ProjectDiagnostic, GetProjectLogMessage, project, stateSets, cancellationToken))
            {
                try
                {
                    // PERF: We need to flip this to false when we do actual diffing.
                    var avoidLoadingData = true;
                    var version          = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

                    var existingData = await ProjectAnalysisData.CreateAsync(PersistentStorageService, project, stateSets, avoidLoadingData, cancellationToken).ConfigureAwait(false);

                    // We can't return here if we have open file only analyzers since saved data for open file only analyzer
                    // is incomplete -- it only contains info on open files rather than whole project.
                    if (existingData.Version == version && !CompilationHasOpenFileOnlyAnalyzers(compilationWithAnalyzers, project.Solution.Options))
                    {
                        return(existingData);
                    }

                    // PERF: Check whether we want to analyze this project or not.
                    if (!FullAnalysisEnabled(project, forceAnalyzerRun))
                    {
                        Logger.Log(FunctionId.Diagnostics_ProjectDiagnostic, p => $"FSA off ({p.FilePath ?? p.Name})", project);

                        return(new ProjectAnalysisData(project.Id, VersionStamp.Default, existingData.Result, ImmutableDictionary <DiagnosticAnalyzer, DiagnosticAnalysisResult> .Empty));
                    }

                    var result = await ComputeDiagnosticsAsync(compilationWithAnalyzers, project, stateSets, forceAnalyzerRun, existingData.Result, cancellationToken).ConfigureAwait(false);

                    // If project is not loaded successfully, get rid of any semantic errors from compiler analyzer.
                    // Note: In the past when project was not loaded successfully we did not run any analyzers on the project.
                    // Now we run analyzers but filter out some information. So on such projects, there will be some perf degradation.
                    result = await RemoveCompilerSemanticErrorsIfProjectNotLoadedAsync(result, project, cancellationToken).ConfigureAwait(false);

                    return(new ProjectAnalysisData(project.Id, version, existingData.Result, result));
                }
                catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
                {
                    throw ExceptionUtilities.Unreachable;
                }
            }
        }
            /// <summary>
            /// Return all diagnostics that belong to given project for the given StateSets (analyzers) either from cache or by calculating them
            /// </summary>
            public async Task <ProjectAnalysisData> GetProjectAnalysisDataAsync(
                CompilationWithAnalyzers analyzerDriverOpt, Project project, IEnumerable <StateSet> stateSets, bool forceAnalyzerRun, CancellationToken cancellationToken)
            {
                using (Logger.LogBlock(FunctionId.Diagnostics_ProjectDiagnostic, GetProjectLogMessage, project, stateSets, cancellationToken))
                {
                    try
                    {
                        // PERF: we need to flip this to false when we do actual diffing.
                        var avoidLoadingData = true;
                        var version          = await GetDiagnosticVersionAsync(project, cancellationToken).ConfigureAwait(false);

                        var existingData = await ProjectAnalysisData.CreateAsync(project, stateSets, avoidLoadingData, cancellationToken).ConfigureAwait(false);

                        // we can't return here if we have open file only analyzers sine saved data for open file only analyzer
                        // is wrong. (since it only contains info on open files rather than whole project)
                        if (existingData.Version == version && !analyzerDriverOpt.ContainsOpenFileOnlyAnalyzers(project.Solution.Workspace))
                        {
                            return(existingData);
                        }

                        // perf optimization. check whether we want to analyze this project or not.
                        if (!FullAnalysisEnabled(project, forceAnalyzerRun))
                        {
                            Logger.Log(FunctionId.Diagnostics_ProjectDiagnostic, p => $"FSA off ({p.FilePath ?? p.Name})", project);

                            return(new ProjectAnalysisData(project.Id, VersionStamp.Default, existingData.Result, ImmutableDictionary <DiagnosticAnalyzer, DiagnosticAnalysisResult> .Empty));
                        }

                        var result = await ComputeDiagnosticsAsync(analyzerDriverOpt, project, stateSets, forceAnalyzerRun, existingData.Result, cancellationToken).ConfigureAwait(false);

                        // if project is not loaded successfully, get rid of any semantic errors from compiler analyzer
                        // * NOTE * previously when project is not loaded successfully, we actually dropped doing anything on the project, but now
                        //          we do everything but filter out some information. so on such projects, there will be some perf degradation.
                        result = await FilterOutCompilerSemanticErrorsIfNeccessaryAsync(project, result, cancellationToken).ConfigureAwait(false);

                        return(new ProjectAnalysisData(project.Id, version, existingData.Result, result));
                    }
                    catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
                    {
                        throw ExceptionUtilities.Unreachable;
                    }
                }
            }