diff --git a/samples/PortSD4AddInToSD5/WorkbenchSingletonIssueProvider.cs b/samples/PortSD4AddInToSD5/WorkbenchSingletonIssueProvider.cs index b1b7fcdd6e..da25ff38e5 100644 --- a/samples/PortSD4AddInToSD5/WorkbenchSingletonIssueProvider.cs +++ b/samples/PortSD4AddInToSD5/WorkbenchSingletonIssueProvider.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Linq; using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp.Refactoring; +using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.SharpDevelop; @@ -102,8 +103,7 @@ namespace PortSD4AddInToSD5 script => { script.Replace(invocationExpression, new IdentifierExpression("SD").Member("MainThread") - .Invoke("InvokeAsync", arg) - .Invoke("FireAndForget")); + .Invoke("InvokeAsyncAndForget", arg)); }); break; } @@ -122,6 +122,22 @@ namespace PortSD4AddInToSD5 }); break; } + case "ICSharpCode.SharpDevelop.IMessageLoop.InvokeAsync": + // We used to recommend SD.MainThread.InvokeAsync(...).FireAndForget(), + // but it's better to use SD.MainThread.InvokeAsyncAndForget(...) + if (invocationExpression.Clone().Invoke("FireAndForget").IsMatch(invocationExpression.Parent.Parent)) { + var ident = invocationExpression.Parent.GetChildByRole(Roles.Identifier); + yield return new CodeIssue( + "Use InvokeAsyncAndForget() instead", + ident.StartLocation, ident.EndLocation, + new CodeAction("Use InvokeAsyncAndForget() instead", + script => { + var newInvocation = (InvocationExpression)invocationExpression.Clone(); + ((MemberReferenceExpression)newInvocation.Target).MemberName = "InvokeAsyncAndForget"; + script.Replace(invocationExpression.Parent.Parent, newInvocation); + })); + } + break; } } } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SearchForIssuesCommand.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SearchForIssuesCommand.cs index 7f80ea6cac..6f97078e09 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SearchForIssuesCommand.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SearchForIssuesCommand.cs @@ -124,6 +124,8 @@ namespace CSharpBinding.Refactoring if (resultForFile != null) { callback(resultForFile); } + } catch (IOException) { + // ignore IO exceptions (e.g. a file is missing) } catch (OperationCanceledException) { throw; } catch (Exception ex) { diff --git a/src/Main/Base/Project/Services/IMessageLoop.cs b/src/Main/Base/Project/Services/IMessageLoop.cs index 168bc7184c..3b2305e719 100644 --- a/src/Main/Base/Project/Services/IMessageLoop.cs +++ b/src/Main/Base/Project/Services/IMessageLoop.cs @@ -18,7 +18,7 @@ namespace ICSharpCode.SharpDevelop public interface IMessageLoop { /// - /// Gets the thread corresponding to this message loop. + /// Gets the thread that runs this message loop. /// Thread Thread { get; } @@ -77,9 +77,12 @@ namespace ICSharpCode.SharpDevelop T InvokeIfRequired(Func callback, DispatcherPriority priority, CancellationToken cancellationToken); /// - /// Invokes the specified callback. + /// Invokes the specified callback on the message loop. /// /// Returns a task that is signalled when the execution of the callback is completed. + /// + /// If the callback method causes an exception; the exception gets stored in the task object. + /// Task InvokeAsync(Action callback); /// Task InvokeAsync(Action callback, DispatcherPriority priority); @@ -93,6 +96,18 @@ namespace ICSharpCode.SharpDevelop /// Task InvokeAsync(Func callback, DispatcherPriority priority, CancellationToken cancellationToken); + /// + /// Invokes the specified callback on the message loop. + /// + /// + /// This method does not wait for the callback complete execution. + /// If this method is used on the main thread; the message loop must be pumped before the callback gets to run. + /// If the callback causes an exception, it is left unhandled. + /// + void InvokeAsyncAndForget(Action callback); + /// + void InvokeAsyncAndForget(Action callback, DispatcherPriority priority); + /// /// Waits , then executed on the message loop thread. /// diff --git a/src/Main/Base/Test/Utils/FakeMessageLoop.cs b/src/Main/Base/Test/Utils/FakeMessageLoop.cs index 604bfb0315..50f9dc3e83 100644 --- a/src/Main/Base/Test/Utils/FakeMessageLoop.cs +++ b/src/Main/Base/Test/Utils/FakeMessageLoop.cs @@ -4,6 +4,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using System.Windows.Threading; namespace ICSharpCode.SharpDevelop { @@ -19,7 +20,7 @@ namespace ICSharpCode.SharpDevelop } } - public System.Windows.Threading.Dispatcher Dispatcher { + public Dispatcher Dispatcher { get { throw new NotImplementedException(); } @@ -55,12 +56,12 @@ namespace ICSharpCode.SharpDevelop callback(); } - public void InvokeIfRequired(Action callback, System.Windows.Threading.DispatcherPriority priority) + public void InvokeIfRequired(Action callback, DispatcherPriority priority) { callback(); } - public void InvokeIfRequired(Action callback, System.Windows.Threading.DispatcherPriority priority, CancellationToken cancellationToken) + public void InvokeIfRequired(Action callback, DispatcherPriority priority, CancellationToken cancellationToken) { callback(); } @@ -70,12 +71,12 @@ namespace ICSharpCode.SharpDevelop return callback(); } - public T InvokeIfRequired(Func callback, System.Windows.Threading.DispatcherPriority priority) + public T InvokeIfRequired(Func callback, DispatcherPriority priority) { return callback(); } - public T InvokeIfRequired(Func callback, System.Windows.Threading.DispatcherPriority priority, CancellationToken cancellationToken) + public T InvokeIfRequired(Func callback, DispatcherPriority priority, CancellationToken cancellationToken) { return callback(); } @@ -85,12 +86,12 @@ namespace ICSharpCode.SharpDevelop throw new NotImplementedException(); } - public Task InvokeAsync(Action callback, System.Windows.Threading.DispatcherPriority priority) + public Task InvokeAsync(Action callback, DispatcherPriority priority) { throw new NotImplementedException(); } - public Task InvokeAsync(Action callback, System.Windows.Threading.DispatcherPriority priority, CancellationToken cancellationToken) + public Task InvokeAsync(Action callback, DispatcherPriority priority, CancellationToken cancellationToken) { throw new NotImplementedException(); } @@ -100,12 +101,22 @@ namespace ICSharpCode.SharpDevelop throw new NotImplementedException(); } - public Task InvokeAsync(Func callback, System.Windows.Threading.DispatcherPriority priority) + public Task InvokeAsync(Func callback, DispatcherPriority priority) { throw new NotImplementedException(); } - public Task InvokeAsync(Func callback, System.Windows.Threading.DispatcherPriority priority, CancellationToken cancellationToken) + public Task InvokeAsync(Func callback, DispatcherPriority priority, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public void InvokeAsyncAndForget(Action callback) + { + throw new NotImplementedException(); + } + + public void InvokeAsyncAndForget(Action callback, DispatcherPriority priority) { throw new NotImplementedException(); } diff --git a/src/Main/SharpDevelop/Parser/LoadSolutionProjects.cs b/src/Main/SharpDevelop/Parser/LoadSolutionProjects.cs index 9b54ca9b93..c58dd808a6 100644 --- a/src/Main/SharpDevelop/Parser/LoadSolutionProjects.cs +++ b/src/Main/SharpDevelop/Parser/LoadSolutionProjects.cs @@ -40,11 +40,10 @@ namespace ICSharpCode.SharpDevelop.Parser void RaiseThreadStarted() { threadRunningTime = Stopwatch.StartNew(); - SD.MainThread.InvokeAsync( - delegate { - IsRunning = true; - Started(this, EventArgs.Empty); - }).FireAndForget(); + SD.MainThread.InvokeAsyncAndForget(delegate { + IsRunning = true; + Started(this, EventArgs.Empty); + }); } void RaiseThreadEnded() diff --git a/src/Main/SharpDevelop/Services/DispatcherMessageLoop.cs b/src/Main/SharpDevelop/Services/DispatcherMessageLoop.cs index 288d0cd292..4073fdeed5 100644 --- a/src/Main/SharpDevelop/Services/DispatcherMessageLoop.cs +++ b/src/Main/SharpDevelop/Services/DispatcherMessageLoop.cs @@ -128,15 +128,25 @@ namespace ICSharpCode.SharpDevelop return dispatcher.InvokeAsync(callback, priority, cancellationToken).Task; } + public void InvokeAsyncAndForget(Action callback) + { + dispatcher.BeginInvoke(callback); + } + + public void InvokeAsyncAndForget(Action callback, DispatcherPriority priority) + { + dispatcher.BeginInvoke(callback, priority); + } + public async void CallLater(TimeSpan delay, Action method) { await Task.Delay(delay).ConfigureAwait(false); - InvokeAsync(method).FireAndForget(); + InvokeAsyncAndForget(method); } IAsyncResult ISynchronizeInvoke.BeginInvoke(Delegate method, object[] args) { - return dispatcher.InvokeAsync(() => method.DynamicInvoke(args)).Task; + return dispatcher.BeginInvoke(method, args).Task; } object ISynchronizeInvoke.EndInvoke(IAsyncResult result) @@ -146,7 +156,7 @@ namespace ICSharpCode.SharpDevelop object ISynchronizeInvoke.Invoke(Delegate method, object[] args) { - return dispatcher.Invoke(() => method.DynamicInvoke(args)); + return dispatcher.Invoke(method, args); } } }