diff --git a/src/EditorFeatures/CSharp/AutomaticCompletion/CSharpBraceCompletionServiceFactory.cs b/src/EditorFeatures/CSharp/AutomaticCompletion/CSharpBraceCompletionServiceFactory.cs index 923494039a630..d80db46c4d60e 100644 --- a/src/EditorFeatures/CSharp/AutomaticCompletion/CSharpBraceCompletionServiceFactory.cs +++ b/src/EditorFeatures/CSharp/AutomaticCompletion/CSharpBraceCompletionServiceFactory.cs @@ -5,9 +5,8 @@ using System; using System.Collections.Generic; using System.Composition; -using Microsoft.CodeAnalysis.BraceCompletion; using Microsoft.CodeAnalysis.AutomaticCompletion; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.BraceCompletion; using Microsoft.CodeAnalysis.Host.Mef; namespace Microsoft.CodeAnalysis.Editor.CSharp.AutomaticCompletion @@ -18,9 +17,8 @@ internal class CSharpBraceCompletionServiceFactory : AbstractBraceCompletionServ [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CSharpBraceCompletionServiceFactory( - [ImportMany(LanguageNames.CSharp)] IEnumerable braceCompletionServices, - IThreadingContext threadingContext) - : base(braceCompletionServices, threadingContext) + [ImportMany(LanguageNames.CSharp)] IEnumerable braceCompletionServices) + : base(braceCompletionServices) { } } diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler.cs index f892125681301..192c7d293420d 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler.cs @@ -38,8 +38,9 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.EventHookup [ContentType(ContentTypeNames.CSharpContentType)] [Name(PredefinedCommandHandlerNames.EventHookup)] [Order(Before = PredefinedCommandHandlerNames.AutomaticCompletion)] - internal partial class EventHookupCommandHandler : ForegroundThreadAffinitizedObject + internal partial class EventHookupCommandHandler { + private readonly IThreadingContext _threadingContext; private readonly IInlineRenameService _inlineRenameService; private readonly IAsynchronousOperationListener _asyncListener; private readonly IGlobalOptionService _globalOptions; @@ -57,8 +58,8 @@ public EventHookupCommandHandler( EventHookupSessionManager eventHookupSessionManager, IGlobalOptionService globalOptions, IAsynchronousOperationListenerProvider listenerProvider) - : base(threadingContext) { + _threadingContext = threadingContext; _inlineRenameService = inlineRenameService; _asyncListener = listenerProvider.GetListener(FeatureAttribute.EventHookup); _globalOptions = globalOptions; diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_SessionCancellingCommands.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_SessionCancellingCommands.cs index 278e2c562220e..1e2c981f3cb78 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_SessionCancellingCommands.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_SessionCancellingCommands.cs @@ -4,8 +4,10 @@ #nullable disable +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.EventHookup { @@ -16,14 +18,14 @@ internal partial class EventHookupCommandHandler : public bool ExecuteCommand(EscapeKeyCommandArgs args, CommandExecutionContext context) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); EventHookupSessionManager.CancelAndDismissExistingSessions(); return false; } public CommandState GetCommandState(EscapeKeyCommandArgs args) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); return CommandState.Unspecified; } } diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs index 2917e781f5ed1..3f656905cba0c 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs @@ -36,7 +36,7 @@ internal partial class EventHookupCommandHandler : IChainedCommandHandler nextHandler) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); if (EventHookupSessionManager.CurrentSession != null) { return CommandState.Available; @@ -68,7 +68,7 @@ public CommandState GetCommandState(TabKeyCommandArgs args, Func n private void HandleTabWorker(ITextView textView, ITextBuffer subjectBuffer, Action nextHandler, CancellationToken cancellationToken) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); // For test purposes only! if (EventHookupSessionManager.CurrentSession.TESTSessionHookupMutex != null) @@ -107,7 +107,7 @@ private void HandleTabWorker(ITextView textView, ITextBuffer subjectBuffer, Acti private void GenerateAndAddEventHandler(ITextView textView, ITextBuffer subjectBuffer, string eventHandlerMethodName, Action nextHandler, CancellationToken cancellationToken) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); using (Logger.LogBlock(FunctionId.EventHookup_Generate_Handler, cancellationToken)) { @@ -151,7 +151,7 @@ private Solution CreateSolutionWithEventHandler( out int plusEqualTokenEndPosition, CancellationToken cancellationToken) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); // Mark the += token with an annotation so we can find it after formatting var plusEqualsTokenAnnotation = new SyntaxAnnotation(); @@ -289,7 +289,7 @@ private static IMethodSymbol GetMethodSymbol( private void BeginInlineRename(ITextView textView, int plusEqualTokenEndPosition, CancellationToken cancellationToken) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); if (_inlineRenameService.ActiveSession == null) { diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TypeCharCommand.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TypeCharCommand.cs index d62f1f2c054c9..af33126f517a8 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TypeCharCommand.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TypeCharCommand.cs @@ -13,6 +13,7 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.EventHookup { @@ -20,7 +21,7 @@ internal partial class EventHookupCommandHandler : IChainedCommandHandler nextHandler) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); return nextHandler(); } } diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager.cs index de8b8614f8726..5606d85163c18 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager.cs @@ -16,12 +16,15 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Adornments; using Microsoft.VisualStudio.Text.Editor; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.EventHookup { [Export] - internal sealed partial class EventHookupSessionManager : ForegroundThreadAffinitizedObject + internal sealed partial class EventHookupSessionManager { + public readonly IThreadingContext ThreadingContext; + private readonly IToolTipService _toolTipService; private IToolTipPresenter _toolTipPresenter; @@ -33,14 +36,14 @@ internal sealed partial class EventHookupSessionManager : ForegroundThreadAffini [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public EventHookupSessionManager(IThreadingContext threadingContext, IToolTipService toolTipService) - : base(threadingContext) { + ThreadingContext = threadingContext; _toolTipService = toolTipService; } internal void EventHookupFoundInSession(EventHookupSession analyzedSession) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); var caretPoint = analyzedSession.TextView.GetCaretPoint(analyzedSession.SubjectBuffer); @@ -114,7 +117,7 @@ internal void BeginSession( internal void CancelAndDismissExistingSessions() { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (CurrentSession != null) { @@ -137,7 +140,7 @@ internal void CancelAndDismissExistingSessions() /// private void TextBuffer_Changed(object sender, TextContentChangedEventArgs e) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); foreach (var change in e.Changes) { @@ -154,7 +157,7 @@ private void TextBuffer_Changed(object sender, TextContentChangedEventArgs e) /// private void Caret_PositionChanged(object sender, EventArgs e) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (CurrentSession == null) { diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs index 12dbd69c81d9e..13e11cf3c2aff 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs @@ -37,9 +37,10 @@ internal sealed partial class EventHookupSessionManager /// += is being used to add an event handler to an event. If it is, then we also determine /// a candidate name for the event handler. /// - internal class EventHookupSession : ForegroundThreadAffinitizedObject + internal class EventHookupSession { public readonly Task GetEventNameTask; + private readonly IThreadingContext _threadingContext; private readonly CancellationTokenSource _cancellationTokenSource; private readonly ITrackingPoint _trackingPoint; private readonly ITrackingSpan _trackingSpan; @@ -55,7 +56,7 @@ public ITrackingPoint TrackingPoint { get { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); return _trackingPoint; } } @@ -64,7 +65,7 @@ public ITrackingSpan TrackingSpan { get { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); return _trackingSpan; } } @@ -73,7 +74,7 @@ public ITextView TextView { get { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); return _textView; } } @@ -82,14 +83,14 @@ public ITextBuffer SubjectBuffer { get { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); return _subjectBuffer; } } public void Cancel() { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); _cancellationTokenSource.Cancel(); } @@ -100,9 +101,8 @@ public EventHookupSession( ITextBuffer subjectBuffer, IAsynchronousOperationListener asyncListener, Mutex testSessionHookupMutex) - : base(eventHookupSessionManager.ThreadingContext) { - AssertIsForeground(); + _threadingContext = eventHookupSessionManager.ThreadingContext; _cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = _cancellationTokenSource.Token; _textView = textView; @@ -129,7 +129,7 @@ public EventHookupSession( var continuedTask = this.GetEventNameTask.SafeContinueWithFromAsync( async t => { - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); if (t.Result != null) { @@ -153,7 +153,7 @@ public EventHookupSession( private async Task DetermineIfEventHookupAndGetHandlerNameAsync(Document document, int position, CancellationToken cancellationToken) { - AssertIsBackground(); + _threadingContext.ThrowIfNotOnBackgroundThread(); // For test purposes only! if (TESTSessionHookupMutex != null) @@ -191,7 +191,7 @@ private async Task DetermineIfEventHookupAndGetHandlerNameAsync(Document private async Task GetPlusEqualsTokenInsideAddAssignExpressionAsync(Document document, int position, CancellationToken cancellationToken) { - AssertIsBackground(); + _threadingContext.ThrowIfNotOnBackgroundThread(); var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken); @@ -210,7 +210,7 @@ private async Task DetermineIfEventHookupAndGetHandlerNameAsync(Document private IEventSymbol GetEventSymbol(SemanticModel semanticModel, SyntaxToken plusEqualsToken, CancellationToken cancellationToken) { - AssertIsBackground(); + _threadingContext.ThrowIfNotOnBackgroundThread(); if (plusEqualsToken.Parent is not AssignmentExpressionSyntax parentToken) { return null; @@ -229,7 +229,7 @@ private string GetEventHandlerName( IEventSymbol eventSymbol, SyntaxToken plusEqualsToken, SemanticModel semanticModel, ISyntaxFactsService syntaxFactsService, NamingRule namingRule) { - AssertIsBackground(); + _threadingContext.ThrowIfNotOnBackgroundThread(); var objectPart = GetNameObjectPart(eventSymbol, plusEqualsToken, semanticModel, syntaxFactsService); var basename = namingRule.NamingStyle.CreateName(ImmutableArray.Create( string.Format("{0}_{1}", objectPart, eventSymbol.Name))); @@ -249,7 +249,7 @@ private string GetEventHandlerName( /// private string GetNameObjectPart(IEventSymbol eventSymbol, SyntaxToken plusEqualsToken, SemanticModel semanticModel, ISyntaxFactsService syntaxFactsService) { - AssertIsBackground(); + _threadingContext.ThrowIfNotOnBackgroundThread(); var parentToken = plusEqualsToken.Parent as AssignmentExpressionSyntax; if (parentToken.Left is MemberAccessExpressionSyntax memberAccessExpression) diff --git a/src/EditorFeatures/CSharp/GoToDefinition/CSharpGoToSymbolService.cs b/src/EditorFeatures/CSharp/GoToDefinition/CSharpGoToSymbolService.cs index 01cfb11f72d2c..4748708ec16bc 100644 --- a/src/EditorFeatures/CSharp/GoToDefinition/CSharpGoToSymbolService.cs +++ b/src/EditorFeatures/CSharp/GoToDefinition/CSharpGoToSymbolService.cs @@ -4,10 +4,8 @@ using System; using System.Composition; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.GoToDefinition; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Editor.CSharp.GoToDefinition { @@ -16,8 +14,7 @@ internal sealed class CSharpGoToSymbolService : AbstractGoToSymbolService { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpGoToSymbolService(IThreadingContext threadingContext) - : base(threadingContext) + public CSharpGoToSymbolService() { } } diff --git a/src/EditorFeatures/Core.Cocoa/Preview/ICocoaDifferenceViewerExtensions.cs b/src/EditorFeatures/Core.Cocoa/Preview/ICocoaDifferenceViewerExtensions.cs index eff031dd33e24..9daccafec7eaa 100644 --- a/src/EditorFeatures/Core.Cocoa/Preview/ICocoaDifferenceViewerExtensions.cs +++ b/src/EditorFeatures/Core.Cocoa/Preview/ICocoaDifferenceViewerExtensions.cs @@ -19,8 +19,9 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Preview { internal static class ICocoaDifferenceViewerExtensions { - private class SizeToFitHelper : ForegroundThreadAffinitizedObject + private class SizeToFitHelper { + private readonly IThreadingContext _threadingContext; private readonly ICocoaDifferenceViewer _diffViewer; private readonly double _minWidth; @@ -28,15 +29,15 @@ private class SizeToFitHelper : ForegroundThreadAffinitizedObject private double _height; public SizeToFitHelper(IThreadingContext threadingContext, ICocoaDifferenceViewer diffViewer, double minWidth) - : base(threadingContext) { + _threadingContext = threadingContext; _diffViewer = diffViewer; _minWidth = minWidth; } public async Task SizeToFitAsync(CancellationToken cancellationToken) { - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); await CalculateSizeAsync(cancellationToken).ConfigureAwait(true); @@ -83,7 +84,7 @@ void HandleSnapshotDifferenceChanged(object sender, SnapshotDifferenceChangeEven private async Task CalculateSizeAsync(CancellationToken cancellationToken) { - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); ICocoaTextView textView; ITextSnapshot snapshot; diff --git a/src/EditorFeatures/Core.Cocoa/Preview/PreviewPaneService.cs b/src/EditorFeatures/Core.Cocoa/Preview/PreviewPaneService.cs index 18d56f07d92ee..09a38b752f6cf 100644 --- a/src/EditorFeatures/Core.Cocoa/Preview/PreviewPaneService.cs +++ b/src/EditorFeatures/Core.Cocoa/Preview/PreviewPaneService.cs @@ -14,12 +14,11 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Preview { [ExportWorkspaceServiceFactory(typeof(IPreviewPaneService), ServiceLayer.Host), Shared] - internal class PreviewPaneService : ForegroundThreadAffinitizedObject, IPreviewPaneService, IWorkspaceServiceFactory + internal class PreviewPaneService : IPreviewPaneService, IWorkspaceServiceFactory { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public PreviewPaneService(IThreadingContext threadingContext) - : base(threadingContext) + public PreviewPaneService() { } diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetCommandHandler.cs index a1132db92c8a7..ca21831a27d28 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetCommandHandler.cs @@ -23,13 +23,13 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets using Workspace = Microsoft.CodeAnalysis.Workspace; internal abstract class AbstractSnippetCommandHandler : - ForegroundThreadAffinitizedObject, ICommandHandler, ICommandHandler, ICommandHandler, ICommandHandler, ICommandHandler { + protected readonly IThreadingContext ThreadingContext; protected readonly IExpansionServiceProvider ExpansionServiceProvider; protected readonly IExpansionManager ExpansionManager; protected readonly IGlobalOptionService GlobalOptions; @@ -41,8 +41,8 @@ public AbstractSnippetCommandHandler( IExpansionServiceProvider expansionServiceProvider, IExpansionManager expansionManager, IGlobalOptionService globalOptions) - : base(threadingContext) { + ThreadingContext = threadingContext; ExpansionServiceProvider = expansionServiceProvider; ExpansionManager = expansionManager; GlobalOptions = globalOptions; @@ -59,7 +59,7 @@ protected virtual bool TryInvokeSnippetPickerOnQuestionMark(ITextView textView, public bool ExecuteCommand(TabKeyCommandArgs args, CommandExecutionContext context) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!AreSnippetsEnabled(args)) { return false; @@ -90,7 +90,7 @@ public bool ExecuteCommand(TabKeyCommandArgs args, CommandExecutionContext conte public CommandState GetCommandState(TabKeyCommandArgs args) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!AreSnippetsEnabled(args)) { @@ -107,7 +107,7 @@ public CommandState GetCommandState(TabKeyCommandArgs args) public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext context) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!AreSnippetsEnabled(args)) { return false; @@ -124,7 +124,7 @@ public bool ExecuteCommand(ReturnKeyCommandArgs args, CommandExecutionContext co public CommandState GetCommandState(ReturnKeyCommandArgs args) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!AreSnippetsEnabled(args)) { @@ -141,7 +141,7 @@ public CommandState GetCommandState(ReturnKeyCommandArgs args) public bool ExecuteCommand(EscapeKeyCommandArgs args, CommandExecutionContext context) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!AreSnippetsEnabled(args)) { return false; @@ -158,7 +158,7 @@ public bool ExecuteCommand(EscapeKeyCommandArgs args, CommandExecutionContext co public CommandState GetCommandState(EscapeKeyCommandArgs args) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!AreSnippetsEnabled(args)) { @@ -175,7 +175,7 @@ public CommandState GetCommandState(EscapeKeyCommandArgs args) public bool ExecuteCommand(BackTabKeyCommandArgs args, CommandExecutionContext context) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!AreSnippetsEnabled(args)) { return false; @@ -192,7 +192,7 @@ public bool ExecuteCommand(BackTabKeyCommandArgs args, CommandExecutionContext c public CommandState GetCommandState(BackTabKeyCommandArgs args) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!AreSnippetsEnabled(args)) { @@ -209,7 +209,7 @@ public CommandState GetCommandState(BackTabKeyCommandArgs args) public bool ExecuteCommand(InsertSnippetCommandArgs args, CommandExecutionContext context) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!AreSnippetsEnabled(args)) { @@ -221,7 +221,7 @@ public bool ExecuteCommand(InsertSnippetCommandArgs args, CommandExecutionContex public CommandState GetCommandState(InsertSnippetCommandArgs args) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!AreSnippetsEnabled(args)) { @@ -243,7 +243,7 @@ public CommandState GetCommandState(InsertSnippetCommandArgs args) protected bool TryHandleTypedSnippet(ITextView textView, ITextBuffer subjectBuffer) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetExpansionClient.cs b/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetExpansionClient.cs index ea18b1237e7aa..705445b4258ec 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetExpansionClient.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/AbstractSnippetExpansionClient.cs @@ -23,7 +23,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets { - internal abstract class AbstractSnippetExpansionClient : ForegroundThreadAffinitizedObject, IExpansionClient + internal abstract class AbstractSnippetExpansionClient : IExpansionClient { protected readonly IExpansionServiceProvider ExpansionServiceProvider; protected readonly IContentType LanguageServiceGuid; @@ -36,8 +36,7 @@ internal abstract class AbstractSnippetExpansionClient : ForegroundThreadAffinit public IExpansionSession? ExpansionSession { get; private set; } - public AbstractSnippetExpansionClient(IThreadingContext threadingContext, IContentType languageServiceGuid, ITextView textView, ITextBuffer subjectBuffer, IExpansionServiceProvider expansionServiceProvider) - : base(threadingContext) + public AbstractSnippetExpansionClient(IContentType languageServiceGuid, ITextView textView, ITextBuffer subjectBuffer, IExpansionServiceProvider expansionServiceProvider) { this.LanguageServiceGuid = languageServiceGuid; this.TextView = textView; diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetCommandHandler.cs index 44e71467aa243..5cc96ccbcfb70 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetCommandHandler.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; @@ -47,7 +48,7 @@ public SnippetCommandHandler( public bool ExecuteCommand(SurroundWithCommandArgs args, CommandExecutionContext context) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!AreSnippetsEnabled(args)) { @@ -59,7 +60,7 @@ public bool ExecuteCommand(SurroundWithCommandArgs args, CommandExecutionContext public CommandState GetCommandState(SurroundWithCommandArgs args) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!AreSnippetsEnabled(args)) { @@ -83,7 +84,7 @@ protected override AbstractSnippetExpansionClient GetSnippetExpansionClient(ITex { if (!textView.Properties.TryGetProperty(typeof(AbstractSnippetExpansionClient), out AbstractSnippetExpansionClient expansionClient)) { - expansionClient = new SnippetExpansionClient(ThreadingContext, subjectBuffer.ContentType, textView, subjectBuffer, ExpansionServiceProvider); + expansionClient = new SnippetExpansionClient(subjectBuffer.ContentType, textView, subjectBuffer, ExpansionServiceProvider); textView.Properties.AddProperty(typeof(AbstractSnippetExpansionClient), expansionClient); } diff --git a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetExpansionClient.cs b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetExpansionClient.cs index d9ec0086a7db8..5254107f15e7c 100644 --- a/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetExpansionClient.cs +++ b/src/EditorFeatures/Core.Cocoa/Snippets/CSharpSnippets/SnippetExpansionClient.cs @@ -17,8 +17,8 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Snippets { internal sealed partial class SnippetExpansionClient : AbstractSnippetExpansionClient { - public SnippetExpansionClient(IThreadingContext threadingContext, IContentType languageServiceGuid, ITextView textView, ITextBuffer subjectBuffer, IExpansionServiceProvider expansionServiceProvider) - : base(threadingContext, languageServiceGuid, textView, subjectBuffer, expansionServiceProvider) + public SnippetExpansionClient(IContentType languageServiceGuid, ITextView textView, ITextBuffer subjectBuffer, IExpansionServiceProvider expansionServiceProvider) + : base(languageServiceGuid, textView, subjectBuffer, expansionServiceProvider) { } diff --git a/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/WpfBackgroundWorkIndicatorFactory.cs b/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/WpfBackgroundWorkIndicatorFactory.cs index 8349f8c32e6d8..73303be9b95d4 100644 --- a/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/WpfBackgroundWorkIndicatorFactory.cs +++ b/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/WpfBackgroundWorkIndicatorFactory.cs @@ -4,6 +4,7 @@ using System; using System.Composition; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -44,7 +45,7 @@ IBackgroundWorkIndicatorContext IBackgroundWorkIndicatorFactory.Create( bool cancelOnEdit, bool cancelOnFocusLost) { - Contract.ThrowIfFalse(_threadingContext.HasMainThread); + _threadingContext.ThrowIfNotOnUIThread(); // If we have an outstanding context in flight, cancel it and create a new one to show the user. _currentContext?.CancelAndDispose(); @@ -61,7 +62,7 @@ IBackgroundWorkIndicatorContext IBackgroundWorkIndicatorFactory.Create( private void OnContextDisposed(BackgroundWorkIndicatorContext context) { - Contract.ThrowIfFalse(_threadingContext.HasMainThread); + _threadingContext.ThrowIfNotOnUIThread(); if (_currentContext == context) _currentContext = null; diff --git a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs index 1ebb81338ea61..a793dd599083c 100644 --- a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs +++ b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Composition; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.InlineHints; @@ -48,7 +49,6 @@ internal sealed class InlineHintsTagger : ITagger, IDispo private TextFormattingRunProperties? _format; private readonly IClassificationType _hintClassification; - private readonly ForegroundThreadAffinitizedObject _threadAffinitizedObject; private readonly InlineHintsTaggerProvider _taggerProvider; private readonly ITextBuffer _buffer; @@ -62,7 +62,6 @@ public InlineHintsTagger( ITextBuffer buffer, ITagAggregator tagAggregator) { - _threadAffinitizedObject = new ForegroundThreadAffinitizedObject(taggerProvider.ThreadingContext); _taggerProvider = taggerProvider; _textView = textView; @@ -77,7 +76,7 @@ public InlineHintsTagger( private void OnClassificationFormatMappingChanged(object sender, EventArgs e) { - _threadAffinitizedObject.AssertIsForeground(); + _taggerProvider.ThreadingContext.ThrowIfNotOnUIThread(); if (_format != null) { _format = null; @@ -107,7 +106,7 @@ private TextFormattingRunProperties Format { get { - _threadAffinitizedObject.AssertIsForeground(); + _taggerProvider.ThreadingContext.ThrowIfNotOnUIThread(); _format ??= _formatMap.GetTextProperties(_hintClassification); return _format; } diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs index 5a0e1c7bdb97f..5afb115c9bf50 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs @@ -5,6 +5,7 @@ #nullable disable using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp @@ -21,14 +22,14 @@ public Session(Controller controller, ISignatureHelpPresenterSession presenterSe public override void Stop() { - AssertIsForeground(); + this.Computation.ThreadingContext.ThrowIfNotOnUIThread(); this.PresenterSession.ItemSelected -= OnPresenterSessionItemSelected; base.Stop(); } private void OnPresenterSessionItemSelected(object sender, SignatureHelpItemEventArgs e) { - AssertIsForeground(); + this.Computation.ThreadingContext.ThrowIfNotOnUIThread(); Contract.ThrowIfFalse(ReferenceEquals(this.PresenterSession, sender)); SetModelExplicitlySelectedItem(m => e.SignatureHelpItem); diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs index c1c72eafde77f..3d9b05ad89458 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs @@ -30,7 +30,7 @@ public void ComputeModel( ImmutableArray providers, SignatureHelpTriggerInfo triggerInfo) { - AssertIsForeground(); + this.Computation.ThreadingContext.ThrowIfNotOnUIThread(); var caretPosition = Controller.TextView.GetCaretPoint(Controller.SubjectBuffer).Value; var disconnectedBufferGraph = new DisconnectedBufferGraph(Controller.SubjectBuffer, Controller.TextView.TextBuffer); @@ -55,7 +55,7 @@ private async Task ComputeModelInBackgroundAsync( { using (Logger.LogBlock(FunctionId.SignatureHelp_ModelComputation_ComputeModelInBackground, cancellationToken)) { - AssertIsBackground(); + this.Computation.ThreadingContext.ThrowIfNotOnBackgroundThread(); cancellationToken.ThrowIfCancellationRequested(); var document = Controller.DocumentProvider.GetDocument(caretPosition.Snapshot, cancellationToken); diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs index c2e17473c6f26..534980d3ab7c3 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Roslyn.Utilities; @@ -16,7 +17,7 @@ internal partial class Session { private void SetModelExplicitlySelectedItem(Func selector) { - AssertIsForeground(); + this.Computation.ThreadingContext.ThrowIfNotOnUIThread(); Computation.ChainTaskAndNotifyControllerWhenFinished( model => SetModelExplicitlySelectedItemInBackground(model, selector), @@ -27,7 +28,7 @@ private Model SetModelExplicitlySelectedItemInBackground( Model model, Func selector) { - AssertIsBackground(); + this.Computation.ThreadingContext.ThrowIfNotOnBackgroundThread(); if (model == null) { diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs index b850b8afd6c9f..dc30c27348316 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs @@ -74,13 +74,13 @@ internal Controller( private SnapshotPoint GetCaretPointInViewBuffer() { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); return this.TextView.Caret.Position.BufferPosition; } internal override void OnModelUpdated(Model modelOpt, bool updateController) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); if (updateController) { @@ -111,7 +111,7 @@ internal override void OnModelUpdated(Model modelOpt, bool updateController) private void StartSession( ImmutableArray providers, SignatureHelpTriggerInfo triggerInfo) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); VerifySessionIsInactive(); this.sessionOpt = new Session(this, Presenter.CreateSession(TextView, SubjectBuffer, null)); @@ -120,7 +120,7 @@ private void StartSession( private ImmutableArray GetProviders() { - this.AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); var snapshot = this.SubjectBuffer.CurrentSnapshot; var currentContentType = snapshot.ContentType; @@ -142,7 +142,7 @@ private ImmutableArray GetProviders() private void Retrigger() { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); if (!IsSessionActive) { return; diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_InvokeSignatureHelp.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_InvokeSignatureHelp.cs index a768a57fbf67d..b0e76ce30850b 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_InvokeSignatureHelp.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_InvokeSignatureHelp.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; @@ -15,13 +16,13 @@ internal partial class Controller { CommandState IChainedCommandHandler.GetCommandState(InvokeSignatureHelpCommandArgs args, Func nextHandler) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); return nextHandler(); } void IChainedCommandHandler.ExecuteCommand(InvokeSignatureHelpCommandArgs args, Action nextHandler, CommandExecutionContext context) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); DismissSessionIfActive(); var providers = GetProviders(); diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_NavigationKeys.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_NavigationKeys.cs index 817ea96d5737f..d2730efa02baf 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_NavigationKeys.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_NavigationKeys.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp { @@ -12,19 +13,19 @@ internal partial class Controller { internal bool TryHandleUpKey() { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); return ChangeSelection(() => sessionOpt.PresenterSession.SelectPreviousItem()); } internal bool TryHandleDownKey() { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); return ChangeSelection(() => sessionOpt.PresenterSession.SelectNextItem()); } private bool ChangeSelection(Action computationAction) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); if (!IsSessionActive) { diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_OnCaretPositionChanged.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_OnCaretPositionChanged.cs index a8f5496c4514f..71b894515fd76 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_OnCaretPositionChanged.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_OnCaretPositionChanged.cs @@ -2,9 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp { @@ -12,7 +11,7 @@ internal partial class Controller { internal override void OnCaretPositionChanged(object sender, EventArgs args) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); OnCaretPositionChanged(); } diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_TypeChar.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_TypeChar.cs index 97d8a532e0591..90ae6ccef10ec 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_TypeChar.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_TypeChar.cs @@ -19,7 +19,7 @@ internal partial class Controller { CommandState IChainedCommandHandler.GetCommandState(TypeCharCommandArgs args, Func nextHandler) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); // We just defer to the editor here. We do not interfere with typing normal characters. return nextHandler(); @@ -27,7 +27,7 @@ CommandState IChainedCommandHandler.GetCommandState(TypeCha void IChainedCommandHandler.ExecuteCommand(TypeCharCommandArgs args, Action nextHandler, CommandExecutionContext context) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); var allProviders = GetProviders(); if (allProviders == null) @@ -132,7 +132,7 @@ void IChainedCommandHandler.ExecuteCommand(TypeCharCommandA private (ImmutableArray matched, ImmutableArray unmatched) FilterProviders( ImmutableArray providers, char ch) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); using var matchedProvidersDisposer = ArrayBuilder.GetInstance(out var matchedProviders); using var unmatchedProvidersDisposer = ArrayBuilder.GetInstance(out var unmatchedProviders); diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpPresenter.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpPresenter.cs index 07691144688ba..4ba12b01ec0e0 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpPresenter.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpPresenter.cs @@ -6,6 +6,7 @@ using System; using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.Language.Intellisense; @@ -19,30 +20,30 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHel [Export(typeof(IIntelliSensePresenter))] [Name(PredefinedSignatureHelpPresenterNames.RoslynSignatureHelpPresenter)] [ContentType(ContentTypeNames.RoslynContentType)] - internal partial class SignatureHelpPresenter : ForegroundThreadAffinitizedObject, IIntelliSensePresenter, ISignatureHelpSourceProvider + internal partial class SignatureHelpPresenter : IIntelliSensePresenter, ISignatureHelpSourceProvider { private static readonly object s_augmentSessionKey = new(); - + private readonly IThreadingContext _threadingContext; private readonly ISignatureHelpBroker _sigHelpBroker; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public SignatureHelpPresenter(IThreadingContext threadingContext, ISignatureHelpBroker sigHelpBroker) - : base(threadingContext) { + _threadingContext = threadingContext; _sigHelpBroker = sigHelpBroker; } ISignatureHelpPresenterSession IIntelliSensePresenter.CreateSession(ITextView textView, ITextBuffer subjectBuffer, ISignatureHelpSession sessionOpt) { - AssertIsForeground(); - return new SignatureHelpPresenterSession(ThreadingContext, _sigHelpBroker, textView); + _threadingContext.ThrowIfNotOnUIThread(); + return new SignatureHelpPresenterSession(_threadingContext, _sigHelpBroker, textView); } ISignatureHelpSource ISignatureHelpSourceProvider.TryCreateSignatureHelpSource(ITextBuffer textBuffer) { - AssertIsForeground(); - return new SignatureHelpSource(ThreadingContext); + _threadingContext.ThrowIfNotOnUIThread(); + return new SignatureHelpSource(_threadingContext); } } } diff --git a/src/EditorFeatures/Core.Wpf/Workspaces/WpfTextBufferVisibilityTracker.cs b/src/EditorFeatures/Core.Wpf/Workspaces/WpfTextBufferVisibilityTracker.cs index 6ac20ad3bb308..adca8550f338b 100644 --- a/src/EditorFeatures/Core.Wpf/Workspaces/WpfTextBufferVisibilityTracker.cs +++ b/src/EditorFeatures/Core.Wpf/Workspaces/WpfTextBufferVisibilityTracker.cs @@ -8,6 +8,7 @@ using System.ComponentModel.Composition; using System.Linq; using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.Text; @@ -39,13 +40,13 @@ public WpfTextBufferVisibilityTracker( private void AssociatedViewService_SubjectBuffersConnected(object sender, SubjectBuffersConnectedEventArgs e) { - Contract.ThrowIfFalse(_threadingContext.HasMainThread); + _threadingContext.ThrowIfNotOnUIThread(); UpdateAllAssociatedViews(e.SubjectBuffers); } private void AssociatedViewService_SubjectBuffersDisconnected(object sender, SubjectBuffersConnectedEventArgs e) { - Contract.ThrowIfFalse(_threadingContext.HasMainThread); + _threadingContext.ThrowIfNotOnUIThread(); UpdateAllAssociatedViews(e.SubjectBuffers); } @@ -62,7 +63,7 @@ private void UpdateAllAssociatedViews(ReadOnlyCollection subjectBuf public bool IsVisible(ITextBuffer subjectBuffer) { - Contract.ThrowIfFalse(_threadingContext.HasMainThread); + _threadingContext.ThrowIfNotOnUIThread(); var views = _associatedViewService.GetAssociatedTextViews(subjectBuffer).ToImmutableArrayOrEmpty(); @@ -78,7 +79,7 @@ public bool IsVisible(ITextBuffer subjectBuffer) public void RegisterForVisibilityChanges(ITextBuffer subjectBuffer, Action callback) { - Contract.ThrowIfFalse(_threadingContext.HasMainThread); + _threadingContext.ThrowIfNotOnUIThread(); if (!_subjectBufferToCallbacks.TryGetValue(subjectBuffer, out var data)) { data = new VisibleTrackerData(this, subjectBuffer); @@ -90,7 +91,7 @@ public void RegisterForVisibilityChanges(ITextBuffer subjectBuffer, Action callb public void UnregisterForVisibilityChanges(ITextBuffer subjectBuffer, Action callback) { - Contract.ThrowIfFalse(_threadingContext.HasMainThread); + _threadingContext.ThrowIfNotOnUIThread(); // Both of these methods must succeed. Otherwise we're somehow unregistering something we don't know about. Contract.ThrowIfFalse(_subjectBufferToCallbacks.TryGetValue(subjectBuffer, out var data)); @@ -124,7 +125,7 @@ public VisibleTrackerData( public void Dispose() { - Contract.ThrowIfFalse(_tracker._threadingContext.HasMainThread); + _tracker._threadingContext.ThrowIfNotOnUIThread(); // Shouldn't be disposing of this if we still have clients that want to hear about visibility changes. Contract.ThrowIfTrue(Callbacks.Count > 0); @@ -137,7 +138,7 @@ public void Dispose() public void UpdateAssociatedViews() { - Contract.ThrowIfFalse(_tracker._threadingContext.HasMainThread); + _tracker._threadingContext.ThrowIfNotOnUIThread(); // Update us to whatever the currently associated text views are for this buffer. UpdateTextViews(_tracker._associatedViewService.GetAssociatedTextViews(_subjectBuffer)); @@ -168,7 +169,7 @@ private void UpdateTextViews(IEnumerable associatedTextViews) private void VisualElement_IsVisibleChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e) { - Contract.ThrowIfFalse(_tracker._threadingContext.HasMainThread); + _tracker._threadingContext.ThrowIfNotOnUIThread(); foreach (var callback in Callbacks) callback(); } diff --git a/src/EditorFeatures/Core/AutomaticCompletion/AbstractBraceCompletionServiceFactory.cs b/src/EditorFeatures/Core/AutomaticCompletion/AbstractBraceCompletionServiceFactory.cs index 771d0f5b0b6da..0f3de0920809c 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/AbstractBraceCompletionServiceFactory.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/AbstractBraceCompletionServiceFactory.cs @@ -7,18 +7,15 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.BraceCompletion; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; namespace Microsoft.CodeAnalysis.AutomaticCompletion { - internal abstract class AbstractBraceCompletionServiceFactory : ForegroundThreadAffinitizedObject, IBraceCompletionServiceFactory + internal abstract class AbstractBraceCompletionServiceFactory : IBraceCompletionServiceFactory { private readonly ImmutableArray _braceCompletionServices; protected AbstractBraceCompletionServiceFactory( - IEnumerable braceCompletionServices, - IThreadingContext threadingContext) - : base(threadingContext) + IEnumerable braceCompletionServices) { _braceCompletionServices = braceCompletionServices.ToImmutableArray(); } diff --git a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs index 62dcf63715945..4cb5ca8aaab01 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.BraceCompletionSession.cs @@ -31,7 +31,7 @@ internal partial class BraceCompletionSessionProvider // fortunately, editor provides another extension point where we have more control over brace completion but we do not // want to re-implement logics base session provider already provides. so I ported editor's default session and // modified it little bit so that we can use it as base class. - private class BraceCompletionSession : ForegroundThreadAffinitizedObject, IBraceCompletionSession + private class BraceCompletionSession : IBraceCompletionSession { #region Private Members @@ -45,6 +45,7 @@ private class BraceCompletionSession : ForegroundThreadAffinitizedObject, IBrace private readonly ITextUndoHistory _undoHistory; private readonly IEditorOperations _editorOperations; private readonly IBraceCompletionService _service; + private readonly IThreadingContext _threadingContext; #endregion @@ -55,7 +56,6 @@ public BraceCompletionSession( SnapshotPoint openingPoint, char openingBrace, char closingBrace, ITextUndoHistory undoHistory, IEditorOperationsFactoryService editorOperationsFactoryService, IBraceCompletionService service, IThreadingContext threadingContext) - : base(threadingContext, assertIsForeground: true) { this.TextView = textView; this.SubjectBuffer = subjectBuffer; @@ -65,6 +65,7 @@ public BraceCompletionSession( _undoHistory = undoHistory; _editorOperations = editorOperationsFactoryService.GetEditorOperations(textView); _service = service; + _threadingContext = threadingContext; } #endregion @@ -73,7 +74,7 @@ public BraceCompletionSession( public void Start() { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); // Brace completion is not cancellable. if (!this.TryStart(CancellationToken.None)) { @@ -83,7 +84,7 @@ public void Start() private bool TryStart(CancellationToken cancellationToken) { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); var closingSnapshotPoint = ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot); if (closingSnapshotPoint.Position < 1) @@ -141,7 +142,7 @@ private bool TryStart(CancellationToken cancellationToken) public void PreBackspace(out bool handledCommand) { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); handledCommand = false; var caretPos = this.GetCaretPosition(); @@ -181,7 +182,7 @@ public void PostBackspace() public void PreOverType(out bool handledCommand) { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); handledCommand = false; if (ClosingPoint == null) { @@ -249,7 +250,7 @@ public void PostOverType() public void PreTab(out bool handledCommand) { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); handledCommand = false; if (!HasForwardTyping) @@ -273,7 +274,7 @@ public void PreReturn(out bool handledCommand) public void PostReturn() { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); if (this.GetCaretPosition().HasValue) { var closingSnapshotPoint = ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot); @@ -331,7 +332,7 @@ private bool HasForwardTyping { get { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); var closingSnapshotPoint = ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot); if (closingSnapshotPoint.Position > 0) @@ -376,7 +377,7 @@ internal ITextUndoTransaction CreateUndoTransaction() private void MoveCaretToClosingPoint() { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); var closingSnapshotPoint = ClosingPoint.GetPoint(SubjectBuffer.CurrentSnapshot); // find the position just after the closing brace in the view's text buffer @@ -393,7 +394,7 @@ private void MoveCaretToClosingPoint() private BraceCompletionContext? GetBraceCompletionContext() { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); var snapshot = SubjectBuffer.CurrentSnapshot; var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); @@ -411,7 +412,7 @@ private void MoveCaretToClosingPoint() private void ApplyBraceCompletionResult(BraceCompletionResult result) { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); using var edit = SubjectBuffer.CreateEdit(); foreach (var change in result.TextChanges) { diff --git a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.cs b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.cs index 865562f5963e5..ceeed31c16625 100644 --- a/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.cs +++ b/src/EditorFeatures/Core/AutomaticCompletion/BraceCompletionSessionProvider.cs @@ -8,6 +8,7 @@ using System.ComponentModel.Composition; using System.Threading; using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -30,8 +31,9 @@ namespace Microsoft.CodeAnalysis.AutomaticCompletion [BracePair(DoubleQuote.OpenCharacter, DoubleQuote.CloseCharacter)] [BracePair(Parenthesis.OpenCharacter, Parenthesis.CloseCharacter)] [BracePair(LessAndGreaterThan.OpenCharacter, LessAndGreaterThan.CloseCharacter)] - internal partial class BraceCompletionSessionProvider : ForegroundThreadAffinitizedObject, IBraceCompletionSessionProvider + internal partial class BraceCompletionSessionProvider : IBraceCompletionSessionProvider { + private readonly IThreadingContext _threadingContext; private readonly ITextBufferUndoManagerProvider _undoManager; private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; @@ -41,15 +43,15 @@ public BraceCompletionSessionProvider( IThreadingContext threadingContext, ITextBufferUndoManagerProvider undoManager, IEditorOperationsFactoryService editorOperationsFactoryService) - : base(threadingContext) { + _threadingContext = threadingContext; _undoManager = undoManager; _editorOperationsFactoryService = editorOperationsFactoryService; } public bool TryCreateSession(ITextView textView, SnapshotPoint openingPoint, char openingBrace, char closingBrace, out IBraceCompletionSession session) { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); var textSnapshot = openingPoint.Snapshot; var document = textSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document != null) @@ -67,7 +69,7 @@ public bool TryCreateSession(ITextView textView, SnapshotPoint openingPoint, cha session = new BraceCompletionSession( textView, openingPoint.Snapshot.TextBuffer, openingPoint, openingBrace, closingBrace, undoHistory, _editorOperationsFactoryService, - editorSession, ThreadingContext); + editorSession, _threadingContext); return true; } } diff --git a/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.Tagger.cs b/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.Tagger.cs index 0ea84597739af..c8e78e7cc1e27 100644 --- a/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.Tagger.cs +++ b/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.Tagger.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Tagging; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Tagging; @@ -25,7 +26,7 @@ namespace Microsoft.CodeAnalysis.Classification { internal partial class CopyPasteAndPrintingClassificationBufferTaggerProvider { - private sealed class Tagger : ForegroundThreadAffinitizedObject, IAccurateTagger, IDisposable + private sealed class Tagger : IAccurateTagger, IDisposable { private readonly CopyPasteAndPrintingClassificationBufferTaggerProvider _owner; private readonly ITextBuffer _subjectBuffer; @@ -43,7 +44,6 @@ public Tagger( ITextBuffer subjectBuffer, IAsynchronousOperationListener asyncListener, IGlobalOptionService globalOptions) - : base(owner.ThreadingContext) { _owner = owner; _subjectBuffer = subjectBuffer; @@ -68,7 +68,7 @@ public event EventHandler TagsChanged { add { } remove { public void Dispose() { - this.AssertIsForeground(); + _owner._threadingContext.ThrowIfNotOnUIThread(); _eventSource.Changed -= OnEventSourceChanged; _eventSource.Disconnect(); } @@ -94,7 +94,7 @@ private void OnEventSourceChanged(object? sender, TaggerEventArgs _) public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) { - this.AssertIsForeground(); + _owner._threadingContext.ThrowIfNotOnUIThread(); // we never return any tags for GetTags. This tagger is only for 'Accurate' scenarios. return Array.Empty>(); @@ -102,7 +102,7 @@ public IEnumerable> GetTags(NormalizedSnapshotSpanC public IEnumerable> GetAllTags(NormalizedSnapshotSpanCollection spans, CancellationToken cancellationToken) { - this.AssertIsForeground(); + _owner._threadingContext.ThrowIfNotOnUIThread(); if (spans.Count == 0) return Array.Empty>(); @@ -136,7 +136,7 @@ public IEnumerable> GetAllTags(NormalizedSnapshotSp var context = new TaggerContext(document, snapshot); var options = _globalOptions.GetClassificationOptions(document.Project.Language); - ThreadingContext.JoinableTaskFactory.Run(async () => + _owner._threadingContext.JoinableTaskFactory.Run(async () => { var snapshotSpan = new DocumentSnapshotSpan(document, spanToTag); diff --git a/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.cs b/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.cs index fdb1664ffb406..e1f5b9fc1145f 100644 --- a/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.cs +++ b/src/EditorFeatures/Core/Classification/CopyPasteAndPrintingClassificationBufferTaggerProvider.cs @@ -27,9 +27,10 @@ namespace Microsoft.CodeAnalysis.Classification [TagType(typeof(IClassificationTag))] [ContentType(ContentTypeNames.CSharpContentType)] [ContentType(ContentTypeNames.VisualBasicContentType)] - internal partial class CopyPasteAndPrintingClassificationBufferTaggerProvider : ForegroundThreadAffinitizedObject, ITaggerProvider + internal partial class CopyPasteAndPrintingClassificationBufferTaggerProvider : ITaggerProvider { private readonly IAsynchronousOperationListener _asyncListener; + private readonly IThreadingContext _threadingContext; private readonly ClassificationTypeMap _typeMap; private readonly IGlobalOptionService _globalOptions; @@ -40,8 +41,8 @@ public CopyPasteAndPrintingClassificationBufferTaggerProvider( ClassificationTypeMap typeMap, IAsynchronousOperationListenerProvider listenerProvider, IGlobalOptionService globalOptions) - : base(threadingContext) { + _threadingContext = threadingContext; _typeMap = typeMap; _asyncListener = listenerProvider.GetListener(FeatureAttribute.Classification); _globalOptions = globalOptions; @@ -49,7 +50,7 @@ public CopyPasteAndPrintingClassificationBufferTaggerProvider( public IAccurateTagger? CreateTagger(ITextBuffer buffer) where T : ITag { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); // The LSP client will handle producing tags when running under the LSP editor. // Our tagger implementation should return nothing to prevent conflicts. diff --git a/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs b/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs index 6a1137eb1b944..cdf8c8795038f 100644 --- a/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs +++ b/src/EditorFeatures/Core/Classification/Semantic/AbstractSemanticOrEmbeddedClassificationViewTaggerProvider.cs @@ -58,7 +58,7 @@ protected AbstractSemanticOrEmbeddedClassificationViewTaggerProvider( protected sealed override ITaggerEventSource CreateEventSource(ITextView? textView, ITextBuffer subjectBuffer) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); Contract.ThrowIfNull(textView); // Note: we don't listen for OnTextChanged. They'll get reported by the ViewSpan changing and also the @@ -78,7 +78,7 @@ protected sealed override ITaggerEventSource CreateEventSource(ITextView? textVi protected sealed override IEnumerable GetSpansToTag(ITextView? textView, ITextBuffer subjectBuffer) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); Contract.ThrowIfNull(textView); // Find the visible span some 100 lines +/- what's actually in view. This way diff --git a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.LastLineCache.cs b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.LastLineCache.cs index d70e0e3951932..5e8d1361d4d26 100644 --- a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.LastLineCache.cs +++ b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.LastLineCache.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.Text; @@ -16,7 +17,7 @@ internal partial class TagComputer /// /// it is a helper class that encapsulates logic on holding onto last classification result /// - private class LastLineCache : ForegroundThreadAffinitizedObject + private class LastLineCache { // this helper class is primarily to improve active typing perf. don't bother to cache // something very big. @@ -25,14 +26,16 @@ private class LastLineCache : ForegroundThreadAffinitizedObject // mutating state private SnapshotSpan _span; private readonly ArrayBuilder _classifications = new(); + private readonly IThreadingContext _threadingContext; - public LastLineCache(IThreadingContext threadingContext) : base(threadingContext) + public LastLineCache(IThreadingContext threadingContext) { + _threadingContext = threadingContext; } private void Clear() { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); _span = default; _classifications.Clear(); @@ -40,7 +43,7 @@ private void Clear() public bool TryUseCache(SnapshotSpan span, ArrayBuilder classifications) { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); // currently, it is using SnapshotSpan even though holding onto it could be // expensive. reason being it should be very soon sync-ed to latest snapshot. @@ -56,7 +59,7 @@ public bool TryUseCache(SnapshotSpan span, ArrayBuilder classifi public void Update(SnapshotSpan span, ArrayBuilder classifications) { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); this.Clear(); if (classifications.Count < MaxClassificationNumber) diff --git a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs index dbb7f4733d63a..0ac9dc4765520 100644 --- a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs +++ b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.TagComputer.cs @@ -34,7 +34,7 @@ internal partial class SyntacticClassificationTaggerProvider /// will determine which sections of the file changed and we will use that to notify the editor /// about what needs to be reclassified. /// - internal partial class TagComputer : ForegroundThreadAffinitizedObject + internal partial class TagComputer { private readonly SyntacticClassificationTaggerProvider _taggerProvider; private readonly ITextBuffer2 _subjectBuffer; @@ -82,7 +82,6 @@ public TagComputer( IAsynchronousOperationListener asyncListener, IClassificationTypeMap typeMap, TimeSpan diffTimeout) - : base(taggerProvider.ThreadingContext, assertIsForeground: false) { _taggerProvider = taggerProvider; _subjectBuffer = subjectBuffer; @@ -96,7 +95,7 @@ public TagComputer( asyncListener, _disposalCancellationSource.Token); - _lastLineCache = new LastLineCache(taggerProvider.ThreadingContext); + _lastLineCache = new LastLineCache(taggerProvider._threadingContext); _workspaceRegistration = Workspace.GetWorkspaceRegistration(subjectBuffer.AsTextContainer()); _workspaceRegistration.WorkspaceChanged += OnWorkspaceRegistrationChanged; @@ -125,7 +124,7 @@ private async Task SwitchToMainThreadAndHookupWorkspaceAsync() { try { - await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(_disposalCancellationSource.Token); + await _taggerProvider._threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(_disposalCancellationSource.Token); // We both try to connect synchronously, and register for workspace registration events. // It's possible (particularly in tests), to connect in the startup path, but then get a @@ -153,13 +152,13 @@ private async Task SwitchToMainThreadAndHookupWorkspaceAsync() internal void IncrementReferenceCount() { - this.AssertIsForeground(); + _taggerProvider._threadingContext.ThrowIfNotOnUIThread(); _taggerReferenceCount++; } internal void DecrementReferenceCount() { - this.AssertIsForeground(); + _taggerProvider._threadingContext.ThrowIfNotOnUIThread(); _taggerReferenceCount--; if (_taggerReferenceCount == 0) @@ -177,7 +176,7 @@ internal void DecrementReferenceCount() private void ConnectToWorkspace(Workspace workspace) { - this.AssertIsForeground(); + _taggerProvider._threadingContext.ThrowIfNotOnUIThread(); _workspace = workspace; _workspace.WorkspaceChanged += this.OnWorkspaceChanged; @@ -189,7 +188,7 @@ private void ConnectToWorkspace(Workspace workspace) public void DisconnectFromWorkspace() { - this.AssertIsForeground(); + _taggerProvider._threadingContext.ThrowIfNotOnUIThread(); lock (_gate) { @@ -343,7 +342,7 @@ async ValueTask ComputeChangedSpanAsync() public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) { - this.AssertIsForeground(); + _taggerProvider._threadingContext.ThrowIfNotOnUIThread(); using (Logger.LogBlock(FunctionId.Tagger_SyntacticClassification_TagComputer_GetTags, CancellationToken.None)) { @@ -353,7 +352,7 @@ public IEnumerable> GetTags(NormalizedSnapshotSpanC private IEnumerable>? GetTagsWorker(NormalizedSnapshotSpanCollection spans) { - this.AssertIsForeground(); + _taggerProvider._threadingContext.ThrowIfNotOnUIThread(); if (spans.Count == 0 || _workspace == null) return null; @@ -372,7 +371,7 @@ public IEnumerable> GetTags(NormalizedSnapshotSpanC void AddClassifications(SnapshotSpan span) { - this.AssertIsForeground(); + _taggerProvider._threadingContext.ThrowIfNotOnUIThread(); // First, get the tree and snapshot that we'll be operating over. var (lastProcessedSnapshot, lastProcessedDocument, lastProcessedRoot) = GetLastProcessedData(); @@ -405,7 +404,7 @@ void AddClassifications(SnapshotSpan span) private void AddLexicalClassifications(IClassificationService classificationService, SnapshotSpan span, ArrayBuilder classifiedSpans) { - this.AssertIsForeground(); + _taggerProvider._threadingContext.ThrowIfNotOnUIThread(); classificationService.AddLexicalClassifications( span.Snapshot.AsText(), span.Span.ToTextSpan(), classifiedSpans, CancellationToken.None); @@ -415,7 +414,7 @@ private void AddSyntacticClassificationsForDocument( IClassificationService classificationService, SnapshotSpan span, Document document, SyntaxNode? root, ArrayBuilder classifiedSpans) { - this.AssertIsForeground(); + _taggerProvider._threadingContext.ThrowIfNotOnUIThread(); var cancellationToken = CancellationToken.None; if (_lastLineCache.TryUseCache(span, classifiedSpans)) @@ -438,7 +437,7 @@ private void AddClassifiedSpansForPreviousDocument( ITextSnapshot lastProcessedSnapshot, Document lastProcessedDocument, SyntaxNode? lastProcessedRoot, ArrayBuilder classifiedSpans) { - this.AssertIsForeground(); + _taggerProvider._threadingContext.ThrowIfNotOnUIThread(); // Slightly more complicated case. They're asking for the classifications for a // different snapshot than what we have a parse tree for. So we first translate the span diff --git a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.cs b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.cs index 9d79e1645f976..17344a7bb3f35 100644 --- a/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.cs +++ b/src/EditorFeatures/Core/Classification/Syntactic/SyntacticClassificationTaggerProvider.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Editor.Shared.Tagging; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -23,9 +24,10 @@ namespace Microsoft.CodeAnalysis.Classification [ContentType(ContentTypeNames.RoslynContentType)] [TextViewRole(PredefinedTextViewRoles.Document)] [TagType(typeof(IClassificationTag))] - internal partial class SyntacticClassificationTaggerProvider : ForegroundThreadAffinitizedObject, ITaggerProvider + internal partial class SyntacticClassificationTaggerProvider : ITaggerProvider { private readonly IAsynchronousOperationListener _listener; + private readonly IThreadingContext _threadingContext; private readonly SyntacticClassificationTypeMap _typeMap; private readonly IGlobalOptionService _globalOptions; @@ -38,8 +40,8 @@ public SyntacticClassificationTaggerProvider( SyntacticClassificationTypeMap typeMap, IGlobalOptionService globalOptions, IAsynchronousOperationListenerProvider listenerProvider) - : base(threadingContext, assertIsForeground: false) { + _threadingContext = threadingContext; _typeMap = typeMap; _globalOptions = globalOptions; _listener = listenerProvider.GetListener(FeatureAttribute.Classification); @@ -47,7 +49,7 @@ public SyntacticClassificationTaggerProvider( public ITagger? CreateTagger(ITextBuffer buffer) where T : ITag { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); if (!_globalOptions.GetOption(InternalFeatureOnOffOptions.SyntacticColorizer)) return null; diff --git a/src/EditorFeatures/Core/CodeActions/CodeActionEditHandlerService.cs b/src/EditorFeatures/Core/CodeActions/CodeActionEditHandlerService.cs index 69d77bc3fd579..89442bf826e2a 100644 --- a/src/EditorFeatures/Core/CodeActions/CodeActionEditHandlerService.cs +++ b/src/EditorFeatures/Core/CodeActions/CodeActionEditHandlerService.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Undo; using Microsoft.CodeAnalysis.ErrorReporting; @@ -25,8 +26,9 @@ namespace Microsoft.CodeAnalysis.CodeActions { [Export(typeof(ICodeActionEditHandlerService))] - internal class CodeActionEditHandlerService : ForegroundThreadAffinitizedObject, ICodeActionEditHandlerService + internal class CodeActionEditHandlerService : ICodeActionEditHandlerService { + private readonly IThreadingContext _threadingContext; private readonly IPreviewFactoryService _previewService; private readonly IInlineRenameService _renameService; private readonly ITextBufferAssociatedViewService _associatedViewService; @@ -38,8 +40,8 @@ public CodeActionEditHandlerService( IPreviewFactoryService previewService, IInlineRenameService renameService, ITextBufferAssociatedViewService associatedViewService) - : base(threadingContext) { + _threadingContext = threadingContext; _previewService = previewService; _renameService = renameService; _associatedViewService = associatedViewService; @@ -77,7 +79,7 @@ public CodeActionEditHandlerService( if (op is PreviewOperation previewOp) { currentResult = SolutionPreviewResult.Merge(currentResult, - new SolutionPreviewResult(ThreadingContext, new SolutionPreviewItem( + new SolutionPreviewResult(_threadingContext, new SolutionPreviewItem( projectId: null, documentId: null, lazyPreview: c => previewOp.GetPreviewAsync(c)))); continue; @@ -88,7 +90,7 @@ public CodeActionEditHandlerService( if (title != null) { currentResult = SolutionPreviewResult.Merge(currentResult, - new SolutionPreviewResult(ThreadingContext, new SolutionPreviewItem( + new SolutionPreviewResult(_threadingContext, new SolutionPreviewItem( projectId: null, documentId: null, text: title))); continue; } @@ -106,7 +108,7 @@ public async Task ApplyAsync( // Much of the work we're going to do will be on the UI thread, so switch there preemptively. // When we get to the expensive parts we can do in the BG then we'll switch over to relinquish // the UI thread. - await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await this._threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); if (operations.IsDefaultOrEmpty) { @@ -143,7 +145,7 @@ public async Task ApplyAsync( { try { - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); applied = await operations.Single().TryApplyAsync( workspace, progressTracker, cancellationToken).ConfigureAwait(true); @@ -266,7 +268,7 @@ private async Task ProcessOperationsAsync( Workspace workspace, ImmutableArray operations, IProgressTracker progressTracker, CancellationToken cancellationToken) { - await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await this._threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var applied = true; var seenApplyChanges = false; @@ -281,7 +283,7 @@ private async Task ProcessOperationsAsync( seenApplyChanges = true; } - this.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); applied &= await operation.TryApplyAsync(workspace, progressTracker, cancellationToken).ConfigureAwait(true); } @@ -300,7 +302,7 @@ private async Task TryNavigateToLocationOrStartRenameSessionAsync( { var navigationService = workspace.Services.GetRequiredService(); await navigationService.TryNavigateToPositionAsync( - this.ThreadingContext, workspace, navigationOperation.DocumentId, navigationOperation.Position, cancellationToken).ConfigureAwait(false); + this._threadingContext, workspace, navigationOperation.DocumentId, navigationOperation.Position, cancellationToken).ConfigureAwait(false); return; } @@ -318,7 +320,7 @@ await navigationService.TryNavigateToPositionAsync( { var navigationService = workspace.Services.GetRequiredService(); await navigationService.TryNavigateToPositionAsync( - this.ThreadingContext, workspace, documentId, navigationToken.Value.SpanStart, cancellationToken).ConfigureAwait(false); + this._threadingContext, workspace, documentId, navigationToken.Value.SpanStart, cancellationToken).ConfigureAwait(false); return; } @@ -343,7 +345,7 @@ await navigationService.TryNavigateToPositionAsync( var navigationService = editorWorkspace.Services.GetRequiredService(); if (await navigationService.TryNavigateToSpanAsync( - this.ThreadingContext, editorWorkspace, documentId, resolvedRenameToken.Span, cancellationToken).ConfigureAwait(false)) + this._threadingContext, editorWorkspace, documentId, resolvedRenameToken.Span, cancellationToken).ConfigureAwait(false)) { var openDocument = workspace.CurrentSolution.GetRequiredDocument(documentId); var openRoot = await openDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -361,7 +363,7 @@ await navigationService.TryNavigateToPositionAsync( var snapshot = text.FindCorrespondingEditorTextSnapshot(); if (snapshot != null) { - await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await this._threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); _renameService.StartInlineSession(openDocument, resolvedRenameToken.AsToken().Span, cancellationToken); } } diff --git a/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTaggerProvider.cs b/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTaggerProvider.cs index 25df235ec41e7..6e243b1a36b85 100644 --- a/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTaggerProvider.cs +++ b/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTaggerProvider.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Tagging; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Tagging; @@ -53,7 +54,7 @@ public ActiveStatementTaggerProvider( protected override ITaggerEventSource CreateEventSource(ITextView? textView, ITextBuffer subjectBuffer) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); return TaggerEventSources.Compose( new EventSource(subjectBuffer), diff --git a/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs b/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs index b40b7cb1e9b6b..5aa4cc1f8600e 100644 --- a/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs +++ b/src/EditorFeatures/Core/Extensibility/NavigationBar/AbstractEditorNavigationBarItemService.cs @@ -16,11 +16,13 @@ namespace Microsoft.CodeAnalysis.Editor.Extensibility.NavigationBar { - internal abstract class AbstractEditorNavigationBarItemService : ForegroundThreadAffinitizedObject, INavigationBarItemService + internal abstract class AbstractEditorNavigationBarItemService : INavigationBarItemService { + protected readonly IThreadingContext ThreadingContext; + protected AbstractEditorNavigationBarItemService(IThreadingContext threadingContext) - : base(threadingContext, assertIsForeground: false) { + ThreadingContext = threadingContext; } protected abstract Task TryNavigateToItemAsync(Document document, WrappedNavigationBarItem item, ITextView textView, ITextVersion textVersion, CancellationToken cancellationToken); @@ -55,7 +57,7 @@ protected async Task NavigateToPositionAsync(Workspace workspace, DocumentId doc ThreadingContext, workspace, documentId, position, virtualSpace, NavigationOptions.Default, cancellationToken).ConfigureAwait(false)) { // Ensure we're back on the UI thread before showing a failure message. - await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var notificationService = workspace.Services.GetRequiredService(); notificationService.SendNotification(EditorFeaturesResources.The_definition_of_the_object_is_hidden, severity: NotificationSeverity.Error); } diff --git a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToCommandHandler`2.cs b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToCommandHandler`2.cs index f40be58be07fa..7f149dd8f3b06 100644 --- a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToCommandHandler`2.cs +++ b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToCommandHandler`2.cs @@ -93,8 +93,7 @@ public CommandState GetCommandState(TCommandArgs args) public bool ExecuteCommand(TCommandArgs args, CommandExecutionContext context) { - // Should only be called on the UI thread. - Contract.ThrowIfFalse(_threadingContext.HasMainThread); + _threadingContext.ThrowIfNotOnUIThread(); var subjectBuffer = args.SubjectBuffer; var caret = args.TextView.GetCaretPoint(subjectBuffer); @@ -128,8 +127,7 @@ private async Task ExecuteCommandAsync( // and failure ourselves. try { - // Should only be called on the UI thread. - Contract.ThrowIfFalse(_threadingContext.HasMainThread); + _threadingContext.ThrowIfNotOnUIThread(); // Make an tracking token so that integration tests can wait until we're complete. using var token = _listener.BeginAsyncOperation($"{GetType().Name}.{nameof(ExecuteCommandAsync)}"); diff --git a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToSymbolService.cs b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToSymbolService.cs index e0192170bc92f..1bbc820c4cb23 100644 --- a/src/EditorFeatures/Core/GoToDefinition/AbstractGoToSymbolService.cs +++ b/src/EditorFeatures/Core/GoToDefinition/AbstractGoToSymbolService.cs @@ -10,13 +10,8 @@ namespace Microsoft.CodeAnalysis.GoToDefinition { // Ctrl+Click (GoToSymbol) - internal abstract class AbstractGoToSymbolService : ForegroundThreadAffinitizedObject, IGoToSymbolService + internal abstract class AbstractGoToSymbolService : IGoToSymbolService { - protected AbstractGoToSymbolService(IThreadingContext threadingContext, bool assertIsForeground = false) - : base(threadingContext, assertIsForeground) - { - } - public async Task GetSymbolsAsync(GoToSymbolContext context) { var document = context.Document; diff --git a/src/EditorFeatures/Core/InlineHints/InlineHintsDataTaggerProvider.cs b/src/EditorFeatures/Core/InlineHints/InlineHintsDataTaggerProvider.cs index 8133adad735e6..6bf114df439cc 100644 --- a/src/EditorFeatures/Core/InlineHints/InlineHintsDataTaggerProvider.cs +++ b/src/EditorFeatures/Core/InlineHints/InlineHintsDataTaggerProvider.cs @@ -66,7 +66,7 @@ protected override ITaggerEventSource CreateEventSource(ITextView? textView, ITe { Contract.ThrowIfNull(textView); return TaggerEventSources.Compose( - TaggerEventSources.OnViewSpanChanged(ThreadingContext, textView), + TaggerEventSources.OnViewSpanChanged(this.ThreadingContext, textView), TaggerEventSources.OnWorkspaceChanged(subjectBuffer, _listener), TaggerEventSources.OnOptionChanged(subjectBuffer, InlineHintsGlobalStateOption.DisplayAllOverride), TaggerEventSources.OnOptionChanged(subjectBuffer, InlineHintsOptionsStorage.EnabledForParameters), @@ -85,7 +85,7 @@ protected override ITaggerEventSource CreateEventSource(ITextView? textView, ITe protected override IEnumerable GetSpansToTag(ITextView? textView, ITextBuffer subjectBuffer) { - this.AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); Contract.ThrowIfNull(textView); // Find the visible span some 100 lines +/- what's actually in view. This way diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs index 72926d07b4379..44b1ce0f52be2 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.OpenTextBufferManager.cs @@ -29,7 +29,7 @@ internal partial class InlineRenameSession /// /// Manages state for open text buffers. /// - internal class OpenTextBufferManager : ForegroundThreadAffinitizedObject + internal class OpenTextBufferManager { private readonly DynamicReadOnlyRegionQuery _isBufferReadOnly; private readonly InlineRenameSession _session; @@ -58,7 +58,6 @@ public OpenTextBufferManager( ITextBuffer subjectBuffer, Workspace workspace, ITextBufferFactoryService textBufferFactoryService) - : base(session.ThreadingContext) { _session = session; _subjectBuffer = subjectBuffer; @@ -95,7 +94,7 @@ public ITextView ActiveTextView private void UpdateReadOnlyRegions(bool removeOnly = false) { - AssertIsForeground(); + _session._threadingContext.ThrowIfNotOnUIThread(); if (!removeOnly && _session.ReplacementText == string.Empty) { return; @@ -170,7 +169,7 @@ internal IEnumerable GetEditableSpansForSnapshot(ITextSnapshot sna internal void SetReferenceSpans(IEnumerable spans) { - AssertIsForeground(); + _session._threadingContext.ThrowIfNotOnUIThread(); if (spans.SetEquals(_referenceSpanToLinkedRenameSpanMap.Keys)) { @@ -219,7 +218,7 @@ private static string GetTriggerText(Document document, TextSpan span) private void OnTextBufferChanged(object sender, TextContentChangedEventArgs args) { - AssertIsForeground(); + _session._threadingContext.ThrowIfNotOnUIThread(); // This might be an event fired due to our own edit if (args.EditTag == s_propagateSpansEditTag || _session._isApplyingEdit) @@ -272,7 +271,7 @@ private bool AreAllReferenceSpansMappable() internal void ApplyReplacementText(bool updateSelection = true) { - AssertIsForeground(); + _session._threadingContext.ThrowIfNotOnUIThread(); if (!AreAllReferenceSpansMappable()) { @@ -294,7 +293,7 @@ internal void ApplyReplacementText(bool updateSelection = true) internal void Disconnect(bool documentIsClosed, bool rollbackTemporaryEdits) { - AssertIsForeground(); + _session._threadingContext.ThrowIfNotOnUIThread(); // Detach from the buffer; it is important that this is done before we start // undoing transactions, since the undo actions will cause buffer changes. @@ -316,7 +315,7 @@ internal void Disconnect(bool documentIsClosed, bool rollbackTemporaryEdits) internal void ApplyConflictResolutionEdits(IInlineRenameReplacementInfo conflictResolution, LinkedFileMergeSessionResult mergeResult, IEnumerable documents, CancellationToken cancellationToken) { - AssertIsForeground(); + _session._threadingContext.ThrowIfNotOnUIThread(); if (!AreAllReferenceSpansMappable()) { @@ -587,7 +586,7 @@ private IEnumerable GetMergedReplacementInfos( Document postMergeDocument, CancellationToken cancellationToken) { - AssertIsForeground(); + _session._threadingContext.ThrowIfNotOnUIThread(); var textDiffService = preMergeDocument.Project.Solution.Workspace.Services.GetService(); var contentType = preMergeDocument.Project.LanguageServices.GetService().GetDefaultContentType(); diff --git a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs index 862b898c542a5..155cfbbfcd2a6 100644 --- a/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs +++ b/src/EditorFeatures/Core/InlineRename/InlineRenameSession.cs @@ -34,7 +34,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { - internal partial class InlineRenameSession : ForegroundThreadAffinitizedObject, IInlineRenameSession, IFeatureController + internal partial class InlineRenameSession : IInlineRenameSession, IFeatureController { private readonly Workspace _workspace; private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; @@ -48,7 +48,7 @@ internal partial class InlineRenameSession : ForegroundThreadAffinitizedObject, private readonly Document _triggerDocument; private readonly ITextView _triggerView; private readonly IDisposable _inlineRenameSessionDurationLogBlock; - + private readonly IThreadingContext _threadingContext; public readonly InlineRenameService RenameService; private bool _dismissed; @@ -125,9 +125,9 @@ public InlineRenameSession( IFeatureServiceFactory featureServiceFactory, IEnumerable refactorNotifyServices, IAsynchronousOperationListener asyncListener) - : base(threadingContext, assertIsForeground: true) { // This should always be touching a symbol since we verified that upon invocation + _threadingContext = threadingContext; _renameInfo = renameInfo; _triggerDocument = triggerSpan.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); @@ -148,7 +148,6 @@ public InlineRenameSession( // Disable completion when an inline rename session starts _featureService = featureServiceFactory.GlobalFeatureService; _completionDisabledToken = _featureService.Disable(PredefinedEditorFeatureNames.Completion, this); - RenameService = renameService; _uiThreadOperationExecutor = uiThreadOperationExecutor; _refactorNotifyServices = refactorNotifyServices; @@ -243,7 +242,7 @@ private void InitializeOpenBuffers(SnapshotSpan triggerSpan) this.UndoManager.CreateInitialState(this.ReplacementText, _triggerView.Selection, new SnapshotSpan(triggerSpan.Snapshot, startingSpan)); _openTextBuffers[triggerSpan.Snapshot.TextBuffer].SetReferenceSpans(SpecializedCollections.SingletonEnumerable(startingSpan.ToTextSpan())); - UpdateReferenceLocationsTask(ThreadingContext.JoinableTaskFactory.RunAsync( + UpdateReferenceLocationsTask(_threadingContext.JoinableTaskFactory.RunAsync( () => _renameInfo.FindRenameLocationsAsync(_options, _cancellationTokenSource.Token))); RenameTrackingDismisser.DismissRenameTracking(_workspace, _workspace.GetOpenDocumentIds()); @@ -251,7 +250,7 @@ private void InitializeOpenBuffers(SnapshotSpan triggerSpan) private bool TryPopulateOpenTextBufferManagerForBuffer(ITextBuffer buffer) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); VerifyNotDismissed(); if (_workspace.Kind == WorkspaceKind.Interactive) @@ -275,7 +274,7 @@ private bool TryPopulateOpenTextBufferManagerForBuffer(ITextBuffer buffer) private void OnSubjectBuffersConnected(object sender, SubjectBuffersConnectedEventArgs e) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); foreach (var buffer in e.SubjectBuffers) { if (buffer.GetWorkspace() == _workspace) @@ -290,10 +289,10 @@ private void OnSubjectBuffersConnected(object sender, SubjectBuffersConnectedEve private void UpdateReferenceLocationsTask(JoinableTask findRenameLocationsTask) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); var asyncToken = _asyncListener.BeginAsyncOperation("UpdateReferencesTask"); - _allRenameLocationsTask = ThreadingContext.JoinableTaskFactory.RunAsync(async () => + _allRenameLocationsTask = _threadingContext.JoinableTaskFactory.RunAsync(async () => { var inlineRenameLocations = await findRenameLocationsTask.JoinAsync().ConfigureAwaitRunInline(); @@ -301,7 +300,7 @@ private void UpdateReferenceLocationsTask(JoinableTask // from running prior to the completion of the UI operation), but the implementation does not currently // follow the originally-intended design. // https://github.com/dotnet/roslyn/issues/40890 - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, _cancellationTokenSource.Token); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, _cancellationTokenSource.Token); RaiseSessionSpansUpdated(inlineRenameLocations.Locations.ToImmutableArray()); @@ -339,14 +338,14 @@ public void RefreshRenameSessionWithOptionsChanged(SymbolRenameOptions newOption return; } - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); VerifyNotDismissed(); _options = newOptions; var cancellationToken = _cancellationTokenSource.Token; - UpdateReferenceLocationsTask(ThreadingContext.JoinableTaskFactory.RunAsync(async () => + UpdateReferenceLocationsTask(_threadingContext.JoinableTaskFactory.RunAsync(async () => { // Join prior work before proceeding, since it performs a required state update. // https://github.com/dotnet/roslyn/pull/34254#discussion_r267024593 @@ -362,7 +361,7 @@ public void RefreshRenameSessionWithOptionsChanged(SymbolRenameOptions newOption public void SetPreviewChanges(bool value) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); VerifyNotDismissed(); _previewChanges = value; @@ -417,7 +416,7 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args) private void RaiseSessionSpansUpdated(ImmutableArray locations) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); SetReferenceLocations(locations); // It's OK to call SetReferenceLocations with all documents, including unchangeable ones, @@ -435,7 +434,7 @@ private void RaiseSessionSpansUpdated(ImmutableArray locat private void SetReferenceLocations(ImmutableArray locations) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); var locationsByDocument = locations.ToLookup(l => l.Document.Id); @@ -463,7 +462,7 @@ private void SetReferenceLocations(ImmutableArray location /// internal void ApplyReplacementText(string replacementText, bool propagateEditImmediately) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); VerifyNotDismissed(); this.ReplacementText = _renameInfo.GetFinalSymbolName(replacementText); @@ -471,7 +470,7 @@ internal void ApplyReplacementText(string replacementText, bool propagateEditImm Action propagateEditAction = delegate { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); if (_dismissed) { @@ -519,9 +518,9 @@ internal void ApplyReplacementText(string replacementText, bool propagateEditImm else { // When responding to a text edit, we delay propagating the edit until the first transaction completes. - ThreadingContext.JoinableTaskFactory.RunAsync(async () => + _threadingContext.JoinableTaskFactory.RunAsync(async () => { - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true); propagateEditAction(); }); } @@ -529,7 +528,7 @@ internal void ApplyReplacementText(string replacementText, bool propagateEditImm private void UpdateConflictResolutionTask() { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); _conflictResolutionTaskCancellationSource.Cancel(); _conflictResolutionTaskCancellationSource = new CancellationTokenSource(); @@ -547,7 +546,7 @@ private void UpdateConflictResolutionTask() var asyncToken = _asyncListener.BeginAsyncOperation(nameof(UpdateConflictResolutionTask)); - _conflictResolutionTask = ThreadingContext.JoinableTaskFactory.RunAsync(async () => + _conflictResolutionTask = _threadingContext.JoinableTaskFactory.RunAsync(async () => { // Join prior work before proceeding, since it performs a required state update. // https://github.com/dotnet/roslyn/pull/34254#discussion_r267024593 @@ -576,7 +575,7 @@ private void QueueApplyReplacements() var cancellationToken = _conflictResolutionTaskCancellationSource.Token; var asyncToken = _asyncListener.BeginAsyncOperation(nameof(QueueApplyReplacements)); - var replacementOperation = ThreadingContext.JoinableTaskFactory.RunAsync(async () => + var replacementOperation = _threadingContext.JoinableTaskFactory.RunAsync(async () => { var replacementInfo = await _conflictResolutionTask.JoinAsync(CancellationToken.None).ConfigureAwait(false); if (replacementInfo == null || cancellationToken.IsCancellationRequested) @@ -587,7 +586,7 @@ private void QueueApplyReplacements() // Switch to a background thread for expensive work await TaskScheduler.Default; var computedMergeResult = await ComputeMergeResultAsync(replacementInfo, cancellationToken); - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); ApplyReplacements(computedMergeResult.replacementInfo, computedMergeResult.mergeResult, cancellationToken); }); replacementOperation.Task.CompletesAsyncOperation(asyncToken); @@ -602,7 +601,7 @@ private void QueueApplyReplacements() private void ApplyReplacements(IInlineRenameReplacementInfo replacementInfo, LinkedFileMergeSessionResult mergeResult, CancellationToken cancellationToken) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); cancellationToken.ThrowIfCancellationRequested(); RaiseReplacementsComputed(replacementInfo); @@ -623,7 +622,7 @@ private void ApplyReplacements(IInlineRenameReplacementInfo replacementInfo, Lin private void RaiseReplacementsComputed(IInlineRenameReplacementInfo resolution) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); ReplacementsComputed?.Invoke(this, resolution); } @@ -665,7 +664,7 @@ public void Cancel() private void Cancel(bool rollbackTemporaryEdits) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); VerifyNotDismissed(); LogRenameSession(RenameLogMessage.UserActionOutcome.Canceled, previewChanges: false); @@ -680,7 +679,7 @@ public void Commit(bool previewChanges = false) /// langword="false"/> otherwise private bool CommitWorker(bool previewChanges) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); VerifyNotDismissed(); // If the identifier was deleted (or didn't change at all) then cancel the operation. diff --git a/src/EditorFeatures/Core/IntelliSense/AbstractController.cs b/src/EditorFeatures/Core/IntelliSense/AbstractController.cs index d701d61c49120..59ebd56ec2481 100644 --- a/src/EditorFeatures/Core/IntelliSense/AbstractController.cs +++ b/src/EditorFeatures/Core/IntelliSense/AbstractController.cs @@ -11,13 +11,15 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Roslyn.Utilities; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense { - internal abstract class AbstractController : ForegroundThreadAffinitizedObject, IController + internal abstract class AbstractController : IController where TSession : class, ISession where TPresenterSession : IIntelliSensePresenterSession { + protected readonly IThreadingContext ThreadingContext; protected readonly IGlobalOptionService GlobalOptions; protected readonly ITextView TextView; protected readonly ITextBuffer SubjectBuffer; @@ -43,9 +45,9 @@ protected AbstractController( IAsynchronousOperationListener asyncListener, IDocumentProvider documentProvider, string asyncOperationId) - : base(threadingContext) { this.GlobalOptions = globalOptions; + ThreadingContext = threadingContext; this.TextView = textView; this.SubjectBuffer = subjectBuffer; this.Presenter = presenter; @@ -67,7 +69,7 @@ protected AbstractController( private void OnTextViewClosed(object sender, EventArgs e) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); DismissSessionIfActive(); this.TextView.Closed -= OnTextViewClosed; @@ -77,7 +79,7 @@ private void OnTextViewClosed(object sender, EventArgs e) public TModel WaitForController() { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); VerifySessionIsActive(); return sessionOpt.WaitForController(); } @@ -86,7 +88,7 @@ void IController.OnModelUpdated(TModel result, bool updateController) { // This is only called from the model computation if it was not cancelled. And if it was // not cancelled then we must have a pointer to it (as well as the presenter session). - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); VerifySessionIsActive(); this.OnModelUpdated(result, updateController); @@ -94,7 +96,7 @@ void IController.OnModelUpdated(TModel result, bool updateController) IAsyncToken IController.BeginAsyncOperation(string name, object tag, string filePath, int lineNumber) { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); VerifySessionIsActive(); name = String.IsNullOrEmpty(name) ? _asyncOperationId @@ -104,19 +106,19 @@ IAsyncToken IController.BeginAsyncOperation(string name, object tag, str protected void VerifySessionIsActive() { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); Contract.ThrowIfFalse(IsSessionActive); } protected void VerifySessionIsInactive() { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); Contract.ThrowIfTrue(IsSessionActive); } protected void DismissSessionIfActive() { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); if (IsSessionActive) { this.StopModelComputation(); @@ -125,7 +127,7 @@ protected void DismissSessionIfActive() public void StopModelComputation() { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); VerifySessionIsActive(); // Make a local copy so that we won't do anything that causes us to recurse and try to @@ -137,7 +139,7 @@ public void StopModelComputation() public bool TryHandleEscapeKey() { - AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); // Escape simply dismissed a session if it's up. Otherwise let the next thing in the // chain handle us. diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs index 1059605bec8ed..25b1173f9c839 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CommitManager.cs @@ -28,7 +28,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion { - internal sealed class CommitManager : ForegroundThreadAffinitizedObject, IAsyncCompletionCommitManager + internal sealed class CommitManager : IAsyncCompletionCommitManager { private static readonly AsyncCompletionData.CommitResult CommitResultUnhandled = new(isHandled: false, AsyncCompletionData.CommitBehavior.None); @@ -36,6 +36,7 @@ internal sealed class CommitManager : ForegroundThreadAffinitizedObject, IAsyncC private readonly RecentItemsManager _recentItemsManager; private readonly ITextView _textView; private readonly IGlobalOptionService _globalOptions; + private readonly IThreadingContext _threadingContext; public IEnumerable PotentialCommitCharacters { @@ -53,10 +54,14 @@ public IEnumerable PotentialCommitCharacters } } - internal CommitManager(ITextView textView, RecentItemsManager recentItemsManager, IGlobalOptionService globalOptions, IThreadingContext threadingContext) - : base(threadingContext) + internal CommitManager( + ITextView textView, + RecentItemsManager recentItemsManager, + IGlobalOptionService globalOptions, + IThreadingContext threadingContext) { _globalOptions = globalOptions; + _threadingContext = threadingContext; _recentItemsManager = recentItemsManager; _textView = textView; } @@ -91,7 +96,7 @@ public AsyncCompletionData.CommitResult TryCommit( CancellationToken cancellationToken) { // We can make changes to buffers. We would like to be sure nobody can change them at the same time. - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); var document = subjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) @@ -184,7 +189,7 @@ private AsyncCompletionData.CommitResult Commit( string filterText, CancellationToken cancellationToken) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); bool includesCommitCharacter; if (!subjectBuffer.CheckEditAccess()) @@ -293,7 +298,7 @@ private AsyncCompletionData.CommitResult Commit( if (provider is INotifyCommittingItemCompletionProvider notifyProvider) { - _ = ThreadingContext.JoinableTaskFactory.RunAsync(async () => + _ = _threadingContext.JoinableTaskFactory.RunAsync(async () => { // Make sure the notification isn't sent on UI thread. await TaskScheduler.Default; diff --git a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs index a1d8e717a355a..decd5aa362972 100644 --- a/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs +++ b/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/CompletionSource.cs @@ -38,7 +38,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion { - internal sealed class CompletionSource : ForegroundThreadAffinitizedObject, IAsyncExpandingCompletionSource + internal sealed class CompletionSource : IAsyncExpandingCompletionSource { internal const string PotentialCommitCharacters = nameof(PotentialCommitCharacters); internal const string NonBlockingCompletion = nameof(NonBlockingCompletion); @@ -59,6 +59,7 @@ internal sealed class CompletionSource : ForegroundThreadAffinitizedObject, IAsy private readonly bool _isDebuggerTextView; private readonly ImmutableHashSet _roles; private readonly Lazy _streamingPresenter; + private readonly IThreadingContext _threadingContext; private readonly VSUtilities.IUIThreadOperationExecutor _operationExecutor; private readonly IAsynchronousOperationListener _asyncListener; private readonly IGlobalOptionService _globalOptions; @@ -72,10 +73,10 @@ internal CompletionSource( VSUtilities.IUIThreadOperationExecutor operationExecutor, IAsynchronousOperationListener asyncListener, IGlobalOptionService globalOptions) - : base(threadingContext) { _textView = textView; _streamingPresenter = streamingPresenter; + _threadingContext = threadingContext; _operationExecutor = operationExecutor; _asyncListener = asyncListener; _globalOptions = globalOptions; @@ -93,7 +94,7 @@ public AsyncCompletionData.CompletionStartData InitializeCompletion( { // We take sourceText from document to get a snapshot span. // We would like to be sure that nobody changes buffers at the same time. - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); if (_textView.Selection.Mode == TextSelectionMode.Box) { @@ -526,7 +527,7 @@ private static void UpdateSessionData(IAsyncCompletionSession session, Completio var classificationOptions = _globalOptions.GetClassificationOptions(document.Project.Language); var context = new IntellisenseQuickInfoBuilderContext( - document, classificationOptions, ThreadingContext, _operationExecutor, _asyncListener, _streamingPresenter); + document, classificationOptions, _threadingContext, _operationExecutor, _asyncListener, _streamingPresenter); var elements = IntelliSense.Helpers.BuildInteractiveTextElements(description.TaggedParts, context).ToArray(); if (elements.Length == 0) diff --git a/src/EditorFeatures/Core/IntelliSense/IDocumentProvider.cs b/src/EditorFeatures/Core/IntelliSense/IDocumentProvider.cs index a3ffc4d35bc70..48a94dd2e33b7 100644 --- a/src/EditorFeatures/Core/IntelliSense/IDocumentProvider.cs +++ b/src/EditorFeatures/Core/IntelliSense/IDocumentProvider.cs @@ -5,7 +5,7 @@ #nullable disable using System.Threading; -using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; @@ -17,16 +17,18 @@ internal interface IDocumentProvider Document GetDocument(ITextSnapshot snapshot, CancellationToken cancellationToken); } - internal class DocumentProvider : ForegroundThreadAffinitizedObject, IDocumentProvider + internal class DocumentProvider : IDocumentProvider { + private readonly IThreadingContext _threadingContext; + public DocumentProvider(IThreadingContext threadingContext) - : base(threadingContext) { + _threadingContext = threadingContext; } public Document GetDocument(ITextSnapshot snapshot, CancellationToken cancellationToken) { - AssertIsBackground(); + _threadingContext.ThrowIfNotOnBackgroundThread(); return snapshot.AsText().GetDocumentWithFrozenPartialSemantics(cancellationToken); } } diff --git a/src/EditorFeatures/Core/IntelliSense/ModelComputation.cs b/src/EditorFeatures/Core/IntelliSense/ModelComputation.cs index b33491f914c2b..8a0048d55543e 100644 --- a/src/EditorFeatures/Core/IntelliSense/ModelComputation.cs +++ b/src/EditorFeatures/Core/IntelliSense/ModelComputation.cs @@ -9,17 +9,18 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.TestHooks; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense { - internal class ModelComputation : ForegroundThreadAffinitizedObject - where TModel : class + internal class ModelComputation where TModel : class { #region Fields that can be accessed from either thread + public readonly IThreadingContext ThreadingContext; private readonly CancellationToken _stopCancellationToken; /// @@ -38,7 +39,7 @@ private TaskScheduler _taskScheduler { get { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); return __taskScheduler; } } @@ -55,9 +56,12 @@ private TaskScheduler _taskScheduler #endregion - public ModelComputation(IThreadingContext threadingContext, IController controller, TaskScheduler computationTaskScheduler) - : base(threadingContext) + public ModelComputation( + IThreadingContext threadingContext, + IController controller, + TaskScheduler computationTaskScheduler) { + ThreadingContext = threadingContext; _controller = controller; __taskScheduler = computationTaskScheduler; @@ -72,7 +76,7 @@ public TModel InitialUnfilteredModel { get { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); return _initialUnfilteredModel; } } @@ -81,7 +85,7 @@ public Task ModelTask { get { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); // We should never be called if we were stopped. Contract.ThrowIfTrue(_stopCancellationToken.IsCancellationRequested); @@ -91,7 +95,7 @@ public Task ModelTask public TModel WaitForController() { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); var model = ModelTask.WaitAndGetResult(CancellationToken.None); if (!_notifyControllerTask.IsCompleted) @@ -107,7 +111,7 @@ public TModel WaitForController() public virtual void Stop() { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); // cancel all outstanding tasks. _stopTokenSource.Cancel(); @@ -127,7 +131,7 @@ public void ChainTaskAndNotifyControllerWhenFinished( Func> transformModelAsync, bool updateController = true) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); Contract.ThrowIfTrue(_stopCancellationToken.IsCancellationRequested, "should not chain tasks after we've been cancelled"); @@ -175,7 +179,7 @@ public void ChainTaskAndNotifyControllerWhenFinished( private void OnModelUpdated(TModel result, bool updateController) { - this.AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); // Store the first result so that anyone who cares knows we've computed something if (_initialUnfilteredModel == null) diff --git a/src/EditorFeatures/Core/IntelliSense/Session.cs b/src/EditorFeatures/Core/IntelliSense/Session.cs index 01f444ee1e892..b9cb036383ad1 100644 --- a/src/EditorFeatures/Core/IntelliSense/Session.cs +++ b/src/EditorFeatures/Core/IntelliSense/Session.cs @@ -5,12 +5,13 @@ #nullable disable using System; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense { - internal class Session : ForegroundThreadAffinitizedObject, ISession + internal class Session : ISession where TPresenterSession : IIntelliSensePresenterSession where TController : IController where TModel : class @@ -25,7 +26,6 @@ internal class Session : ForegroundThrea public TPresenterSession PresenterSession { get; } public Session(TController controller, ModelComputation computation, TPresenterSession presenterSession) - : base(computation.ThreadingContext) { this.Controller = controller; this.Computation = computation; @@ -40,14 +40,14 @@ public Session(TController controller, ModelComputation computation, TPr private void OnPresenterSessionDismissed(object sender, EventArgs e) { - AssertIsForeground(); + Computation.ThreadingContext.ThrowIfNotOnUIThread(); Contract.ThrowIfFalse(ReferenceEquals(this.PresenterSession, sender)); Controller.StopModelComputation(); } public virtual void Stop() { - AssertIsForeground(); + Computation.ThreadingContext.ThrowIfNotOnUIThread(); this.Computation.Stop(); this.PresenterSession.Dismissed -= OnPresenterSessionDismissed; this.PresenterSession.Dismiss(); @@ -55,7 +55,7 @@ public virtual void Stop() public TModel WaitForController() { - AssertIsForeground(); + Computation.ThreadingContext.ThrowIfNotOnUIThread(); return Computation.WaitForController(); } } diff --git a/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs b/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs index 8a6b0fc578a62..c728fc62bb524 100644 --- a/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs +++ b/src/EditorFeatures/Core/NavigationBar/NavigationBarController.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Tagging; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Tagging; @@ -29,8 +30,9 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.NavigationBar /// The threading model for this class is simple: all non-static members are affinitized to the /// UI thread. /// - internal partial class NavigationBarController : ForegroundThreadAffinitizedObject, IDisposable + internal partial class NavigationBarController : IDisposable { + private readonly IThreadingContext _threadingContext; private readonly INavigationBarPresenter _presenter; private readonly ITextBuffer _subjectBuffer; private readonly ITextBufferVisibilityTracker? _visibilityTracker; @@ -72,8 +74,8 @@ public NavigationBarController( ITextBufferVisibilityTracker? visibilityTracker, IUIThreadOperationExecutor uiThreadOperationExecutor, IAsynchronousOperationListener asyncListener) - : base(threadingContext) { + _threadingContext = threadingContext; _presenter = presenter; _subjectBuffer = subjectBuffer; _visibilityTracker = visibilityTracker; @@ -127,7 +129,7 @@ private void OnEventSourceChanged(object? sender, TaggerEventArgs e) void IDisposable.Dispose() { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); _presenter.CaretMoved -= OnCaretMoved; _presenter.ViewFocused -= OnViewFocused; @@ -157,13 +159,13 @@ private void StartModelUpdateAndSelectedItemUpdateTasks() private void OnCaretMoved(object? sender, EventArgs e) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); StartSelectedItemUpdateTask(); } private void OnViewFocused(object? sender, EventArgs e) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); StartSelectedItemUpdateTask(); } @@ -193,7 +195,7 @@ private void GetProjectItems(out ImmutableArray projec private void OnItemSelected(object? sender, NavigationBarItemSelectedEventArgs e) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); var token = _asyncListener.BeginAsyncOperation(nameof(OnItemSelected)); var task = OnItemSelectedAsync(e.Item); _ = task.CompletesAsyncOperation(token); @@ -201,7 +203,7 @@ private void OnItemSelected(object? sender, NavigationBarItemSelectedEventArgs e private async Task OnItemSelectedAsync(NavigationBarItem item) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); using var waitContext = _uiThreadOperationExecutor.BeginExecute( EditorFeaturesResources.Navigation_Bars, EditorFeaturesResources.Refreshing_navigation_bars, @@ -222,7 +224,7 @@ private async Task OnItemSelectedAsync(NavigationBarItem item) private async Task ProcessItemSelectionAsync(NavigationBarItem item, CancellationToken cancellationToken) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); if (item is NavigationBarProjectItem projectItem) { diff --git a/src/EditorFeatures/Core/NavigationBar/NavigationBarController_ModelComputation.cs b/src/EditorFeatures/Core/NavigationBar/NavigationBarController_ModelComputation.cs index 696eb52f6bf0f..aa53f06d3b4d4 100644 --- a/src/EditorFeatures/Core/NavigationBar/NavigationBarController_ModelComputation.cs +++ b/src/EditorFeatures/Core/NavigationBar/NavigationBarController_ModelComputation.cs @@ -24,7 +24,7 @@ internal partial class NavigationBarController private async ValueTask ComputeModelAndSelectItemAsync(ImmutableArray unused, CancellationToken cancellationToken) { // Jump back to the UI thread to determine what snapshot the user is processing. - await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var textSnapshot = _subjectBuffer.CurrentSnapshot; // Ensure we switch to the threadpool before calling GetDocumentWithFrozenPartialSemantics. It ensures @@ -60,7 +60,7 @@ internal partial class NavigationBarController // work until far in teh future (or if visibility changes). This ensures our non-visible docs do settle // once enough time has passed, while greatly reducing their impact on the system. await _visibilityTracker.DelayWhileNonVisibleAsync( - this.ThreadingContext, _subjectBuffer, DelayTimeSpan.NonFocus, cancellationToken).ConfigureAwait(false); + _threadingContext, _subjectBuffer, DelayTimeSpan.NonFocus, cancellationToken).ConfigureAwait(false); using (Logger.LogBlock(FunctionId.NavigationBar_ComputeModelAsync, cancellationToken)) { @@ -83,7 +83,7 @@ private async ValueTask SelectItemAsync(CancellationToken cancellationToken) { // Switch to the UI so we can determine where the user is and determine the state the last time we updated // the UI. - await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var currentView = _presenter.TryGetCurrentView(); var caretPosition = currentView?.GetCaretPoint(_subjectBuffer); @@ -112,7 +112,7 @@ private async ValueTask SelectItemAsync(CancellationToken cancellationToken) } // Finally, switch back to the UI to update our state and UI. - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); _presenter.PresentItems( projectItems, diff --git a/src/EditorFeatures/Core/PasteTracking/PasteTrackingService.cs b/src/EditorFeatures/Core/PasteTracking/PasteTrackingService.cs index e4535e569811a..3a3ae3f9b2dd0 100644 --- a/src/EditorFeatures/Core/PasteTracking/PasteTrackingService.cs +++ b/src/EditorFeatures/Core/PasteTracking/PasteTrackingService.cs @@ -6,6 +6,7 @@ using System; using System.Composition; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; @@ -41,7 +42,7 @@ public bool TryGetPastedTextSpan(SourceTextContainer sourceTextContainer, out Te internal void RegisterPastedTextSpan(ITextBuffer textBuffer, TextSpan textSpan) { - Contract.ThrowIfFalse(_threadingContext.HasMainThread); + _threadingContext.ThrowIfNotOnUIThread(); // Use the TextBuffer properties to store the pasted text span. // The `PropertiesCollection` is thread-safe and will be cleared diff --git a/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs b/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs index 74b35d39aa4cf..23459a6ab9693 100644 --- a/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs +++ b/src/EditorFeatures/Core/Preview/AbstractPreviewFactoryService.cs @@ -30,12 +30,11 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Preview { - internal abstract class AbstractPreviewFactoryService : ForegroundThreadAffinitizedObject, IPreviewFactoryService + internal abstract class AbstractPreviewFactoryService : IPreviewFactoryService where TDifferenceViewer : IDifferenceViewer { private const double DefaultZoomLevel = 0.75; private readonly ITextViewRoleSet _previewRoleSet; - private readonly ITextBufferFactoryService _textBufferFactoryService; private readonly IContentTypeRegistryService _contentTypeRegistryService; private readonly IProjectionBufferFactoryService _projectionBufferFactoryService; @@ -44,6 +43,8 @@ internal abstract class AbstractPreviewFactoryService : Foreg private readonly IDifferenceBufferFactoryService _differenceBufferService; private readonly IGlobalOptionService _globalOptions; + protected readonly IThreadingContext ThreadingContext; + [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public AbstractPreviewFactoryService( @@ -56,10 +57,9 @@ public AbstractPreviewFactoryService( IDifferenceBufferFactoryService differenceBufferService, ITextViewRoleSet previewRoleSet, IGlobalOptionService globalOptions) - : base(threadingContext) { - Contract.ThrowIfFalse(ThreadingContext.HasMainThread); - + threadingContext.ThrowIfNotOnUIThread(); + ThreadingContext = threadingContext; _textBufferFactoryService = textBufferFactoryService; _contentTypeRegistryService = contentTypeRegistryService; _projectionBufferFactoryService = projectionBufferFactoryService; diff --git a/src/EditorFeatures/Core/Preview/SolutionPreviewResult.cs b/src/EditorFeatures/Core/Preview/SolutionPreviewResult.cs index 866ed94bb914b..3e66dc9cca86a 100644 --- a/src/EditorFeatures/Core/Preview/SolutionPreviewResult.cs +++ b/src/EditorFeatures/Core/Preview/SolutionPreviewResult.cs @@ -7,13 +7,15 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor { - internal class SolutionPreviewResult : ForegroundThreadAffinitizedObject + internal class SolutionPreviewResult { + private readonly IThreadingContext _threadingContext; private readonly IList _previews; public readonly SolutionChangeSummary? ChangeSummary; @@ -22,9 +24,12 @@ public SolutionPreviewResult(IThreadingContext threadingContext, SolutionPreview { } - public SolutionPreviewResult(IThreadingContext threadingContext, IList? previews, SolutionChangeSummary? changeSummary = null) - : base(threadingContext) + public SolutionPreviewResult( + IThreadingContext threadingContext, + IList? previews, + SolutionChangeSummary? changeSummary = null) { + _threadingContext = threadingContext; _previews = previews ?? SpecializedCollections.EmptyList(); this.ChangeSummary = changeSummary; } @@ -33,7 +38,7 @@ public SolutionPreviewResult(IThreadingContext threadingContext, IList?> GetPreviewsAsync(DocumentId? preferredDocumentId = null, ProjectId? preferredProjectId = null, CancellationToken cancellationToken = default) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); cancellationToken.ThrowIfCancellationRequested(); var orderedPreviews = _previews.OrderBy((i1, i2) => @@ -102,7 +107,7 @@ public SolutionPreviewResult(IThreadingContext threadingContext, IList refactorNotifyServices, ITextUndoHistoryRegistry undoHistoryRegistry, string displayText) - : base(stateMachine.ThreadingContext) { _stateMachine = stateMachine; _snapshotSpan = snapshotSpan; @@ -52,7 +51,7 @@ public RenameTrackingCommitter( public void Commit(CancellationToken cancellationToken) { - AssertIsForeground(); + _stateMachine.ThreadingContext.ThrowIfNotOnUIThread(); var clearTrackingSession = ApplyChangesToWorkspace(cancellationToken); @@ -88,7 +87,7 @@ private async Task RenameSymbolWorkerAsync(Cancellati private bool ApplyChangesToWorkspace(CancellationToken cancellationToken) { - AssertIsForeground(); + _stateMachine.ThreadingContext.ThrowIfNotOnUIThread(); // Now that the necessary work has been done to create the intermediate and final // solutions during PreparePreview, check one more time for cancellation before making all of the @@ -210,7 +209,7 @@ private async Task TryGetSymbolAsync(Solution solutionWithOriginalName, private void UpdateWorkspaceForResetOfTypedIdentifier(Workspace workspace, Solution newSolution, int trackingSessionId) { - AssertIsForeground(); + _stateMachine.ThreadingContext.ThrowIfNotOnUIThread(); // Update document in an ITextUndoTransaction with custom behaviors on undo/redo to // deal with the state machine. @@ -242,7 +241,7 @@ private void UpdateWorkspaceForGlobalIdentifierRename( string newName, int trackingSessionId) { - AssertIsForeground(); + _stateMachine.ThreadingContext.ThrowIfNotOnUIThread(); // Perform rename in a workspace undo action so that undo will revert all // references. It should also be performed in an ITextUndoTransaction to handle diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs index 74a5de8b254c3..e3df47e425b0e 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs @@ -34,8 +34,10 @@ internal sealed partial class RenameTrackingTaggerProvider /// Keeps track of the rename tracking state for a given text buffer by tracking its /// changes over time. /// - private sealed class StateMachine : ForegroundThreadAffinitizedObject + private sealed class StateMachine { + public readonly IThreadingContext ThreadingContext; + private readonly IInlineRenameService _inlineRenameService; private readonly IAsynchronousOperationListener _asyncListener; private readonly ITextBuffer _buffer; @@ -62,8 +64,8 @@ public StateMachine( IDiagnosticAnalyzerService diagnosticAnalyzerService, IGlobalOptionService globalOptions, IAsynchronousOperationListener asyncListener) - : base(threadingContext) { + ThreadingContext = threadingContext; _buffer = buffer; _buffer.Changed += Buffer_Changed; _inlineRenameService = inlineRenameService; @@ -74,7 +76,7 @@ public StateMachine( private void Buffer_Changed(object sender, TextContentChangedEventArgs e) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!GlobalOptions.GetOption(InternalFeatureOnOffOptions.RenameTracking)) { @@ -129,7 +131,7 @@ private void Buffer_Changed(object sender, TextContentChangedEventArgs e) public void UpdateTrackingSessionIfRenamable() { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (this.TrackingSession.IsDefinitelyRenamableIdentifier()) { this.TrackingSession.CheckNewIdentifier(this, _buffer.CurrentSnapshot); @@ -139,7 +141,7 @@ public void UpdateTrackingSessionIfRenamable() private bool ShouldClearTrackingSession(ITextChange change) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (!TryGetSyntaxFactsService(out var syntaxFactsService)) { return true; @@ -159,7 +161,7 @@ private bool ShouldClearTrackingSession(ITextChange change) private void StartTrackingSession(TextContentChangedEventArgs eventArgs) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); ClearTrackingSession(); if (_inlineRenameService.ActiveSession != null) @@ -204,7 +206,7 @@ private static bool IsTrackableCharacter(ISyntaxFactsService syntaxFactsService, public bool ClearTrackingSession() { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (this.TrackingSession != null) { @@ -228,7 +230,7 @@ public bool ClearTrackingSession() public bool ClearVisibleTrackingSession() { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (this.TrackingSession != null && this.TrackingSession.IsDefinitelyRenamableIdentifier()) { @@ -259,7 +261,7 @@ public bool ClearVisibleTrackingSession() internal int StoreCurrentTrackingSessionAndGenerateId() { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); var existingIndex = _committedSessions.IndexOf(TrackingSession); if (existingIndex >= 0) @@ -329,7 +331,7 @@ public bool CanInvokeRename( public void RestoreTrackingSession(int trackingSessionId) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); ClearTrackingSession(); this.TrackingSession = _committedSessions[trackingSessionId]; @@ -338,7 +340,7 @@ public void RestoreTrackingSession(int trackingSessionId) public void OnTrackingSessionUpdated(TrackingSession trackingSession) { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); if (this.TrackingSession == trackingSession) { @@ -376,13 +378,13 @@ private bool TryGetLanguageHeuristicsService(out IRenameTrackingLanguageHeuristi public void Connect() { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); _refCount++; } public void Disconnect() { - AssertIsForeground(); + ThreadingContext.ThrowIfNotOnUIThread(); _refCount--; Contract.ThrowIfFalse(_refCount >= 0); diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs index 8a5d66a243dcf..0fcfd77ae9f4d 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.LanguageServices; @@ -33,12 +34,13 @@ internal enum TriggerIdentifierKind /// /// Determines whether the original token was a renameable identifier on a background thread /// - private class TrackingSession : ForegroundThreadAffinitizedObject + private class TrackingSession { private static readonly Task s_notRenamableTask = Task.FromResult(TriggerIdentifierKind.NotRenamable); private readonly Task _isRenamableIdentifierTask; private readonly CancellationTokenSource _cancellationTokenSource; private readonly CancellationToken _cancellationToken; + private readonly IThreadingContext _threadingContext; private readonly IAsynchronousOperationListener _asyncListener; private Task _newIdentifierBindsTask = SpecializedTasks.False; @@ -52,11 +54,12 @@ private class TrackingSession : ForegroundThreadAffinitizedObject private bool _forceRenameOverloads; public bool ForceRenameOverloads => _forceRenameOverloads; - public TrackingSession(StateMachine stateMachine, SnapshotSpan snapshotSpan, IAsynchronousOperationListener asyncListener) - : base(stateMachine.ThreadingContext) + public TrackingSession( + StateMachine stateMachine, + SnapshotSpan snapshotSpan, + IAsynchronousOperationListener asyncListener) { - AssertIsForeground(); - + _threadingContext = stateMachine.ThreadingContext; _asyncListener = asyncListener; _trackingSpan = snapshotSpan.Snapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeInclusive); _cancellationTokenSource = new CancellationTokenSource(); @@ -80,7 +83,7 @@ public TrackingSession(StateMachine stateMachine, SnapshotSpan snapshotSpan, IAs _isRenamableIdentifierTask.SafeContinueWithFromAsync( async t => { - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, _cancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, _cancellationToken); stateMachine.UpdateTrackingSessionIfRenamable(); }, @@ -107,7 +110,7 @@ private void QueueUpdateToStateMachine(StateMachine stateMachine, Task task) task.SafeContinueWithFromAsync(async t => { - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, _cancellationToken); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, _cancellationToken); if (_isRenamableIdentifierTask.Result != TriggerIdentifierKind.NotRenamable) { @@ -121,7 +124,7 @@ private void QueueUpdateToStateMachine(StateMachine stateMachine, Task task) internal void CheckNewIdentifier(StateMachine stateMachine, ITextSnapshot snapshot) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); _newIdentifierBindsTask = _isRenamableIdentifierTask.SafeContinueWithFromAsync( async t => t.Result != TriggerIdentifierKind.NotRenamable && @@ -144,13 +147,13 @@ internal bool IsDefinitelyRenamableIdentifier() public void Cancel() { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); _cancellationTokenSource.Cancel(); } private async Task DetermineIfRenamableIdentifierAsync(SnapshotSpan snapshotSpan, bool initialCheck) { - AssertIsBackground(); + _threadingContext.ThrowIfNotOnBackgroundThread(); var document = snapshotSpan.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document != null) { diff --git a/src/EditorFeatures/Core/Shared/Extensions/IThreadingContextExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/IThreadingContextExtensions.cs index e4274bda0b020..4496213ef62d3 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/IThreadingContextExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/IThreadingContextExtensions.cs @@ -11,5 +11,8 @@ internal static class IThreadingContextExtensions { public static void ThrowIfNotOnUIThread(this IThreadingContext threadingContext) => Contract.ThrowIfFalse(threadingContext.JoinableTaskContext.IsOnMainThread); + + public static void ThrowIfNotOnBackgroundThread(this IThreadingContext threadingContext) + => Contract.ThrowIfTrue(threadingContext.JoinableTaskContext.IsOnMainThread); } } diff --git a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.ViewSpanChangedEventSource.cs b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.ViewSpanChangedEventSource.cs index f5dea7172bb61..3d4761f8a679d 100644 --- a/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.ViewSpanChangedEventSource.cs +++ b/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.ViewSpanChangedEventSource.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Tagging; using Microsoft.VisualStudio.Text; @@ -15,8 +16,7 @@ internal partial class TaggerEventSources { private class ViewSpanChangedEventSource : AbstractTaggerEventSource { - private readonly ForegroundThreadAffinitizedObject _foregroundObject; - + private readonly IThreadingContext _threadingContext; private readonly ITextView _textView; private Span? _span; @@ -24,25 +24,25 @@ private class ViewSpanChangedEventSource : AbstractTaggerEventSource public ViewSpanChangedEventSource(IThreadingContext threadingContext, ITextView textView) { Debug.Assert(textView != null); - _foregroundObject = new ForegroundThreadAffinitizedObject(threadingContext); + _threadingContext = threadingContext; _textView = textView; } public override void Connect() { - _foregroundObject.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); _textView.LayoutChanged += OnLayoutChanged; } public override void Disconnect() { - _foregroundObject.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); _textView.LayoutChanged -= OnLayoutChanged; } private void OnLayoutChanged(object? sender, TextViewLayoutChangedEventArgs e) { - _foregroundObject.AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); // The formatted span refers to the span of the textview's buffer that is visible. // If it changes, then we want to reclassify. Note: the span might not change if // text were overwritten. However, in the case of text-edits, we'll hear about diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource.cs index c54c62c0ebc55..f62bc329fdfbf 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Tagging; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Options; @@ -39,7 +40,7 @@ internal partial class AbstractAsynchronousTaggerProvider /// and s. Special cases, like reference highlighting (which processes multiple /// subject buffers at once) have their own providers and tag source derivations. /// - private sealed partial class TagSource : ForegroundThreadAffinitizedObject + private sealed partial class TagSource { /// /// If we get more than this many differences, then we just issue it as a single change @@ -145,9 +146,8 @@ public TagSource( ITextBufferVisibilityTracker? visibilityTracker, AbstractAsynchronousTaggerProvider dataSource, IAsynchronousOperationListener asyncListener) - : base(dataSource.ThreadingContext) { - this.AssertIsForeground(); + dataSource.ThreadingContext.ThrowIfNotOnUIThread(); if (dataSource.SpanTrackingMode == SpanTrackingMode.Custom) throw new ArgumentException("SpanTrackingMode.Custom not allowed.", "spanTrackingMode"); @@ -197,7 +197,7 @@ public TagSource( _eventSource = CreateEventSource(); _onVisibilityChanged = () => { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); // any time visibility changes, resume tagging on all taggers. Any non-visible taggers will pause // themselves immediately afterwards. @@ -216,7 +216,7 @@ public TagSource( // Represented as a local function just so we can keep this in sync with Dispose.Disconnect below. void Connect() { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); // Register to hear about visibility changes so we can pause/resume this tagger. _visibilityTracker?.RegisterForVisibilityChanges(subjectBuffer, _onVisibilityChanged); @@ -257,7 +257,7 @@ private void Dispose() // Keep in sync with TagSource.Connect above (just performing the disconnect operations in the reverse order void Disconnect() { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); // Tell the interaction object to stop issuing events. _eventSource.Disconnect(); @@ -279,14 +279,14 @@ void Disconnect() private void Pause() { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); _paused = true; _eventSource.Pause(); } private void Resume() { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); // if we're not actually paused, no need to do anything. if (_paused) { @@ -321,13 +321,13 @@ private TextChangeRange? AccumulatedTextChanges { get { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); return _accumulatedTextChanges_doNotAccessDirectly; } set { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); _accumulatedTextChanges_doNotAccessDirectly = value; } } @@ -336,13 +336,13 @@ private ImmutableDictionary> CachedTagTre { get { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); return _cachedTagTrees_doNotAccessDirectly; } set { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); _cachedTagTrees_doNotAccessDirectly = value; } } @@ -351,20 +351,20 @@ private object? State { get { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); return _state_doNotAccessDirecty; } set { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); _state_doNotAccessDirecty = value; } } private void RaiseTagsChanged(ITextBuffer buffer, DiffResult difference) { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); if (difference.Count == 0) { // nothing changed. diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs index a90f9d9c66613..8cc29a29c32ce 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs @@ -29,7 +29,7 @@ private partial class TagSource { private void OnCaretPositionChanged(object? _, CaretPositionChangedEventArgs e) { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); Debug.Assert(_dataSource.CaretChangeBehavior.HasFlag(TaggerCaretChangeBehavior.RemoveAllTagsOnCaretMoveOutsideOfTag)); @@ -50,7 +50,7 @@ private void OnCaretPositionChanged(object? _, CaretPositionChangedEventArgs e) private void RemoveAllTags() { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); var oldTagTrees = this.CachedTagTrees; this.CachedTagTrees = ImmutableDictionary>.Empty; @@ -64,14 +64,14 @@ private void RemoveAllTags() private void OnSubjectBufferChanged(object? _, TextContentChangedEventArgs e) { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); UpdateTagsForTextChange(e); AccumulateTextChanges(e); } private void AccumulateTextChanges(TextContentChangedEventArgs contentChanged) { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); var contentChanges = contentChanged.Changes; var count = contentChanges.Count; @@ -106,7 +106,7 @@ private void AccumulateTextChanges(TextContentChangedEventArgs contentChanged) private void UpdateTagsForTextChange(TextContentChangedEventArgs e) { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); if (_dataSource.TextChangeBehavior.HasFlag(TaggerTextChangeBehavior.RemoveAllTags)) { @@ -174,7 +174,7 @@ private void EnqueueWork(bool initialTags) private async ValueTask ProcessEventChangeAsync(ImmutableArray changes, CancellationToken cancellationToken) { - await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await _dataSource.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); // no point preceding if we're already disposed. We check this on the UI thread so that we will know // about any prior disposal on the UI thread. @@ -206,7 +206,7 @@ await _visibilityTracker.DelayWhileNonVisibleAsync( await _dataSource.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); if (cancellationToken.IsCancellationRequested) return; @@ -241,7 +241,7 @@ await _visibilityTracker.DelayWhileNonVisibleAsync( var bufferToChanges = ProcessNewTagTrees(spansToTag, oldTagTrees, newTagTrees, cancellationToken); // Then switch back to the UI thread to update our state and kick off the work to notify the editor. - await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await _dataSource.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); // Once we assign our state, we're uncancellable. We must report the changed information // to the editor. The only case where it's ok not to is if the tagger itself is disposed. @@ -261,7 +261,7 @@ await _visibilityTracker.DelayWhileNonVisibleAsync( private ImmutableArray GetSpansAndDocumentsToTag() { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); // TODO: Update to tag spans from all related documents. @@ -519,7 +519,7 @@ private static DiffResult ComputeDifference( /// private TagSpanIntervalTree? TryGetTagIntervalTreeForBuffer(ITextBuffer buffer) { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); // If we've been disposed, no need to proceed. if (_disposalTokenSource.Token.IsCancellationRequested) @@ -534,7 +534,7 @@ private static DiffResult ComputeDifference( _dataSource.ComputeInitialTagsSynchronously(buffer) && !this.CachedTagTrees.TryGetValue(buffer, out _)) { - this.ThreadingContext.JoinableTaskFactory.Run(() => + _dataSource.ThreadingContext.JoinableTaskFactory.Run(() => this.RecomputeTagsAsync(initialTags: true, _disposalTokenSource.Token)); } @@ -547,7 +547,7 @@ private static DiffResult ComputeDifference( public IEnumerable> GetTags(NormalizedSnapshotSpanCollection requestedSpans) { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); if (requestedSpans.Count == 0) return SpecializedCollections.EmptyEnumerable>(); diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_TagsChanged.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_TagsChanged.cs index a7cb189fe08ba..9daa6af00c6b4 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_TagsChanged.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_TagsChanged.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; using Roslyn.Utilities; @@ -23,7 +24,7 @@ private partial class TagSource private void OnTagsChangedForBuffer( ICollection> changes, bool initialTags) { - this.AssertIsForeground(); + _dataSource.ThreadingContext.ThrowIfNotOnUIThread(); foreach (var change in changes) { diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs index 23171ce95e1a5..6fad7682db16e 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.cs @@ -27,11 +27,12 @@ namespace Microsoft.CodeAnalysis.Editor.Tagging /// /// Base type of all asynchronous tagger providers ( and ). /// - internal abstract partial class AbstractAsynchronousTaggerProvider : ForegroundThreadAffinitizedObject where TTag : ITag + internal abstract partial class AbstractAsynchronousTaggerProvider where TTag : ITag { private readonly object _uniqueKey = new(); protected readonly IAsynchronousOperationListener AsyncListener; + protected readonly IThreadingContext ThreadingContext; protected readonly IGlobalOptionService GlobalOptions; private readonly ITextBufferVisibilityTracker? _visibilityTracker; @@ -89,8 +90,8 @@ protected AbstractAsynchronousTaggerProvider( IGlobalOptionService globalOptions, ITextBufferVisibilityTracker? visibilityTracker, IAsynchronousOperationListener asyncListener) - : base(threadingContext) { + ThreadingContext = threadingContext; GlobalOptions = globalOptions; AsyncListener = asyncListener; _visibilityTracker = visibilityTracker; diff --git a/src/EditorFeatures/VisualBasic/AutomaticCompletion/VisualBasicBraceCompletionServiceFactory.vb b/src/EditorFeatures/VisualBasic/AutomaticCompletion/VisualBasicBraceCompletionServiceFactory.vb index c99c8769a8a3d..110e4213b2e99 100644 --- a/src/EditorFeatures/VisualBasic/AutomaticCompletion/VisualBasicBraceCompletionServiceFactory.vb +++ b/src/EditorFeatures/VisualBasic/AutomaticCompletion/VisualBasicBraceCompletionServiceFactory.vb @@ -3,9 +3,8 @@ ' See the LICENSE file in the project root for more information. Imports System.Composition -Imports Microsoft.CodeAnalysis.BraceCompletion Imports Microsoft.CodeAnalysis.AutomaticCompletion -Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities +Imports Microsoft.CodeAnalysis.BraceCompletion Imports Microsoft.CodeAnalysis.Host.Mef Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.AutomaticCompletion @@ -16,9 +15,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.AutomaticCompletion Public Sub New( - braceCompletionServices As IEnumerable(Of IBraceCompletionService), - threadingContext As IThreadingContext) - MyBase.New(braceCompletionServices, threadingContext) + braceCompletionServices As IEnumerable(Of IBraceCompletionService)) + MyBase.New(braceCompletionServices) End Sub End Class End Namespace diff --git a/src/EditorFeatures/VisualBasic/GoToDefinition/VisualBasicGoToSymbolService.vb b/src/EditorFeatures/VisualBasic/GoToDefinition/VisualBasicGoToSymbolService.vb index 61fec7b9a0be4..1e02d918ba82d 100644 --- a/src/EditorFeatures/VisualBasic/GoToDefinition/VisualBasicGoToSymbolService.vb +++ b/src/EditorFeatures/VisualBasic/GoToDefinition/VisualBasicGoToSymbolService.vb @@ -3,10 +3,8 @@ ' See the LICENSE file in the project root for more information. Imports System.Composition -Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.GoToDefinition Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.GoToDefinition @@ -15,8 +13,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.GoToDefinition - Public Sub New(threadingContext As IThreadingContext) - MyBase.New(threadingContext) + Public Sub New() End Sub End Class End Namespace diff --git a/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb b/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb index fc3cc823452f7..5972b2c509ae0 100644 --- a/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb +++ b/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb @@ -33,7 +33,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Dim navigationPoint = NavigationPointHelpers.GetNavigationPoint(generatedTree.GetText(text.Encoding), indentSize, generatedNode) ' switch back to ui thread to actually perform the application and navigation - Await Me.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken) + Await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken) Using transaction = New CaretPreservingEditTransaction(VBEditorResources.Generate_Member, textView, _textUndoHistoryRegistry, _editorOperationsFactoryService) newDocument.Project.Solution.Workspace.ApplyDocumentChanges(newDocument, cancellationToken) diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpOptionPageService.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpOptionPageService.cs index fbdeb92ef5387..5a6373f2861f4 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpOptionPageService.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpOptionPageService.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Composition; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.LanguageServices.CSharp.Options.Formatting; @@ -17,24 +16,24 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.LanguageService { [ExportLanguageService(typeof(IOptionPageService), LanguageNames.CSharp), Shared] - internal class CSharpOptionPageService : ForegroundThreadAffinitizedObject, IOptionPageService + internal class CSharpOptionPageService : IOptionPageService { private readonly CSharpPackage _package; + private readonly IThreadingContext _threadingContext; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CSharpOptionPageService(IThreadingContext threadingContext, SVsServiceProvider serviceProvider) - : base(threadingContext) { var shell = (IVsShell)serviceProvider.GetService(typeof(SVsShell)); ErrorHandler.ThrowOnFailure(shell.LoadPackage(Guids.CSharpPackageId, out var package)); _package = (CSharpPackage)package; + _threadingContext = threadingContext; } public void ShowFormattingOptionPage() { - AssertIsForeground(); - + _threadingContext.ThrowIfNotOnUIThread(); _package.ShowOptionPage(typeof(FormattingOptionPage)); } } diff --git a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ClassificationVerifier.cs b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ClassificationVerifier.cs index 2be44c76c8ac3..3cdcc49cacb0f 100644 --- a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ClassificationVerifier.cs +++ b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.ClassificationVerifier.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using System.Windows; using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; @@ -160,7 +161,7 @@ private bool IsClassificationCustomized( ColorableItemInfo colorItem, string classification) { - Contract.ThrowIfFalse(_threadingContext.HasMainThread); + _threadingContext.ThrowIfNotOnUIThread(); Contract.ThrowIfNull(_fontAndColorUtilities); var foregroundColorRef = colorItem.crForeground; diff --git a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.Settings.cs b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.Settings.cs index 6c864f36817bf..5921cade18fb7 100644 --- a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.Settings.cs +++ b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.Settings.cs @@ -8,6 +8,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Shell; @@ -100,7 +101,7 @@ public async Task GetAppliedColorSchemeAsync(CancellationToken private void SetAppliedColorScheme(ColorSchemeName schemeName) { - Contract.ThrowIfFalse(_threadingContext.HasMainThread); + _threadingContext.ThrowIfNotOnUIThread(); // The applied color scheme is stored in the configuration registry with the color theme information because // when the hive gets rebuilt during upgrades, we need to reapply the color scheme information. diff --git a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs index 2177c9e290d3f..020d23f0a7413 100644 --- a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs +++ b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs @@ -11,6 +11,7 @@ using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; @@ -406,7 +407,7 @@ private sealed class StatusBarUpdater : IDisposable public StatusBarUpdater(IVsStatusbar statusBar, IThreadingContext threadingContext, string? projectOrSolutionName, uint totalProjectCount) { - Contract.ThrowIfFalse(threadingContext.HasMainThread); + threadingContext.ThrowIfNotOnUIThread(); _statusBar = statusBar; _threadingContext = threadingContext; _totalProjectCount = totalProjectCount; diff --git a/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs b/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs index 990569f96ef1a..d260cf44ec2fc 100644 --- a/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs +++ b/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs @@ -13,6 +13,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Host; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.Host.Mef; @@ -294,7 +295,7 @@ protected static (Guid, string projectName, string? projectFlavor) GetGuidAndPro private void RemoveExistingInfoBar() { - Contract.ThrowIfFalse(this.ThreadingContext.HasMainThread); + this.ThreadingContext.ThrowIfNotOnUIThread(); var infoBar = _infoBar; _infoBar = null; @@ -307,7 +308,7 @@ private void RemoveExistingInfoBar() private IVsInfoBarHost? GetInfoBarHost() { - Contract.ThrowIfFalse(this.ThreadingContext.HasMainThread); + this.ThreadingContext.ThrowIfNotOnUIThread(); // Guid of the FindRefs window. Defined here: // https://devdiv.visualstudio.com/DevDiv/_git/VS?path=/src/env/ErrorList/Pkg/Guids.cs&version=GBmain&line=24 diff --git a/src/VisualStudio/Core/Def/Implementation/VirtualMemoryNotificationListener.cs b/src/VisualStudio/Core/Def/Implementation/VirtualMemoryNotificationListener.cs index 08814d1bd1c4c..5c201624979bc 100644 --- a/src/VisualStudio/Core/Def/Implementation/VirtualMemoryNotificationListener.cs +++ b/src/VisualStudio/Core/Def/Implementation/VirtualMemoryNotificationListener.cs @@ -26,7 +26,7 @@ namespace Microsoft.VisualStudio.LanguageServices /// Listens to broadcast notifications from the Visual Studio Shell indicating that the application is running /// low on available virtual memory. /// - internal sealed class VirtualMemoryNotificationListener : ForegroundThreadAffinitizedObject, IVsBroadcastMessageEvents + internal sealed class VirtualMemoryNotificationListener : IVsBroadcastMessageEvents { // memory threshold to turn off full solution analysis - 200MB private const long MemoryThreshold = 200 * 1024 * 1024; @@ -41,11 +41,9 @@ internal sealed class VirtualMemoryNotificationListener : ForegroundThreadAffini private bool _infoBarShown; private VirtualMemoryNotificationListener( - IThreadingContext threadingContext, IVsShell shell, IGlobalOptionService globalOptions, VisualStudioWorkspace workspace) - : base(threadingContext, assertIsForeground: true) { _globalOptions = globalOptions; _workspace = workspace; @@ -76,7 +74,7 @@ public static async Task CreateAsync( var shell = (IVsShell?)await serviceProvider.GetServiceAsync(typeof(SVsShell)).ConfigureAwait(true); Assumes.Present(shell); - return new VirtualMemoryNotificationListener(threadingContext, shell, globalOptions, workspace); + return new VirtualMemoryNotificationListener(shell, globalOptions, workspace); } /// diff --git a/src/VisualStudio/Core/Def/Implementation/VsRefactorNotifyService.cs b/src/VisualStudio/Core/Def/Implementation/VsRefactorNotifyService.cs index 416549b48aaa7..cbbf53c12db63 100644 --- a/src/VisualStudio/Core/Def/Implementation/VsRefactorNotifyService.cs +++ b/src/VisualStudio/Core/Def/Implementation/VsRefactorNotifyService.cs @@ -11,6 +11,7 @@ using System.Runtime.InteropServices; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; @@ -21,18 +22,20 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation using Workspace = Microsoft.CodeAnalysis.Workspace; [Export(typeof(IRefactorNotifyService))] - internal sealed class VsRefactorNotifyService : ForegroundThreadAffinitizedObject, IRefactorNotifyService + internal sealed class VsRefactorNotifyService : IRefactorNotifyService { + private readonly IThreadingContext _threadingContext; + [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public VsRefactorNotifyService(IThreadingContext threadingContext) - : base(threadingContext) { + _threadingContext = threadingContext; } public bool TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, ISymbol symbol, string newName, bool throwOnFailure) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); if (TryGetRenameAPIRequiredArguments(workspace, changedDocumentIDs, symbol, out var hierarchyToItemIDsMap, out var rqnames)) { foreach (var hierarchy in hierarchyToItemIDsMap.Keys) @@ -69,7 +72,7 @@ public bool TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable changedDocumentIDs, ISymbol symbol, string newName, bool throwOnFailure) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); if (TryGetRenameAPIRequiredArguments(workspace, changedDocumentIDs, symbol, out var hierarchyToItemIDsMap, out var rqnames)) { foreach (var hierarchy in hierarchyToItemIDsMap.Keys) @@ -110,7 +113,7 @@ private bool TryGetRenameAPIRequiredArguments( out Dictionary> hierarchyToItemIDsMap, out string[] rqnames) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); rqnames = null; if (!TryGetItemIDsAndRQName(workspace, changedDocumentIDs, symbol, out hierarchyToItemIDsMap, out var rqname)) @@ -129,7 +132,7 @@ private bool TryGetItemIDsAndRQName( out Dictionary> hierarchyToItemIDsMap, out string rqname) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); hierarchyToItemIDsMap = null; rqname = null; @@ -172,7 +175,7 @@ private static bool TryGetRenamingRQNameForSymbol(ISymbol symbol, out string rqn private Dictionary> GetHierarchiesAndItemIDsFromDocumentIDs(VisualStudioWorkspace visualStudioWorkspace, IEnumerable changedDocumentIDs) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); var hierarchyToItemIDsMap = new Dictionary>(); diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginTaggerProvider.cs b/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginTaggerProvider.cs index 37802ba1a0c16..32d5933c0e920 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginTaggerProvider.cs +++ b/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginTaggerProvider.cs @@ -74,7 +74,7 @@ protected override ITaggerEventSource CreateEventSource(ITextView? textView, ITe protected override IEnumerable GetSpansToTag(ITextView? textView, ITextBuffer subjectBuffer) { - this.AssertIsForeground(); + this.ThreadingContext.ThrowIfNotOnUIThread(); Contract.ThrowIfNull(textView); var visibleSpan = textView.GetVisibleLinesSpan(subjectBuffer, extraLines: 100); diff --git a/src/VisualStudio/Core/Def/PreviewPane/PreviewPaneService.cs b/src/VisualStudio/Core/Def/PreviewPane/PreviewPaneService.cs index 1b3772454ce1d..b5d6a1250ba7b 100644 --- a/src/VisualStudio/Core/Def/PreviewPane/PreviewPaneService.cs +++ b/src/VisualStudio/Core/Def/PreviewPane/PreviewPaneService.cs @@ -30,14 +30,13 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.PreviewPane { [ExportWorkspaceServiceFactory(typeof(IPreviewPaneService), ServiceLayer.Host), Shared] - internal class PreviewPaneService : ForegroundThreadAffinitizedObject, IPreviewPaneService, IWorkspaceServiceFactory + internal class PreviewPaneService : IPreviewPaneService, IWorkspaceServiceFactory { private readonly IVsUIShell _uiShell; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public PreviewPaneService(IThreadingContext threadingContext, SVsServiceProvider serviceProvider) - : base(threadingContext) + public PreviewPaneService(SVsServiceProvider serviceProvider) { _uiShell = serviceProvider.GetService(typeof(SVsUIShell)) as IVsUIShell; } diff --git a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetInfoService.cs b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetInfoService.cs index ca9f061178dcf..8fe2143c4180d 100644 --- a/src/VisualStudio/Core/Def/Snippets/AbstractSnippetInfoService.cs +++ b/src/VisualStudio/Core/Def/Snippets/AbstractSnippetInfoService.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Snippets; @@ -23,7 +24,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets /// This service is created on the UI thread during package initialization, but it must not /// block the initialization process. /// - internal abstract class AbstractSnippetInfoService : ForegroundThreadAffinitizedObject, ISnippetInfoService, IVsExpansionEvents + internal abstract class AbstractSnippetInfoService : ISnippetInfoService, IVsExpansionEvents { private readonly Guid _languageGuidForSnippets; private IVsExpansionManager? _expansionManager; @@ -48,7 +49,6 @@ public AbstractSnippetInfoService( Shell.IAsyncServiceProvider serviceProvider, Guid languageGuidForSnippets, IAsynchronousOperationListenerProvider listenerProvider) - : base(threadingContext) { _waiter = listenerProvider.GetListener(FeatureAttribute.Snippets); _languageGuidForSnippets = languageGuidForSnippets; @@ -72,7 +72,7 @@ private async Task InitializeAndPopulateSnippetsCacheAsync(Shell.IAsyncServicePr public int OnAfterSnippetsUpdate() { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); if (_expansionManager != null) { @@ -133,7 +133,7 @@ private async Task PopulateSnippetCacheAsync() // The rest of the process requires being on the UI thread, see the explanation on // PopulateSnippetCacheFromExpansionEnumeration for details - await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); PopulateSnippetCacheFromExpansionEnumeration(expansionEnumerator); } @@ -162,7 +162,7 @@ private async Task PopulateSnippetCacheAsync() /// private void PopulateSnippetCacheFromExpansionEnumeration(IVsExpansionEnumeration expansionEnumerator) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); var updatedSnippets = ExtractSnippetInfo(expansionEnumerator); var updatedSnippetShortcuts = GetShortcutsHashFromSnippets(updatedSnippets); @@ -176,7 +176,7 @@ private void PopulateSnippetCacheFromExpansionEnumeration(IVsExpansionEnumeratio private ImmutableArray ExtractSnippetInfo(IVsExpansionEnumeration expansionEnumerator) { - AssertIsForeground(); + _threadingContext.ThrowIfNotOnUIThread(); var snippetListBuilder = ImmutableArray.CreateBuilder(); var snippetInfo = new VsExpansion();