Exemple #1
0
        internal static async ValueTask <ImmutableArray <IDiagnosticSource> > GetWorkspacePullDocumentsAsync(RequestContext context, IGlobalOptionService globalOptions, CancellationToken cancellationToken)
        {
            Contract.ThrowIfNull(context.Solution);

            // If we're being called from razor, we do not support WorkspaceDiagnostics at all.  For razor, workspace
            // diagnostics will be handled by razor itself, which will operate by calling into Roslyn and asking for
            // document-diagnostics instead.
            if (context.ServerKind == WellKnownLspServerKinds.RazorLspServer)
            {
                return(ImmutableArray <IDiagnosticSource> .Empty);
            }

            using var _ = ArrayBuilder <IDiagnosticSource> .GetInstance(out var result);

            var solution = context.Solution;

            var documentTrackingService = solution.Services.GetRequiredService <IDocumentTrackingService>();

            // Collect all the documents from the solution in the order we'd like to get diagnostics for.  This will
            // prioritize the files from currently active projects, but then also include all other docs in all projects
            // (depending on current FSA settings).

            var activeDocument   = documentTrackingService.GetActiveDocument(solution);
            var visibleDocuments = documentTrackingService.GetVisibleDocuments(solution);

            // Now, prioritize the projects related to the active/visible files.
            await AddDocumentsAndProject(activeDocument?.Project, context.SupportedLanguages, isOpen : true, cancellationToken).ConfigureAwait(false);

            foreach (var doc in visibleDocuments)
            {
                await AddDocumentsAndProject(doc.Project, context.SupportedLanguages, isOpen : true, cancellationToken).ConfigureAwait(false);
            }

            // finally, add the remainder of all documents.
            foreach (var project in solution.Projects)
            {
                await AddDocumentsAndProject(project, context.SupportedLanguages, isOpen : false, cancellationToken).ConfigureAwait(false);
            }

            // Ensure that we only process documents once.
            result.RemoveDuplicates();
            return(result.ToImmutable());

            async Task AddDocumentsAndProject(Project?project, ImmutableArray <string> supportedLanguages, bool isOpen, CancellationToken cancellationToken)
            {
                if (project == null)
                {
                    return;
                }

                if (!supportedLanguages.Contains(project.Language))
                {
                    // This project is for a language not supported by the LSP server making the request.
                    // Do not report diagnostics for these projects.
                    return;
                }

                var isFSAOn   = globalOptions.IsFullSolutionAnalysisEnabled(project.Language);
                var documents = ImmutableArray <TextDocument> .Empty;

                // If FSA is on, then add all the documents in the project.  Other analysis scopes are handled by the document pull handler.
                if (isFSAOn)
                {
                    documents = documents.AddRange(project.Documents).AddRange(project.AdditionalDocuments);
                }

                // If all features are enabled for source generated documents, make sure they are included when FSA is on or a file in the project is open.
                // This is done because for either scenario we've already run generators, so there shouldn't be much cost in getting the diagnostics.
                if ((isFSAOn || isOpen) && solution.Services.GetService <IWorkspaceConfigurationService>()?.Options.EnableOpeningSourceGeneratedFiles == true)
                {
                    var sourceGeneratedDocuments = await project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false);

                    documents = documents.AddRange(sourceGeneratedDocuments);
                }

                foreach (var document in documents)
                {
                    // Only consider closed documents here (and only open ones in the DocumentPullDiagnosticHandler).
                    // Each handler treats those as separate worlds that they are responsible for.
                    if (context.IsTracking(document.GetURI()))
                    {
                        context.TraceInformation($"Skipping tracked document: {document.GetURI()}");
                        continue;
                    }

                    // Do not attempt to get workspace diagnostics for Razor files, Razor will directly ask us for document diagnostics
                    // for any razor file they are interested in.
                    if (document.IsRazorDocument())
                    {
                        continue;
                    }

                    result.Add(new WorkspaceDocumentDiagnosticSource(document));
                }

                // Finally, if FSA is on we also want to check for diagnostics associated with the project itself.
                if (isFSAOn)
                {
                    result.Add(new ProjectDiagnosticSource(project));
                }
            }
        }