private async Task <DocumentAnalysisData?> TryGetCachedDocumentAnalysisDataAsync( TextDocument document, StateSet stateSet, AnalysisKind kind, CancellationToken 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 (DiagnosticAnalyzerInfoCache.IsAnalyzerSuppressed(stateSet.Analyzer, document.Project)) { return(new DocumentAnalysisData(version, existingData.Items, ImmutableArray <DiagnosticData> .Empty)); } return(null); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
private async Task AnalyzeProjectAsync(Project project, bool forceAnalyzerRun, CancellationToken cancellationToken) { try { var stateSets = GetStateSetsForFullSolutionAnalysis(_stateManager.GetOrUpdateStateSets(project), project).ToList(); var options = project.Solution.Options; // 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 => !DiagnosticAnalyzerInfoCache.IsAnalyzerSuppressed(a, project) && !a.IsOpenFileOnly(options)); // get driver only with active analyzers. var compilationWithAnalyzers = await AnalyzerHelper.CreateCompilationWithAnalyzersAsync(project, activeAnalyzers, includeSuppressedDiagnostics : true, cancellationToken).ConfigureAwait(false); var result = await GetProjectAnalysisDataAsync(compilationWithAnalyzers, project, stateSets, forceAnalyzerRun, cancellationToken).ConfigureAwait(false); if (result.OldResult == null) { RaiseProjectDiagnosticsIfNeeded(project, stateSets, result.Result); return; } // we might not have compilationWithAnalyzers even if project supports compilation if we are called with no analyzers. var compilation = compilationWithAnalyzers?.Compilation ?? (project.SupportsCompilation ? await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false) : null); // 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.SaveAsync(PersistentStorageService, project, result.GetResult(stateSet.Analyzer)).ConfigureAwait(false); stateSet.ComputeCompilationEndAnalyzer(project, compilation); } RaiseProjectDiagnosticsIfNeeded(project, stateSets, result.OldResult, result.Result); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
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 (DiagnosticAnalyzerInfoCache.IsAnalyzerSuppressed(stateSet.Analyzer, document.Project)) { return(new DocumentAnalysisData(version, existingData.Items, ImmutableArray <DiagnosticData> .Empty)); } var diagnostics = await AnalyzerHelper.ComputeDiagnosticsAsync(stateSet.Analyzer, document, kind, DiagnosticAnalyzerInfoCache, compilation, span : null, 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; } } }