Exemple #1
0
            public void FireEvents(DocumentId documentId, CancellationToken cancellationToken)
            {
                _notificationService.RegisterNotification(() =>
                {
                    var projectCodeModel = _projectCodeModelFactory.TryGetProjectCodeModel(documentId.ProjectId);

                    if (projectCodeModel == null)
                    {
                        return(false);
                    }

                    var filename = _workspace.GetFilePath(documentId);
                    if (filename == null)
                    {
                        return(false);
                    }

                    if (!projectCodeModel.TryGetCachedFileCodeModel(filename, out var fileCodeModelHandle))
                    {
                        return(false);
                    }

                    var codeModel = fileCodeModelHandle.Object;
                    return(codeModel.FireEvents());
                },
                                                          _listener.BeginAsyncOperation("CodeModelEvent"),
                                                          cancellationToken);
            }
Exemple #2
0
        private System.Threading.Tasks.Task ProcessNextDocumentBatchAsync(
            ImmutableArray <DocumentId> documentIds,
            CancellationToken cancellationToken
            )
        {
            foreach (var documentId in documentIds)
            {
                // Now, enqueue foreground work to actually process these documents in a serialized and incremental
                // fashion.  FireEventsForDocument will actually limit how much time it spends firing events so that it
                // doesn't saturate  the UI thread.
                _notificationService.RegisterNotification(
                    () => FireEventsForDocument(documentId),
                    _listener.BeginAsyncOperation("CodeModelEvent"),
                    cancellationToken
                    );
            }

            return(System.Threading.Tasks.Task.CompletedTask);

            bool FireEventsForDocument(DocumentId documentId)
            {
                // If we've been asked to shutdown, don't bother reporting any more events.
                if (_threadingContext.DisposalToken.IsCancellationRequested)
                {
                    return(false);
                }

                var projectCodeModel = this.TryGetProjectCodeModel(documentId.ProjectId);

                if (projectCodeModel == null)
                {
                    return(false);
                }

                var filename = _visualStudioWorkspace.GetFilePath(documentId);

                if (filename == null)
                {
                    return(false);
                }

                if (
                    !projectCodeModel.TryGetCachedFileCodeModel(
                        filename,
                        out var fileCodeModelHandle
                        )
                    )
                {
                    return(false);
                }

                var codeModel = fileCodeModelHandle.Object;

                return(codeModel.FireEvents());
            }
        }
Exemple #3
0
        private async ValueTask ProcessNextDocumentBatchAsync(
            ImmutableArray <DocumentId> documentIds, CancellationToken cancellationToken)
        {
            // This logic preserves the previous behavior we had with IForegroundNotificationService.
            // Specifically, we don't run on the UI thread for more than 15ms at a time.  And once we
            // have, we wait 50ms before continuing.  These constants are just what we defined from
            // legacy, and otherwise have no special meaning.
            const int MaxTimeSlice           = 15;
            var       delayBetweenProcessing = TimeSpan.FromMilliseconds(50);

            Debug.Assert(!_threadingContext.JoinableTaskContext.IsOnMainThread, "The following context switch is not expected to cause runtime overhead.");
            await TaskScheduler.Default;

            // Ensure MEF services used by the code model are initially obtained on a background thread.
            // This code avoids allocations where possible.
            // https://github.com/dotnet/roslyn/issues/54159
            string?previousLanguage = null;

            foreach (var(_, projectState) in _visualStudioWorkspace.CurrentSolution.State.ProjectStates)
            {
                if (projectState.Language == previousLanguage)
                {
                    // Avoid duplicate calls if the language did not change
                    continue;
                }

                previousLanguage = projectState.Language;
                projectState.LanguageServices.GetService <ICodeModelService>();
                projectState.LanguageServices.GetService <ISyntaxFactsService>();
                projectState.LanguageServices.GetService <ICodeGenerationService>();
            }

            await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

            var stopwatch = SharedStopwatch.StartNew();

            foreach (var documentId in documentIds)
            {
                FireEventsForDocument(documentId);

                // Keep firing events for this doc, as long as we haven't exceeded the max amount
                // of waiting time, and there's no user input that should take precedence.
                if (stopwatch.Elapsed.Ticks > MaxTimeSlice || IsInputPending())
                {
                    await this.Listener.Delay(delayBetweenProcessing, cancellationToken).ConfigureAwait(true);

                    stopwatch = SharedStopwatch.StartNew();
                }
            }

            return;

            void FireEventsForDocument(DocumentId documentId)
            {
                // If we've been asked to shutdown, don't bother reporting any more events.
                if (_threadingContext.DisposalToken.IsCancellationRequested)
                {
                    return;
                }

                var projectCodeModel = this.TryGetProjectCodeModel(documentId.ProjectId);

                if (projectCodeModel == null)
                {
                    return;
                }

                var filename = _visualStudioWorkspace.GetFilePath(documentId);

                if (filename == null)
                {
                    return;
                }

                if (!projectCodeModel.TryGetCachedFileCodeModel(filename, out var fileCodeModelHandle))
                {
                    return;
                }

                var codeModel = fileCodeModelHandle.Object;

                codeModel.FireEvents();
                return;
            }
        }
Exemple #4
0
        private async Task ProcessNextDocumentBatchAsync(
            ImmutableArray <DocumentId> documentIds, CancellationToken cancellationToken)
        {
            // This logic preserves the previous behavior we had with IForegroundNotificationService.
            // Specifically, we don't run on the UI thread for more than 15ms at a time.  And once we
            // have, we wait 50ms before continuing.  These constants are just what we defined from
            // legacy, and otherwise have no special meaning.
            const int MaxTimeSlice           = 15;
            var       delayBetweenProcessing = TimeSpan.FromMilliseconds(50);

            await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

            var stopwatch = SharedStopwatch.StartNew();

            foreach (var documentId in documentIds)
            {
                FireEventsForDocument(documentId);

                // Keep firing events for this doc, as long as we haven't exceeded the max amount
                // of waiting time, and there's no user input that should take precedence.
                if (stopwatch.Elapsed.Ticks > MaxTimeSlice || IsInputPending())
                {
                    await this.Listener.Delay(delayBetweenProcessing, cancellationToken).ConfigureAwait(true);

                    stopwatch = SharedStopwatch.StartNew();
                }
            }

            return;

            void FireEventsForDocument(DocumentId documentId)
            {
                // If we've been asked to shutdown, don't bother reporting any more events.
                if (_threadingContext.DisposalToken.IsCancellationRequested)
                {
                    return;
                }

                var projectCodeModel = this.TryGetProjectCodeModel(documentId.ProjectId);

                if (projectCodeModel == null)
                {
                    return;
                }

                var filename = _visualStudioWorkspace.GetFilePath(documentId);

                if (filename == null)
                {
                    return;
                }

                if (!projectCodeModel.TryGetCachedFileCodeModel(filename, out var fileCodeModelHandle))
                {
                    return;
                }

                var codeModel = fileCodeModelHandle.Object;

                codeModel.FireEvents();
                return;
            }
        }