public DiagnosticIncrementalAnalyzer( DiagnosticAnalyzerService analyzerService, int correlationId, Workspace workspace, HostDiagnosticAnalyzers hostAnalyzers, DiagnosticAnalyzerInfoCache analyzerInfoCache, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) { Contract.ThrowIfNull(analyzerService); AnalyzerService = analyzerService; Workspace = workspace; HostAnalyzers = hostAnalyzers; DiagnosticAnalyzerInfoCache = analyzerInfoCache; HostDiagnosticUpdateSource = hostDiagnosticUpdateSource; PersistentStorageService = workspace.Services.GetRequiredService <IPersistentStorageService>(); _correlationId = correlationId; _stateManager = new StateManager(hostAnalyzers, PersistentStorageService, analyzerInfoCache); _stateManager.ProjectAnalyzerReferenceChanged += OnProjectAnalyzerReferenceChanged; _telemetry = new DiagnosticAnalyzerTelemetry(); _diagnosticAnalyzerRunner = new InProcOrRemoteHostAnalyzerRunner(analyzerService.Listener, analyzerInfoCache, HostDiagnosticUpdateSource); _projectCompilationsWithAnalyzers = new ConditionalWeakTable <Project, CompilationWithAnalyzers?>(); }
public StateManager(DiagnosticAnalyzerInfoCache analyzerInfoCache) { _analyzerInfoCache = analyzerInfoCache; _hostAnalyzerStateMap = ImmutableDictionary <string, HostAnalyzerStateSets> .Empty; _projectAnalyzerStateMap = new ConcurrentDictionary <ProjectId, ProjectAnalyzerStateSets>(concurrencyLevel: 2, capacity: 10); }
private static ImmutableDictionary <DiagnosticAnalyzer, StateSet> CreateStateSetMap( DiagnosticAnalyzerInfoCache analyzerInfoCache, string language, IEnumerable <ImmutableArray <DiagnosticAnalyzer> > analyzerCollection) { var compilerAnalyzer = analyzerInfoCache.GetCompilerDiagnosticAnalyzer(language); var builder = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, StateSet>(); foreach (var analyzers in analyzerCollection) { foreach (var analyzer in analyzers) { // TODO: // #1, all de-duplication should move to DiagnosticAnalyzerInfoCache // #2, not sure whether de-duplication of analyzer itself makes sense. this can only happen // if user deliberately put same analyzer twice. if (builder.ContainsKey(analyzer)) { continue; } var buildToolName = analyzer == compilerAnalyzer ? PredefinedBuildTools.Live : GetBuildToolName(analyzerInfoCache, language, analyzer); builder.Add(analyzer, new StateSet(language, analyzer, buildToolName)); } } return(builder.ToImmutable()); }
private ImmutableDictionary <DiagnosticAnalyzer, DiagnosticAnalysisResult> CreateAnalysisResults( Project project, ImmutableArray <StateSet> stateSets, ImmutableArray <DiagnosticData> diagnostics) { using var poolObject = SharedPools.Default <HashSet <string> >().GetPooledObject(); var lookup = diagnostics.ToLookup(d => d.Id); var builder = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, DiagnosticAnalysisResult>(); using var _ = PooledHashSet <DocumentId> .GetInstance(out var existingDocumentsInStateSet); foreach (var stateSet in stateSets) { var descriptors = DiagnosticAnalyzerInfoCache.GetDiagnosticDescriptors(stateSet.Analyzer); var liveDiagnostics = ConvertToLiveDiagnostics(lookup, descriptors, poolObject.Object); // Ensure that all documents with diagnostics in the previous state set are added to the result. existingDocumentsInStateSet.Clear(); stateSet.CollectDocumentsWithDiagnostics(project.Id, existingDocumentsInStateSet); builder.Add(stateSet.Analyzer, DiagnosticAnalysisResult.CreateFromBuild(project, liveDiagnostics, existingDocumentsInStateSet)); } return(builder.ToImmutable()); }
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 <ImmutableDictionary <DiagnosticAnalyzer, DiagnosticAnalysisResult> > RemoveCompilerSemanticErrorsIfProjectNotLoadedAsync( ImmutableDictionary <DiagnosticAnalyzer, DiagnosticAnalysisResult> result, Project project, CancellationToken cancellationToken) { // see whether solution is loaded successfully var projectLoadedSuccessfully = await project.HasSuccessfullyLoadedAsync(cancellationToken).ConfigureAwait(false); if (projectLoadedSuccessfully) { return(result); } var compilerAnalyzer = DiagnosticAnalyzerInfoCache.GetCompilerDiagnosticAnalyzer(project.Language); if (compilerAnalyzer == null) { // this language doesn't support compiler analyzer return(result); } if (!result.TryGetValue(compilerAnalyzer, out var analysisResult)) { // no result from compiler analyzer return(result); } Logger.Log(FunctionId.Diagnostics_ProjectDiagnostic, p => $"Failed to Load Successfully ({p.FilePath ?? p.Name})", project); // get rid of any result except syntax from compiler analyzer result var newCompilerAnalysisResult = analysisResult.DropExceptSyntax(); // return new result return(result.SetItem(compilerAnalyzer, newCompilerAnalysisResult)); }
private bool IsCandidateForFullSolutionAnalysis(DiagnosticAnalyzer analyzer, Project project, ImmutableDictionary <string, ReportDiagnostic> analyzerConfigSpecialDiagnosticOptions) { // PERF: Don't query descriptors for compiler analyzer or file content load analyzer, always execute them. if (analyzer == FileContentLoadAnalyzer.Instance || analyzer.IsCompilerAnalyzer()) { return(true); } if (analyzer.IsBuiltInAnalyzer()) { // always return true for builtin analyzer. we can't use // descriptor check since many builtin analyzer always return // hidden descriptor regardless what descriptor it actually // return on runtime. they do this so that they can control // severity through option page rather than rule set editor. // this is special behavior only ide analyzer can do. we hope // once we support editorconfig fully, third party can use this // ability as well and we can remove this kind special treatment on builtin // analyzer. return(true); } if (analyzer is DiagnosticSuppressor) { // Always execute diagnostic suppressors. return(true); } // For most of analyzers, the number of diagnostic descriptors is small, so this should be cheap. var descriptors = DiagnosticAnalyzerInfoCache.GetDiagnosticDescriptors(analyzer); return(descriptors.Any(d => d.GetEffectiveSeverity(project.CompilationOptions !, analyzerConfigSpecialDiagnosticOptions) != ReportDiagnostic.Hidden)); }
public CodeAnalysisService(Stream stream, IServiceProvider serviceProvider) : base(serviceProvider, stream) { _analyzerInfoCache = new DiagnosticAnalyzerInfoCache(); StartService(); }
public DiagnosticComputer(Project project, DiagnosticAnalyzerInfoCache analyzerInfoCache) { _project = project; _analyzerInfoCache = analyzerInfoCache; // we only track performance from primary branch. all forked branch we don't care such as preview. _performanceTracker = project.IsFromPrimaryBranch() ? project.Solution.Workspace.Services.GetService <IPerformanceTrackerService>() : null; }
private void UpdateAnalyzerTelemetryData(ImmutableDictionary <DiagnosticAnalyzer, AnalyzerTelemetryInfo> telemetry) { foreach (var(analyzer, telemetryInfo) in telemetry) { var isTelemetryCollectionAllowed = DiagnosticAnalyzerInfoCache.IsTelemetryCollectionAllowed(analyzer); _telemetry.UpdateAnalyzerActionsTelemetry(analyzer, telemetryInfo, isTelemetryCollectionAllowed); } }
public StateManager(HostDiagnosticAnalyzers hostAnalyzers, IPersistentStorageService persistentStorageService, DiagnosticAnalyzerInfoCache analyzerInfoCache) { _hostAnalyzers = hostAnalyzers; _persistentStorageService = persistentStorageService; _analyzerInfoCache = analyzerInfoCache; _hostAnalyzerStateMap = ImmutableDictionary <string, HostAnalyzerStateSets> .Empty; _projectAnalyzerStateMap = new ConcurrentDictionary <ProjectId, ProjectAnalyzerStateSets>(concurrencyLevel: 2, capacity: 10); }
public CodeAnalysisService(Stream stream, IServiceProvider serviceProvider) : base(serviceProvider, stream) { // TODO: currently we only use the cache for information that doesn't involve references or packages. // Once we move all analysis OOP we will create the full cache. _analyzerInfoCache = new DiagnosticAnalyzerInfoCache(ImmutableArray <AnalyzerReference> .Empty); StartService(); }
public InProcOrRemoteHostAnalyzerRunner(IAsynchronousOperationListener operationListener, DiagnosticAnalyzerInfoCache analyzerInfoCache) { _asyncOperationListener = operationListener; _analyzerInfoCache = analyzerInfoCache; // currently option is a bit weird since it is not part of snapshot and // we can't load all options without loading all language specific dlls. // we have tracking issue for this. // https://github.com/dotnet/roslyn/issues/13643 _lastOptionSetPerLanguage = new ConcurrentDictionary <string, ValueTuple <OptionSet, CustomAsset> >(); }
public HostAnalyzerStateSets(DiagnosticAnalyzerInfoCache analyzerInfoCache, string language, ImmutableDictionary <DiagnosticAnalyzer, StateSet> analyzerMap) { StateSetMap = analyzerMap; _compilerAnalyzer = analyzerInfoCache.GetCompilerDiagnosticAnalyzer(language); // order statesets // order will be in this order // BuiltIn Compiler Analyzer (C#/VB) < Regular DiagnosticAnalyzers < Document/ProjectDiagnosticAnalyzers OrderedStateSets = StateSetMap.Values.OrderBy(PriorityComparison).ToImmutableArray(); }
public RemoteHostClientService( IThreadingContext threadingContext, IAsynchronousOperationListener listener, Workspace workspace, DiagnosticAnalyzerInfoCache analyzerInfoCache) : base(threadingContext) { _gate = new object(); _listener = listener; _workspace = workspace; _analyzerInfoCache = analyzerInfoCache; }
public ProjectAnalyzerStateSets( Project project, ImmutableDictionary <object, ImmutableArray <DiagnosticAnalyzer> > mapPerReferences, ImmutableDictionary <DiagnosticAnalyzer, StateSet> analyzerMap, DiagnosticAnalyzerInfoCache analyzerInfoCache, HostDiagnosticAnalyzers hostAnalyzers) : this(project.AnalyzerReferences, mapPerReferences, analyzerMap, analyzerInfoCache.GetOrCreateSkippedAnalyzersInfo(project, hostAnalyzers)) { Contract.ThrowIfNull(project); Contract.ThrowIfNull(mapPerReferences); Contract.ThrowIfNull(analyzerMap); }
private static string GetBuildToolName(DiagnosticAnalyzerInfoCache analyzerInfoCache, string language, DiagnosticAnalyzer analyzer) { var packageName = analyzerInfoCache.GetDiagnosticAnalyzerPackageName(language, analyzer); if (packageName == null) { return(analyzer.GetAnalyzerAssemblyName()); } if (packageName == RoslynLanguageServices) { return(PredefinedBuildTools.Live); } return($"{analyzer.GetAnalyzerAssemblyName()} [{packageName}]"); }
public DiagnosticComputer( TextDocument?document, Project project, TextSpan?span, AnalysisKind?analysisKind, DiagnosticAnalyzerInfoCache analyzerInfoCache) { _document = document; _project = project; _span = span; _analysisKind = analysisKind; _analyzerInfoCache = analyzerInfoCache; // We only track performance from primary branch. All forked branch we don't care such as preview. _performanceTracker = project.IsFromPrimaryBranch() ? project.Solution.Workspace.Services.GetService <IPerformanceTrackerService>() : null; }
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; } } }
public DiagnosticIncrementalAnalyzer( DiagnosticAnalyzerService analyzerService, int correlationId, Workspace workspace, DiagnosticAnalyzerInfoCache analyzerInfoCache) { Contract.ThrowIfNull(analyzerService); AnalyzerService = analyzerService; Workspace = workspace; _documentTrackingService = workspace.Services.GetRequiredService <IDocumentTrackingService>(); _correlationId = correlationId; _stateManager = new StateManager(workspace, analyzerInfoCache); _stateManager.ProjectAnalyzerReferenceChanged += OnProjectAnalyzerReferenceChanged; _telemetry = new DiagnosticAnalyzerTelemetry(); _diagnosticAnalyzerRunner = new InProcOrRemoteHostAnalyzerRunner(analyzerInfoCache, analyzerService.Listener); _projectCompilationsWithAnalyzers = new ConditionalWeakTable <Project, CompilationWithAnalyzers?>(); }
private ImmutableDictionary <DiagnosticAnalyzer, DiagnosticAnalysisResult> CreateAnalysisResults( Project project, ImmutableArray <StateSet> stateSets, ProjectAnalysisData oldAnalysisData, ImmutableArray <DiagnosticData> diagnostics) { using var poolObject = SharedPools.Default <HashSet <string> >().GetPooledObject(); var lookup = diagnostics.ToLookup(d => d.Id); var builder = ImmutableDictionary.CreateBuilder <DiagnosticAnalyzer, DiagnosticAnalysisResult>(); foreach (var stateSet in stateSets) { var descriptors = DiagnosticAnalyzerInfoCache.GetDiagnosticDescriptors(stateSet.Analyzer); var liveDiagnostics = MergeDiagnostics( ConvertToLiveDiagnostics(lookup, descriptors, poolObject.Object), oldAnalysisData.GetResult(stateSet.Analyzer).GetAllDiagnostics()); builder.Add(stateSet.Analyzer, DiagnosticAnalysisResult.CreateFromBuild(project, liveDiagnostics)); } return(builder.ToImmutable()); }
public DiagnosticIncrementalAnalyzer( DiagnosticAnalyzerService analyzerService, int correlationId, Workspace workspace, DiagnosticAnalyzerInfoCache analyzerInfoCache, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource) { Contract.ThrowIfNull(analyzerService); AnalyzerService = analyzerService; Workspace = workspace; DiagnosticAnalyzerInfoCache = analyzerInfoCache; HostDiagnosticUpdateSource = hostDiagnosticUpdateSource; DiagnosticLogAggregator = new DiagnosticLogAggregator(analyzerService); _correlationId = correlationId; _stateManager = new StateManager(analyzerInfoCache); _stateManager.ProjectAnalyzerReferenceChanged += OnProjectAnalyzerReferenceChanged; _diagnosticAnalyzerRunner = new InProcOrRemoteHostAnalyzerRunner(AnalyzerService, HostDiagnosticUpdateSource); _projectCompilationsWithAnalyzers = new ConditionalWeakTable <Project, CompilationWithAnalyzers?>(); }
static HostAnalyzerStateSets CreateLanguageSpecificAnalyzerMap(string language, DiagnosticAnalyzerInfoCache analyzerInfoCache) { var analyzersPerReference = analyzerInfoCache.GetOrCreateHostDiagnosticAnalyzersPerReference(language); var analyzerMap = CreateStateSetMap(analyzerInfoCache, language, analyzersPerReference.Values); VerifyUniqueStateNames(analyzerMap.Values); return(new HostAnalyzerStateSets(analyzerInfoCache, language, analyzerMap)); }
private ISkippedAnalyzersInfo GetOrCreateSkippedAnalyzersInfo(Project project) => DiagnosticAnalyzerInfoCache.GetOrCreateSkippedAnalyzersInfo(project, HostAnalyzers);
private static DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner CreateAnalyzerRunner(Workspace workspace) { var infoCache = new DiagnosticAnalyzerInfoCache(ImmutableArray <AnalyzerReference> .Empty); return(new DiagnosticIncrementalAnalyzer.InProcOrRemoteHostAnalyzerRunner(AsynchronousOperationListenerProvider.NullListener, infoCache, hostDiagnosticUpdateSource: new MyUpdateSource(workspace))); }
public InProcOrRemoteHostAnalyzerRunner(IAsynchronousOperationListener operationListener, DiagnosticAnalyzerInfoCache analyzerInfoCache) { _asyncOperationListener = operationListener; _analyzerInfoCache = analyzerInfoCache; }