From c003fb02021d3860256b94b8ff4835b356fff862 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Tue, 7 Nov 2023 11:24:07 +1100 Subject: [PATCH] cleanup --- contributing.md | 4 +- src/Consume/Consume.cs | 2 +- .../CallerArgumentExpressionAttribute.cs | 14 ++++ .../CompilerFeatureRequiredAttribute.cs | 3 + .../DisableRuntimeMarshallingAttribute.cs | 2 + ...erpolatedStringHandlerArgumentAttribute.cs | 2 + .../InterpolatedStringHandlerAttribute.cs | 6 +- src/Polyfill/ModuleInitializerAttribute.cs | 2 + .../PolyfillExtensions_IEnumerable.cs | 3 +- src/Polyfill/PolyfillExtensions_Task.cs | 16 ++--- ...lyfillExtensionsTests_CancellationToken.cs | 62 ++++++++++-------- ...ExtensionsTests_CancellationTokenSource.cs | 64 ++++++++++--------- src/Tests/PolyfillExtensionsTests_Process.cs | 16 ++--- 13 files changed, 118 insertions(+), 78 deletions(-) diff --git a/contributing.md b/contributing.md index 24410003..cf958675 100644 --- a/contributing.md +++ b/contributing.md @@ -135,6 +135,7 @@ Example: using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Link = System.ComponentModel.DescriptionAttribute; namespace System.Runtime.CompilerServices; @@ -158,6 +159,7 @@ namespace System.Runtime.CompilerServices; /// The specification for module initializers in the .NET runtime can be found here: /// https://github.com/dotnet/runtime/blob/master/docs/design/specs/Ecma-335-Augments.md#module-initializer /// +[Link("https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.moduleinitializerattribute?view=net-7.0")] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage( @@ -173,7 +175,7 @@ sealed class ModuleInitializerAttribute : #endif ``` -snippet source | anchor +snippet source | anchor diff --git a/src/Consume/Consume.cs b/src/Consume/Consume.cs index 97c4923e..36e60cd7 100644 --- a/src/Consume/Consume.cs +++ b/src/Consume/Consume.cs @@ -142,7 +142,7 @@ void CancellationTokenUnsafeRegister() { var source = new CancellationTokenSource(); var token = source.Token; - token.UnsafeRegister((state) => {}, null); + token.UnsafeRegister(state => {}, null); token.UnsafeRegister((state, token) => {}, null); } diff --git a/src/Polyfill/CallerArgumentExpressionAttribute.cs b/src/Polyfill/CallerArgumentExpressionAttribute.cs index 8fa14804..bf174414 100644 --- a/src/Polyfill/CallerArgumentExpressionAttribute.cs +++ b/src/Polyfill/CallerArgumentExpressionAttribute.cs @@ -4,21 +4,35 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Link = System.ComponentModel.DescriptionAttribute; namespace System.Runtime.CompilerServices; +/// +/// Indicates that a parameter captures the expression passed for another parameter as a string. +/// [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage(AttributeTargets.Parameter)] +[Link("https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callerargumentexpressionattribute")] #if PolyPublic public #endif sealed class CallerArgumentExpressionAttribute : Attribute { + /// + /// Initializes a new instance of the class. + /// + /// + /// The name of the parameter whose expression should be captured as a string. + /// public CallerArgumentExpressionAttribute(string parameterName) => ParameterName = parameterName; + /// + /// Gets the name of the parameter whose expression should be captured as a string. + /// public string ParameterName { get; } } diff --git a/src/Polyfill/CompilerFeatureRequiredAttribute.cs b/src/Polyfill/CompilerFeatureRequiredAttribute.cs index 14478d39..9d39b5fe 100644 --- a/src/Polyfill/CompilerFeatureRequiredAttribute.cs +++ b/src/Polyfill/CompilerFeatureRequiredAttribute.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Link = System.ComponentModel.DescriptionAttribute; namespace System.Runtime.CompilerServices; @@ -16,6 +17,7 @@ namespace System.Runtime.CompilerServices; validOn: AttributeTargets.All, AllowMultiple = true, Inherited = false)] +[Link("https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.compilerfeaturerequiredattribute")] #if PolyPublic public #endif @@ -25,6 +27,7 @@ sealed class CompilerFeatureRequiredAttribute : /// /// Initialize a new instance of /// + /// The name of the required compiler feature. public CompilerFeatureRequiredAttribute(string featureName) => FeatureName = featureName; diff --git a/src/Polyfill/DisableRuntimeMarshallingAttribute.cs b/src/Polyfill/DisableRuntimeMarshallingAttribute.cs index 2b0f80f2..4d611658 100644 --- a/src/Polyfill/DisableRuntimeMarshallingAttribute.cs +++ b/src/Polyfill/DisableRuntimeMarshallingAttribute.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Link = System.ComponentModel.DescriptionAttribute; namespace System.Runtime.CompilerServices; @@ -27,6 +28,7 @@ namespace System.Runtime.CompilerServices; [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage(AttributeTargets.Assembly)] +[Link("https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.disableruntimemarshallingattribute")] #if PolyPublic public #endif diff --git a/src/Polyfill/InterpolatedStringHandlerArgumentAttribute.cs b/src/Polyfill/InterpolatedStringHandlerArgumentAttribute.cs index 1aae1d37..94b5583e 100644 --- a/src/Polyfill/InterpolatedStringHandlerArgumentAttribute.cs +++ b/src/Polyfill/InterpolatedStringHandlerArgumentAttribute.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Link = System.ComponentModel.DescriptionAttribute; namespace System.Runtime.CompilerServices; @@ -13,6 +14,7 @@ namespace System.Runtime.CompilerServices; [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage(AttributeTargets.Parameter)] +[Link("https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.interpolatedstringhandlerargumentattribute")] #if PolyPublic public #endif diff --git a/src/Polyfill/InterpolatedStringHandlerAttribute.cs b/src/Polyfill/InterpolatedStringHandlerAttribute.cs index 19a71f32..4486b5dc 100644 --- a/src/Polyfill/InterpolatedStringHandlerAttribute.cs +++ b/src/Polyfill/InterpolatedStringHandlerAttribute.cs @@ -4,12 +4,16 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Link = System.ComponentModel.DescriptionAttribute; namespace System.Runtime.CompilerServices; using Targets = AttributeTargets; -/// Indicates the attributed type is to be used as an interpolated string handler. +/// +/// Indicates the attributed type is to be used as an interpolated string handler. +/// +[Link("https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.interpolatedstringhandlerargumentattribute")] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage( diff --git a/src/Polyfill/ModuleInitializerAttribute.cs b/src/Polyfill/ModuleInitializerAttribute.cs index 17d50e8b..7889a399 100644 --- a/src/Polyfill/ModuleInitializerAttribute.cs +++ b/src/Polyfill/ModuleInitializerAttribute.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Link = System.ComponentModel.DescriptionAttribute; namespace System.Runtime.CompilerServices; @@ -27,6 +28,7 @@ namespace System.Runtime.CompilerServices; /// The specification for module initializers in the .NET runtime can be found here: /// https://github.com/dotnet/runtime/blob/master/docs/design/specs/Ecma-335-Augments.md#module-initializer /// +[Link("https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.moduleinitializerattribute?view=net-7.0")] [ExcludeFromCodeCoverage] [DebuggerNonUserCode] [AttributeUsage( diff --git a/src/Polyfill/PolyfillExtensions_IEnumerable.cs b/src/Polyfill/PolyfillExtensions_IEnumerable.cs index 938ef0aa..7a650704 100644 --- a/src/Polyfill/PolyfillExtensions_IEnumerable.cs +++ b/src/Polyfill/PolyfillExtensions_IEnumerable.cs @@ -145,7 +145,8 @@ static IEnumerable ChunkIterator(IEnumerable source { // For all but the first chunk, the array will already be correctly sized. // We can just store into it until either it's full or MoveNext returns false. - TSource[] local = array; // avoid bounds checks by using cached local (`array` is lifted to iterator object as a field) + // avoid bounds checks by using cached local (`array` is lifted to iterator object as a field) + TSource[] local = array; for (; (uint)i < (uint)local.Length && e.MoveNext(); i++) { local[i] = e.Current; diff --git a/src/Polyfill/PolyfillExtensions_Task.cs b/src/Polyfill/PolyfillExtensions_Task.cs index 85a9fb2a..55e3b8f2 100644 --- a/src/Polyfill/PolyfillExtensions_Task.cs +++ b/src/Polyfill/PolyfillExtensions_Task.cs @@ -21,15 +21,15 @@ public static async Task WaitAsync( this Task target, TimeSpan timeout) { - var cancellationSource = new CancellationTokenSource(); + var cancelSource = new CancellationTokenSource(); try { - await target.WaitAsync(timeout, cancellationSource.Token); + await target.WaitAsync(timeout, cancelSource.Token); } finally { - cancellationSource.Cancel(); - cancellationSource.Dispose(); + cancelSource.Cancel(); + cancelSource.Dispose(); } } @@ -60,15 +60,15 @@ public static async Task WaitAsync( this Task target, TimeSpan timeout) { - var cancellationSource = new CancellationTokenSource(); + var cancelSource = new CancellationTokenSource(); try { - return await target.WaitAsync(timeout, cancellationSource.Token); + return await target.WaitAsync(timeout, cancelSource.Token); } finally { - cancellationSource.Cancel(); - cancellationSource.Dispose(); + cancelSource.Cancel(); + cancelSource.Dispose(); } } diff --git a/src/Tests/PolyfillExtensionsTests_CancellationToken.cs b/src/Tests/PolyfillExtensionsTests_CancellationToken.cs index d0fc66de..eb329708 100644 --- a/src/Tests/PolyfillExtensionsTests_CancellationToken.cs +++ b/src/Tests/PolyfillExtensionsTests_CancellationToken.cs @@ -6,10 +6,11 @@ public void CancellationToken_Register_Exceptions() CancellationToken token = default; #nullable disable - Assert.Throws(() => token.Register((Action)null, null)); + Assert.Throws(() => token.Register((Action) null, null)); - Assert.Throws(() => token.UnsafeRegister((Action)null, null)); - Assert.Throws(() => token.UnsafeRegister((Action)null, null)); + // ReSharper disable once RedundantCast + Assert.Throws(() => token.UnsafeRegister((Action) null, null)); + Assert.Throws(() => token.UnsafeRegister((Action) null, null)); #nullable enable } @@ -18,52 +19,57 @@ public void CancellationToken_Register_Exceptions() [TestCase(true)] public static void CancellationToken_Register_ExecutionContextFlowsIfExpected(bool callbackWithToken) { - var cts = new CancellationTokenSource(); + var cancelSource = new CancellationTokenSource(); - const int Iters = 5; - int invoked = 0; + const int iterations = 5; + var invoked = 0; - AsyncLocal al = new AsyncLocal(); - for (int i = 1; i <= Iters; i++) + var asyncLocal = new AsyncLocal(); + for (var i = 1; i <= iterations; i++) { - bool flowExecutionContext = i % 2 == 0; + var flowExecutionContext = i % 2 == 0; - al.Value = i; + asyncLocal.Value = i; Action callback = s => { invoked++; - Assert.AreEqual(flowExecutionContext ? (int)s! : 0, al.Value); + Assert.AreEqual(flowExecutionContext ? (int) s! : 0, asyncLocal.Value); }; - CancellationToken ct = cts.Token; + var token = cancelSource.Token; if (flowExecutionContext && callbackWithToken) { - ct.Register((s, t) => - { - Assert.AreEqual(ct, t); - callback(s); - }, i); + token.Register( + (s, t) => + { + Assert.AreEqual(token, t); + callback(s); + }, + i); } else if (flowExecutionContext) { - ct.Register(callback, i); + token.Register(callback, i); } else if (callbackWithToken) { - ct.UnsafeRegister((s, t) => - { - Assert.AreEqual(ct, t); - callback(s); - }, i); + token.UnsafeRegister( + (s, t) => + { + Assert.AreEqual(token, t); + callback(s); + }, + i); } else { - ct.UnsafeRegister(callback, i); + token.UnsafeRegister(callback, i); } } - al.Value = 0; - cts.Cancel(); - Assert.AreEqual(Iters, invoked); + asyncLocal.Value = 0; + + cancelSource.Cancel(); + Assert.AreEqual(iterations, invoked); } -} +} \ No newline at end of file diff --git a/src/Tests/PolyfillExtensionsTests_CancellationTokenSource.cs b/src/Tests/PolyfillExtensionsTests_CancellationTokenSource.cs index ffc04e73..9230051e 100644 --- a/src/Tests/PolyfillExtensionsTests_CancellationTokenSource.cs +++ b/src/Tests/PolyfillExtensionsTests_CancellationTokenSource.cs @@ -13,57 +13,63 @@ private static bool IsCompletedSuccessfully(Task task) [Ignore("This test is taken directly from the .NET repo but we can't match the real CancelAsync logic exactly, so differ slightly and can't pass this test")] public static void CancellationTokenSource_CancelAsync_NoRegistrations_CallbackCompletesImmediately() { - var cts = new CancellationTokenSource(); - Assert.True(IsCompletedSuccessfully(cts.CancelAsync())); - Assert.True(cts.IsCancellationRequested); + var cancelSource = new CancellationTokenSource(); + Assert.True(IsCompletedSuccessfully(cancelSource.CancelAsync())); + Assert.True(cancelSource.IsCancellationRequested); - cts = new CancellationTokenSource(); - cts.Token.Register(() => { }).Dispose(); - Assert.True(IsCompletedSuccessfully(cts.CancelAsync())); - Assert.True(cts.IsCancellationRequested); + cancelSource = new(); + cancelSource.Token.Register(() => + { + }).Dispose(); + Assert.True(IsCompletedSuccessfully(cancelSource.CancelAsync())); + Assert.True(cancelSource.IsCancellationRequested); } [Test] public static async Task CancellationTokenSource_CancelAsync_CallbacksInvokedAsynchronously() { - var cts = new CancellationTokenSource(); + var cancelSource = new CancellationTokenSource(); - var mres = new ManualResetEventSlim(); - cts.Token.Register(mres.Wait); + var resetEventSlim = new ManualResetEventSlim(); + cancelSource.Token.Register(resetEventSlim.Wait); - Task t = cts.CancelAsync(); + var t = cancelSource.CancelAsync(); Assert.False(t.IsCompleted); - Assert.True(cts.IsCancellationRequested); + Assert.True(cancelSource.IsCancellationRequested); - Assert.True(IsCompletedSuccessfully(cts.CancelAsync())); // secondary call completes immediately + // secondary call completes immediately + Assert.True(IsCompletedSuccessfully(cancelSource.CancelAsync())); - mres.Set(); + resetEventSlim.Set(); await t; } [Test] public static void CancellationTokenSource_CancelAsync_AllCallbacksInvoked() { - const int Iters = 1000; + const int iterations = 1000; - int sum = 0; - int callingThreadId = Environment.CurrentManagedThreadId; + var sum = 0; - var cts = new CancellationTokenSource(); - for (int i = 1; i <= Iters; i++) + var cancelSource = new CancellationTokenSource(); + for (var i = 1; i <= iterations; i++) { - cts.Token.Register(s => - { - sum += (int)s!; - }, i); + cancelSource.Token.Register( + s => + { + sum += (int) s!; + }, + i); } - Task t = cts.CancelAsync(); - Assert.True(cts.IsCancellationRequested); + var t = cancelSource.CancelAsync(); + Assert.True(cancelSource.IsCancellationRequested); - ((IAsyncResult)t).AsyncWaitHandle.WaitOne(); // synchronously block without inlining to ensure this thread isn't reused - t.Wait(); // propagate any exceptions + // synchronously block without inlining to ensure this thread isn't reused + ((IAsyncResult) t).AsyncWaitHandle.WaitOne(); + // propagate any exceptions + t.Wait(cancelSource.Token); - Assert.AreEqual(Iters * (Iters + 1) / 2, sum); + Assert.AreEqual(iterations * (iterations + 1) / 2, sum); } -} +} \ No newline at end of file diff --git a/src/Tests/PolyfillExtensionsTests_Process.cs b/src/Tests/PolyfillExtensionsTests_Process.cs index 9410fd6f..a901d870 100644 --- a/src/Tests/PolyfillExtensionsTests_Process.cs +++ b/src/Tests/PolyfillExtensionsTests_Process.cs @@ -5,17 +5,15 @@ partial class PolyfillExtensionsTests [TestCase(10)] // real timeout public void Process_CurrentProcess_WaitAsyncNeverCompletes(int milliseconds) { - using (var cts = new CancellationTokenSource(milliseconds)) - { - CancellationToken token = cts.Token; - Process process = Process.GetCurrentProcess(); + using var cancelSource = new CancellationTokenSource(milliseconds); + var token = cancelSource.Token; + var process = Process.GetCurrentProcess(); - OperationCanceledException? ex = Assert.CatchAsync(async () => await process.WaitForExitAsync(token)) as OperationCanceledException; + var ex = Assert.CatchAsync(() => process.WaitForExitAsync(token)) as OperationCanceledException; - Assert.IsNotNull(ex); - Assert.AreEqual(token, ex!.CancellationToken); - Assert.False(process.HasExited); - } + Assert.IsNotNull(ex); + Assert.AreEqual(token, ex!.CancellationToken); + Assert.False(process.HasExited); } [Test, RequiresThread]