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?>();
        }
Exemple #2
0
            public StateManager(DiagnosticAnalyzerInfoCache analyzerInfoCache)
            {
                _analyzerInfoCache = analyzerInfoCache;

                _hostAnalyzerStateMap    = ImmutableDictionary <string, HostAnalyzerStateSets> .Empty;
                _projectAnalyzerStateMap = new ConcurrentDictionary <ProjectId, ProjectAnalyzerStateSets>(concurrencyLevel: 2, capacity: 10);
            }
Exemple #3
0
            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());
        }
Exemple #5
0
        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));
        }
Exemple #8
0
        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;
        }
Exemple #10
0
 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;
            }
Exemple #16
0
 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);
 }
Exemple #17
0
            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}]");
            }
Exemple #18
0
        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?>();
        }
Exemple #22
0
        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));
                }
Exemple #25
0
 private ISkippedAnalyzersInfo GetOrCreateSkippedAnalyzersInfo(Project project)
 => DiagnosticAnalyzerInfoCache.GetOrCreateSkippedAnalyzersInfo(project, HostAnalyzers);
Exemple #26
0
        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;
 }