From 8e3a5c2324ee09cbc2e5edcb67a818657e52c48b Mon Sep 17 00:00:00 2001
From: Glenn Watson <5834289+glennawatson@users.noreply.github.com>
Date: Sat, 25 Jul 2026 16:41:41 +1000
Subject: [PATCH 1/8] chore: update roslyn common analyzers
---
.editorconfig | 271 ++++++++++++++++++++++++-----------
src/Directory.Packages.props | 2 +-
2 files changed, 192 insertions(+), 81 deletions(-)
diff --git a/.editorconfig b/.editorconfig
index 6428c8c..730fb50 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -723,122 +723,60 @@ dotnet_diagnostic.SYSLIB1104.severity = error # Configuration binding source gen
# Bug catchers — always error.
dotnet_diagnostic.IDE0035.severity = none # Remove unreachable code — covered by SST1453
dotnet_diagnostic.IDE0043.severity = none # Format string contains invalid placeholder — covered by SST1454
-dotnet_diagnostic.IDE0051.severity = none # Remove unused private member — covered by SST1440
dotnet_diagnostic.IDE0052.severity = none # Remove unread private member — covered by SST1441
-dotnet_diagnostic.IDE0076.severity = none # Remove invalid global SuppressMessage attribute — covered by SST1457
-dotnet_diagnostic.IDE0077.severity = none # Avoid legacy format target in global SuppressMessage attribute — covered by SST1458
-dotnet_diagnostic.IDE0080.severity = none # Remove unnecessary suppression operator — covered by SST2209
# Simplification / cleanup.
-dotnet_diagnostic.IDE0001.severity = none # Simplify name — covered by SST1116
dotnet_diagnostic.IDE0002.severity = none # Simplify member access — covered by SST1117
dotnet_diagnostic.IDE0004.severity = none # Remove unnecessary cast — covered by SST1175
-dotnet_diagnostic.IDE0005.severity = none # Covered by SST1445 (canonical)
dotnet_diagnostic.IDE0016.severity = none # Use throw expression — covered by SST2207
-dotnet_diagnostic.IDE0017.severity = none # Use object initializers — covered by SST1193
-dotnet_diagnostic.IDE0018.severity = none # Inline variable declaration — covered by SST2208
-dotnet_diagnostic.IDE0019.severity = none # Use pattern matching to avoid 'as' followed by a 'null' check — covered by SST2005
-dotnet_diagnostic.IDE0020.severity = none # Use pattern matching to avoid 'is' check followed by a cast — covered by SST2007
+dotnet_diagnostic.IDE0019.severity = none # Use pattern matching to avoid 'as' followed by a 'null' check — covered by SST2005/SST2274
dotnet_diagnostic.IDE0028.severity = none # Use collection initializers — covered by SST1194
-dotnet_diagnostic.IDE0029.severity = none # Use coalesce expression — covered by SST1195
-dotnet_diagnostic.IDE0030.severity = none # Use coalesce expression (nullable types) — covered by SST1195/SST2227
dotnet_diagnostic.IDE0031.severity = none # Use null propagation — covered by SST1196
-dotnet_diagnostic.IDE0032.severity = none # Use auto property — covered by SST1420
-dotnet_diagnostic.IDE0033.severity = none # Use explicitly provided tuple name — covered by SST1142
-dotnet_diagnostic.IDE0034.severity = none # Simplify default expression — covered by SST1188
-dotnet_diagnostic.IDE0037.severity = none # Use inferred member name — covered by SST1173/SST2216
dotnet_diagnostic.IDE0038.severity = none # Use pattern matching ('is' check without a cast) — covered by SST2007
-dotnet_diagnostic.IDE0041.severity = none # Use 'is null' check — covered by SST1149/SST2231
+dotnet_diagnostic.IDE0041.severity = none # Use 'is null' check — covered by SST1149/SST2231/SST2282
dotnet_diagnostic.IDE0042.severity = none # Deconstruct variable declaration — covered by SST2214
dotnet_diagnostic.IDE0044.severity = none # Add readonly modifier — covered by SST1424
-dotnet_diagnostic.IDE0046.severity = none # Use conditional expression for return — covered by SST1197
dotnet_diagnostic.IDE0047.severity = none # Remove unnecessary parentheses — covered by SST1459
dotnet_diagnostic.IDE0049.severity = none # Use language keywords instead of framework type names for type references — covered by SST1121
-dotnet_diagnostic.IDE0054.severity = none # Use compound assignment — covered by SST1185
-dotnet_diagnostic.IDE0056.severity = none # Use index operator — covered by SST2203
dotnet_diagnostic.IDE0057.severity = none # Use range operator — covered by SST2204
dotnet_diagnostic.IDE0059.severity = none # Remove unnecessary value assignment — covered by SST2222
-dotnet_diagnostic.IDE0062.severity = none # Make local function static — covered by SST2235
-dotnet_diagnostic.IDE0063.severity = none # Use simple 'using' statement — covered by SST2236
dotnet_diagnostic.IDE0064.severity = none # Make struct fields writable — flag readonly-but-mutable struct fields where intent diverges from declaration
dotnet_diagnostic.IDE0066.severity = none # Use switch expression — covered by SST2201
-dotnet_diagnostic.IDE0070.severity = none # Use 'System.HashCode.Combine' — covered by SST2217
-dotnet_diagnostic.IDE0071.severity = none # Simplify interpolation — covered by SST2220
-dotnet_diagnostic.IDE0072.severity = none # Add missing cases to switch expression — covered by SST2206
-dotnet_diagnostic.IDE0074.severity = none # Use compound assignment — covered by SST1185
dotnet_diagnostic.IDE0075.severity = none # Simplify conditional expression — covered by SST1182
dotnet_diagnostic.IDE0078.severity = none # Use pattern matching — covered by SST2006/SST2231
-dotnet_diagnostic.IDE0082.severity = none # Convert typeof to nameof — covered by SST1199
-dotnet_diagnostic.IDE0083.severity = none # Use pattern matching ('not' operator) — covered by SST2006
dotnet_diagnostic.IDE0084.severity = none # Use pattern matching ('IsNot' operator)
-dotnet_diagnostic.IDE0090.severity = none # Simplify 'new' expression — covered by SST2202
-dotnet_diagnostic.IDE0100.severity = none # Remove unnecessary equality operator — covered by SST1143
-dotnet_diagnostic.IDE0110.severity = none # Remove unnecessary discard — covered by SST2213
dotnet_diagnostic.IDE0120.severity = none # Simplify LINQ expression — covered by PSH1100/PSH1101
-dotnet_diagnostic.IDE0150.severity = none # Prefer 'null' check over type check — covered by SST2231
-dotnet_diagnostic.IDE0161.severity = none # Use file-scoped namespace declaration — covered by SST2237
-dotnet_diagnostic.IDE0170.severity = none # Simplify property pattern — covered by SST2238
-dotnet_diagnostic.IDE0180.severity = none # Use tuple to swap values — covered by SST2215
-dotnet_diagnostic.IDE0200.severity = none # Remove unnecessary lambda expression — covered by SST2239
-dotnet_diagnostic.IDE0220.severity = none # Add explicit cast in foreach loop — covered by SST2225
dotnet_diagnostic.IDE0221.severity = none # Add explicit cast — covered by SST2226
-dotnet_diagnostic.IDE0240.severity = none # Remove redundant nullable directive — covered by SST2210
-dotnet_diagnostic.IDE0241.severity = none # Remove unnecessary nullable directive — covered by SST2211
dotnet_diagnostic.IDE0250.severity = none # Make struct 'readonly' — covered by PSH1014
-dotnet_diagnostic.IDE0251.severity = none # Make member 'readonly' — covered by SST1460
dotnet_diagnostic.IDE0260.severity = none # Use pattern matching — covered by SST2006/SST2231
-dotnet_diagnostic.IDE0270.severity = none # Use coalesce expression — covered by SST2227
# Disabled — conflict with an existing SA/CA rule or project convention.
-dotnet_diagnostic.IDE0003.severity = none # Remove 'this' qualifier — we don't follow the this. prefix style (SA1101 = none)
dotnet_diagnostic.IDE0007.severity = none # Use var — we don't force var in either direction
dotnet_diagnostic.IDE0008.severity = none # Use explicit type — we don't force var in either direction
dotnet_diagnostic.IDE0009.severity = none # Member access should be qualified — SA1101 = none
-dotnet_diagnostic.IDE0010.severity = none # Add missing cases to switch statement — too noisy for default/fallthrough patterns
-dotnet_diagnostic.IDE0011.severity = none # Add braces — RCS1001 / RCS1007 already handle this
-dotnet_diagnostic.IDE0021.severity = none # Use expression body for constructors — preference not enforced
-dotnet_diagnostic.IDE0022.severity = none # Use expression body for methods — preference not enforced
-dotnet_diagnostic.IDE0023.severity = none # Use expression body for conversion operators — preference not enforced
-dotnet_diagnostic.IDE0024.severity = none # Use expression body for operators — preference not enforced
-dotnet_diagnostic.IDE0025.severity = none # Use expression body for properties — preference not enforced
-dotnet_diagnostic.IDE0026.severity = none # Use expression body for indexers — preference not enforced
-dotnet_diagnostic.IDE0027.severity = none # Use expression body for accessors — preference not enforced
-dotnet_diagnostic.IDE0036.severity = none # Order modifiers — SA1206 handles
-dotnet_diagnostic.IDE0039.severity = none # Use local function — covered by SST2228
-dotnet_diagnostic.IDE0040.severity = none # Add accessibility modifiers — SA1400 handles
-dotnet_diagnostic.IDE0045.severity = none # Use conditional expression for assignment — covered by SST1198
+dotnet_diagnostic.IDE0021.severity = none # Use expression body for constructors — covered by SST2276 (opt-in)
+dotnet_diagnostic.IDE0022.severity = none # Use expression body for methods — covered by SST2275
+dotnet_diagnostic.IDE0023.severity = none # Use expression body for conversion operators — covered by SST2278 (opt-in)
+dotnet_diagnostic.IDE0024.severity = none # Use expression body for operators — covered by SST2277 (opt-in)
+dotnet_diagnostic.IDE0025.severity = none # Use expression body for properties — covered by SST2279
+dotnet_diagnostic.IDE0026.severity = none # Use expression body for indexers — covered by SST2280
dotnet_diagnostic.IDE0048.severity = none # Add parentheses for clarity — preference not enforced
-dotnet_diagnostic.IDE0053.severity = none # Use expression body for lambdas — preference not enforced
dotnet_diagnostic.IDE0055.severity = none # Formatting — StyleCop SA rules own formatting
dotnet_diagnostic.IDE0058.severity = none # Remove unnecessary expression value — covered by SST2221
dotnet_diagnostic.IDE0060.severity = none # Remove unused parameter — CA1801 handles (with api_surface config)
-dotnet_diagnostic.IDE0061.severity = none # Use expression body for local function — preference not enforced
-dotnet_diagnostic.IDE0065.severity = none # 'using' directive placement — SA1200 = none (we put usings outside file-scoped namespaces)
-dotnet_diagnostic.IDE0073.severity = none # Require file header — SA1633 handles
+dotnet_diagnostic.IDE0061.severity = none # Use expression body for local function — covered by SST2281
dotnet_diagnostic.IDE0079.severity = none # Remove unnecessary suppression — can misfire on multi-TFM suppressions
dotnet_diagnostic.IDE0130.severity = none # Namespace does not match folder structure — we don't enforce strict mirror
dotnet_diagnostic.IDE0160.severity = none # Use block-scoped namespace — we use file-scoped (IDE0161)
dotnet_diagnostic.IDE0210.severity = none # Convert to top-level statements — we use Main style
dotnet_diagnostic.IDE0211.severity = none # Convert to 'Program.Main' style — we use Main style
-dotnet_diagnostic.IDE0280.severity = none # Use nameof — CA1507 / RCS1015 handle this
-dotnet_diagnostic.IDE0290.severity = none # Use primary constructor — subjective, not enforced
dotnet_diagnostic.IDE0300.severity = none # Use collection expression for array — covered by SST2101
-dotnet_diagnostic.IDE0301.severity = none # Use collection expression for empty — covered by SST2100
-dotnet_diagnostic.IDE0302.severity = none # Use collection expression for stackalloc — covered by SST2102
-dotnet_diagnostic.IDE0303.severity = none # Use collection expression for Create — covered by SST2103
-dotnet_diagnostic.IDE0304.severity = none # Use collection expression for builder — covered by SST2104
-dotnet_diagnostic.IDE0305.severity = none # Use collection expression for fluent — covered by SST2105
dotnet_diagnostic.IDE0306.severity = none # Use collection expression for new — covered by SST2101
dotnet_diagnostic.IDE0320.severity = none # Make anonymous function static — covered by PSH1000
dotnet_diagnostic.IDE0050.severity = none # Convert anonymous type to tuple — covered by SST2224
-dotnet_diagnostic.IDE0230.severity = none # Use UTF-8 string literal — covered by SST2212
dotnet_diagnostic.IDE0310.severity = none # Convert lambda expression to method group — handled by RCS1207
-dotnet_diagnostic.IDE0340.severity = none # Use unbound generic type — covered by SST2232
-dotnet_diagnostic.IDE0350.severity = none # Use implicitly typed lambda — covered by SST2218
dotnet_diagnostic.IDE0360.severity = none # Simplify property accessor — covered by SST2219
dotnet_diagnostic.IDE0370.severity = none # Remove unnecessary suppression (null-forgiving operator) — disabled for the same reason as RCS1249: multi-TFM nullability annotations can differ per platform
-dotnet_diagnostic.IDE0380.severity = none # Remove unnecessary unsafe modifier — covered by SST1455
-dotnet_diagnostic.IDE1005.severity = none # Use conditional delegate call — covered by SST2240
###################
# Microsoft .NET Style Rules (IDE1xxx / IDE3xxx) - Naming & Miscellaneous
@@ -1907,6 +1845,7 @@ dotnet_diagnostic.SES1402.severity = error # Do not load an assembly from raw by
dotnet_diagnostic.SES1403.severity = error # JSON deserialization depth limit must stay within a safe ceiling
dotnet_diagnostic.SES1404.severity = error # A type is instantiated by name from a non-constant Activator typeName
dotnet_diagnostic.SES1405.severity = error # MessagePack typeless deserialization reconstructs whatever type the payload names
+dotnet_diagnostic.SES1406.severity = warning # Reflection must not reach non-public members via BindingFlags.NonPublic (opt-in; replaces S3011)
# Web hardening
dotnet_diagnostic.SES1501.severity = error # A CORS policy must not allow credentials together with any origin
@@ -1933,6 +1872,178 @@ dotnet_diagnostic.SES1604.severity = error # Prompt-template input encoding must
dotnet_diagnostic.SES1605.severity = error # AI instrumentation must not enable sensitive-data capture
dotnet_diagnostic.SES1606.severity = error # Do not fetch model weights over cleartext HTTP
+# RoslynCommonAnalyzers rules added to reach 3.37.0 (on-by-default enforced; opt-in left off)
+dotnet_diagnostic.PSH1022.severity = error # A parameterless `new EventArgs()` allocates where the shared `EventArgs.Empty` singleton would serve. Code fix uses the singleton.
+dotnet_diagnostic.PSH1114.severity = none # Freeze static lookup collections that are never mutated. Opt-in.
+dotnet_diagnostic.PSH1226.severity = error # A string's `ToCharArray()` result is only iterated, allocating a throwaway `char[]`; iterate the string directly. Code fix drops the copy.
+dotnet_diagnostic.PSH1227.severity = error # A cheaper equivalent exists — `string.CompareOrdinal` over `Compare(…, Ordinal)`, `Debug.Fail` over `Debug.Assert(false, …)`. Info. Code fix rewrites the call.
+dotnet_diagnostic.PSH1306.severity = none # Guard one-time execution with an interlocked latch. Opt-in.
+dotnet_diagnostic.PSH1309.severity = none # Register cancellation callbacks without flowing the execution context. Opt-in.
+dotnet_diagnostic.PSH1410.severity = none # Mark trivial forwarders for aggressive inlining. Opt-in.
+dotnet_diagnostic.PSH1420.severity = error # A shareable client held in an instance field of an Azure Functions worker class is rebuilt on every invocation, leaking sockets and connections; share a static/singleton client or inject `IHttpClientFactory`.
+dotnet_diagnostic.PSH1506.severity = error # The HTTP request or response body is read or written synchronously (`ReadToEnd`, `Body.Read`, `Body.Write`), which blocks a thread on Kestrel and buffers the whole payload; use the async overload. Code fix awaits it when the method is already async.
+dotnet_diagnostic.PSH1600.severity = error # A delegate captured per iteration inside a component render loop reallocates on every render (measured ~128 B per row per render) and churns the diff; hoist it to a cached delegate or a precomputed per-item model.
+dotnet_diagnostic.PSH1601.severity = error # A JavaScript-interop call is issued once per loop iteration; on Interactive Server each is a separate SignalR round-trip. Batch into a single call over the collection.
+dotnet_diagnostic.PSH1602.severity = error # `StateHasChanged` is called unconditionally in `OnAfterRender`/`OnAfterRenderAsync`, scheduling another render every time — a runaway loop. Guard it with `firstRender` or a state flag.
+dotnet_diagnostic.PSH1603.severity = error # A non-delegate allocation is used as a component-parameter value inside a render loop, allocating per item and forcing the child to re-render each pass. Sibling of PSH1600.
+dotnet_diagnostic.SES1701.severity = error # Raw HTML is rendered from a non-constant value (`MarkupString`/`AddMarkupContent`), bypassing automatic encoding — an XSS risk. Sanitizer allow-list via `securitysharp.SES1701.sanitizers`.
+dotnet_diagnostic.SES1702.severity = error # A JavaScript-interop call targets a script-evaluation primitive (`eval`, `Function`, `document.write`), turning interop into a script-injection channel.
+dotnet_diagnostic.SES1703.severity = error # `[Authorize]` on a non-routable component enforces nothing — authorization runs as a routing concern. Exempt types via `securitysharp.SES1703.exempt_types`.
+dotnet_diagnostic.SES1704.severity = error # `IHttpContextAccessor` or a cascading `HttpContext` is used in an interactively-rendered component, where it is null or frozen at circuit start.
+dotnet_diagnostic.SES1705.severity = error # `NavigationManager.NavigateTo` is called with a target that is not a verified relative URL — an open-redirect risk. Validator allow-list via `securitysharp.SES1705.validators`.
+dotnet_diagnostic.SES1706.severity = error # An uploaded file is read with an unbounded or client-chosen size limit, letting an attacker fill server memory. Threshold via `securitysharp.SES1706.max_bytes`.
+dotnet_diagnostic.SES1707.severity = error # A secret-shaped literal appears in code reachable as WebAssembly, which downloads to the browser in full — guaranteed disclosure.
+dotnet_diagnostic.SES1708.severity = error # `CircuitOptions.DetailedErrors` is enabled, shipping server exception detail to every connected client.
+dotnet_diagnostic.SES1709.severity = error # `SerializeAllClaims` serializes every claim into client-readable WebAssembly authentication state, exposing internal ids, tokens, and PII.
+dotnet_diagnostic.SES1710.severity = error # Antiforgery validation is disabled on a form (`[RequireAntiforgeryToken(required: false)]`), removing CSRF protection.
+dotnet_diagnostic.SST1101.severity = none # see docs/rules/SST1101.md
+dotnet_diagnostic.SST1220.severity = error # An all-named argument list is in a different order than the parameters. Code fix reorders it to declaration order. Info.
+dotnet_diagnostic.SST1221.severity = error # `where` constraint clauses are not ordered to match the type-parameter list. Code fix reorders them. Info.
+dotnet_diagnostic.SST1321.severity = error # A method whose name ends in `Async` returns nothing awaitable — the inverse of SST1317. Code fix (rename) drops the suffix.
+dotnet_diagnostic.SST1434.severity = error # see docs/rules/SST1434.md
+dotnet_diagnostic.SST1525.severity = error # A multi-statement `switch` section has no braces; the braces-on policy extends to switch sections. Code fix wraps it.
+dotnet_diagnostic.SST1526.severity = none # A wrapped binary expression places the operator inconsistently. Configurable (`before`/`after`, default before). Opt-in.
+dotnet_diagnostic.SST1527.severity = none # The `=>` of an expression-bodied member wraps inconsistently. Configurable. Opt-in.
+dotnet_diagnostic.SST1528.severity = none # The `=` of a wrapped initializer wraps inconsistently. Configurable. Opt-in.
+dotnet_diagnostic.SST1529.severity = none # A wrapped `?.`/`.` call chain places the break inconsistently. Configurable. Opt-in.
+dotnet_diagnostic.SST1530.severity = none # A newline sits between a type declaration and its base list. Code fix pulls the base list onto the declaration line. Opt-in.
+dotnet_diagnostic.SST1531.severity = none # A short object initializer is split across lines. Code fix collapses it when it fits. Opt-in.
+dotnet_diagnostic.SST1532.severity = none # A file mixes line endings. Configurable (`lf`/`crlf`, default lf). Opt-in.
+dotnet_diagnostic.SST1533.severity = none # A source file contains no code. Opt-in.
+dotnet_diagnostic.SST1660.severity = error # The ` ` tags are not in parameter order. Code fix reorders them. Info.
+dotnet_diagnostic.SST1661.severity = error # A snippet uses ``/`` mismatched to single- vs multi-line content. Code fix swaps the tag. Info.
+dotnet_diagnostic.SST1662.severity = none # A thrown exception type has no `` documentation. Code fix adds the skeleton. Opt-in.
+dotnet_diagnostic.SST1663.severity = none # A `//` comment before a public member reads like a summary; use `///`. Code fix converts it. Opt-in.
+dotnet_diagnostic.SST1664.severity = none # A summary separates paragraphs with blank lines instead of ``. Code fix wraps them. Opt-in.
+dotnet_diagnostic.SST1708.severity = error # An extension method never uses its `this` receiver, so it need not be an extension.
+dotnet_diagnostic.SST1709.severity = none # A method in a `*Extensions` class whose first parameter lacks `this`. Code fix converts it to an extension block. Opt-in.
+dotnet_diagnostic.SST1804.severity = error # A positional record has an empty `{ }` body where `;` would do. Code fix rewrites it. Info.
+dotnet_diagnostic.SST1900.severity = error # see docs/rules/SST1900.md
+dotnet_diagnostic.SST2229.severity = error # see docs/rules/SST2229.md
+dotnet_diagnostic.SST2230.severity = error # see docs/rules/SST2230.md
+dotnet_diagnostic.SST2233.severity = none # see docs/rules/SST2233.md
+dotnet_diagnostic.SST2254.severity = none # A target-typed `new()` is written where an explicit type reads more clearly; the code fix restores `new TypeName(...)`. Opt-in — the counterpart to SST2202's target-typed direction, so a team enables at most one.
+dotnet_diagnostic.SST2255.severity = error # A hand-written null-or-empty string test. Code fix uses `string.IsNullOrEmpty`.
+dotnet_diagnostic.SST2256.severity = error # An extension method called in static form. Code fix rewrites to instance form. Info.
+dotnet_diagnostic.SST2257.severity = error # A lambda block body that is a single `return`. Code fix uses an expression body. Info.
+dotnet_diagnostic.SST2258.severity = error # A redundant explicit delegate wrapper (`new EventHandler(M)`). Code fix drops it. Info.
+dotnet_diagnostic.SST2259.severity = error # A stray `;` after a type declaration. Code fix removes it. Info.
+dotnet_diagnostic.SST2260.severity = error # An `as` cast to a type the operand already has. Code fix removes it. Info.
+dotnet_diagnostic.SST2261.severity = error # `(x && !y)
+dotnet_diagnostic.SST2262.severity = error # A raw string literal whose content needs no raw syntax. Code fix demotes it. Info.
+dotnet_diagnostic.SST2263.severity = error # An infinite loop whose body re-derives its stop condition. Code fix hoists the condition into the header. Info.
+dotnet_diagnostic.SST2264.severity = error # A numeric literal cast to an enum. Code fix names the member.
+dotnet_diagnostic.SST2265.severity = none # Consecutive fluent calls on one receiver can fold into a chain. Opt-in.
+dotnet_diagnostic.SST2266.severity = none # A local read exactly once can be inlined into that use. Opt-in.
+dotnet_diagnostic.SST2267.severity = none # Infinite loops written in mixed `while(true)`/`for(;;)` styles. Configurable. Opt-in.
+dotnet_diagnostic.SST2268.severity = none # Inconsistent `()` on object creation with an initializer. Configurable. Opt-in.
+dotnet_diagnostic.SST2269.severity = none # Inconsistent parentheses around a conditional's condition. Configurable. Opt-in.
+dotnet_diagnostic.SST2270.severity = none # Inconsistent explicit-vs-implicit array-creation type. Configurable. Opt-in.
+dotnet_diagnostic.SST2271.severity = none # `var`-vs-explicit local type per the configured preference. Configurable. Opt-in.
+dotnet_diagnostic.SST2272.severity = none # `[Flags]` member values written as mixed decimals and shifts. Configurable. Opt-in.
+dotnet_diagnostic.SST2273.severity = none # A function or loop body wraps its work in a trailing `if` that could be an early-exit guard clause. Code fix inverts it. Configurable threshold. Opt-in.
+dotnet_diagnostic.SST2274.severity = error # A value assigned with `as` and then null-checked is an `is` declaration pattern in one step. Code fix rewrites it.
+dotnet_diagnostic.SST2275.severity = error # A method whose block body is a single statement can use an expression body `=> expr`. Code fix rewrites it.
+dotnet_diagnostic.SST2276.severity = none # A constructor whose block body is a single statement can use an expression body. Code fix rewrites it. Opt-in.
+dotnet_diagnostic.SST2277.severity = none # An operator whose block body is a single `return` can use an expression body. Code fix rewrites it. Opt-in.
+dotnet_diagnostic.SST2278.severity = none # A conversion operator whose block body is a single `return` can use an expression body. Code fix rewrites it. Opt-in.
+dotnet_diagnostic.SST2279.severity = error # A get-only property whose getter is a single `return` can use a whole-member expression body. Code fix rewrites it.
+dotnet_diagnostic.SST2280.severity = error # A get-only indexer whose getter is a single `return` can use a whole-member expression body. Code fix rewrites it.
+dotnet_diagnostic.SST2281.severity = error # A local function whose block body is a single statement can use an expression body. Code fix rewrites it.
+dotnet_diagnostic.SST2282.severity = error # A reference-type `ReferenceEquals` check against `null` reads as an `is null` / `is not null` pattern. Code fix rewrites it.
+dotnet_diagnostic.SST2283.severity = error # A null guard that throws right before assigning the guarded value can fold into the assignment as `?? throw`. Code fix rewrites it.
+dotnet_diagnostic.SST2329.severity = error # A `[Flags]` enum declares no zero-valued member. Code fix adds `None = 0`.
+dotnet_diagnostic.SST2330.severity = error # A `[Flags]` member is a numeric literal equal to a combination of others (`All = 7`). Code fix writes `A
+dotnet_diagnostic.SST2331.severity = none # An enum leaves member values implicit, so their numbers depend on declaration order. Opt-in.
+dotnet_diagnostic.SST2332.severity = error # An auto-property's `private set` is only written during construction; make it get-only.
+dotnet_diagnostic.SST2333.severity = none # A generic comparison/equality contract is implemented without its non-generic counterpart. Opt-in.
+dotnet_diagnostic.SST2334.severity = none # A publicly visible type has no `[DebuggerDisplay]`. Opt-in.
+dotnet_diagnostic.SST2335.severity = none # Parts of a partial type disagree on the `static` modifier. Opt-in.
+dotnet_diagnostic.SST2491.severity = error # A non-`async` method returns an awaitable from inside `using`/`try-finally`/`lock`, so the resource is torn down before the task completes. Code fix makes it `async`.
+dotnet_diagnostic.SST2492.severity = error # A null-guard throws on a parameter the signature declares may be null.
+dotnet_diagnostic.SST2493.severity = error # `== null`/`!= null` on an unconstrained generic `T`. Code fix uses `is null`/`is not null`.
+dotnet_diagnostic.SST2494.severity = error # A `??` whose left operand is a constant null, so the right is always taken. Code fix folds it.
+dotnet_diagnostic.SST2495.severity = error # A `[Flags]` combination includes an operand whose bits another already covers. Code fix removes it.
+dotnet_diagnostic.SST2496.severity = error # An explicit `Dispose`/`Close` on a resource an enclosing `using` already disposes. Code fix removes it. Info.
+dotnet_diagnostic.SST2700.severity = error # An MVC route template contains a backslash; route segments are separated by `/`, so the route is unreachable. Code fix replaces `\` with `/`.
+dotnet_diagnostic.SST2701.severity = error # A `[JSInvokable]` method is not public, so JavaScript interop cannot call it. Code fix makes it public.
+dotnet_diagnostic.SST2702.severity = error # A `[SupplyParameterFromQuery]` property has a type the framework cannot bind from the query string, which throws at runtime.
+dotnet_diagnostic.SST2703.severity = error # A routable component's route constraint (`{id:int}`) disagrees with the matching `[Parameter]` CLR type, so the route silently fails to match.
+dotnet_diagnostic.SST2704.severity = error # A public action on an `[ApiController]` declares no HTTP-verb attribute, so it answers every verb and can make routing ambiguous.
+dotnet_diagnostic.SST2705.severity = none # A bound model member is a non-nullable value type with no required marker, so a request that omits it binds the default with no error. Opt-in.
+dotnet_diagnostic.SST2706.severity = error # A Windows Forms entry point carries neither `[STAThread]` nor `[MTAThread]`; without STA, clipboard, drag-and-drop, and common dialogs misbehave. Code fix adds `[STAThread]`.
+dotnet_diagnostic.SST2707.severity = none # A fire-and-forget `Task.Run` in a controller captures the request's `HttpContext`, which is disposed when the request ends, so the background work throws `ObjectDisposedException`. Opt-in.
+dotnet_diagnostic.SST2708.severity = error # A component subscribes to an event in a lifecycle method but never unsubscribes, so the event source keeps the component alive — a per-session leak on a Server circuit.
+dotnet_diagnostic.SST2709.severity = error # `StateHasChanged` is called while the component is being disposed, which the renderer no longer supports and throws.
+dotnet_diagnostic.SST2710.severity = error # `StateHasChanged` is called directly from a timer callback, off the renderer's dispatcher; marshal it with `InvokeAsync(StateHasChanged)`.
+dotnet_diagnostic.SST2711.severity = error # A synchronous component lifecycle method is overridden as `async void`, which the framework never awaits; override the `…Async` twin returning `Task`. Code fix rewrites the signature.
+dotnet_diagnostic.SST2712.severity = error # An `[Inject]`/`[CascadingParameter]` property has no setter, so the framework's reflection-based binding leaves it null. Code fix adds a setter.
+dotnet_diagnostic.SST2713.severity = error # A `DotNetObjectReference.Create(this)` is passed inline and never stored, so nothing can dispose it and it leaks on the JavaScript side.
+
+# In-box IDE code-style rules disabled where a StyleSharp rule covers the same shape (avoids double-reporting under EnforceCodeStyleInBuild)
+dotnet_diagnostic.IDE0001.severity = none # covered by SST1116
+dotnet_diagnostic.IDE0003.severity = none # covered by SST1117
+dotnet_diagnostic.IDE0005.severity = none # covered by SST1445
+dotnet_diagnostic.IDE0010.severity = none # covered by SST2205
+dotnet_diagnostic.IDE0011.severity = none # covered by SST1503
+dotnet_diagnostic.IDE0017.severity = none # covered by SST1193
+dotnet_diagnostic.IDE0018.severity = none # covered by SST2208
+dotnet_diagnostic.IDE0020.severity = none # covered by SST2007
+dotnet_diagnostic.IDE0027.severity = none # covered by SST2219
+dotnet_diagnostic.IDE0029.severity = none # covered by SST1195
+dotnet_diagnostic.IDE0030.severity = none # covered by SST1195
+dotnet_diagnostic.IDE0032.severity = none # covered by SST1420
+dotnet_diagnostic.IDE0033.severity = none # covered by SST1142
+dotnet_diagnostic.IDE0034.severity = none # covered by SST1188
+dotnet_diagnostic.IDE0036.severity = none # covered by SST1206
+dotnet_diagnostic.IDE0037.severity = none # covered by SST2216
+dotnet_diagnostic.IDE0039.severity = none # covered by SST2228
+dotnet_diagnostic.IDE0040.severity = none # covered by SST1400
+dotnet_diagnostic.IDE0045.severity = none # covered by SST1198
+dotnet_diagnostic.IDE0046.severity = none # covered by SST1197
+dotnet_diagnostic.IDE0051.severity = none # covered by SST1440
+dotnet_diagnostic.IDE0053.severity = none # covered by SST2257
+dotnet_diagnostic.IDE0054.severity = none # covered by SST1185
+dotnet_diagnostic.IDE0056.severity = none # covered by SST2203
+dotnet_diagnostic.IDE0062.severity = none # covered by SST2235
+dotnet_diagnostic.IDE0063.severity = none # covered by SST2236
+dotnet_diagnostic.IDE0065.severity = none # covered by SST1200
+dotnet_diagnostic.IDE0070.severity = none # covered by SST2217
+dotnet_diagnostic.IDE0071.severity = none # covered by SST2220
+dotnet_diagnostic.IDE0072.severity = none # covered by SST2206
+dotnet_diagnostic.IDE0073.severity = none # covered by SST1633
+dotnet_diagnostic.IDE0074.severity = none # covered by SST2223
+dotnet_diagnostic.IDE0076.severity = none # covered by SST1457
+dotnet_diagnostic.IDE0077.severity = none # covered by SST1458
+dotnet_diagnostic.IDE0080.severity = none # covered by SST2209
+dotnet_diagnostic.IDE0082.severity = none # covered by SST1199
+dotnet_diagnostic.IDE0083.severity = none # covered by SST2006
+dotnet_diagnostic.IDE0090.severity = none # covered by SST2202
+dotnet_diagnostic.IDE0100.severity = none # covered by SST1143
+dotnet_diagnostic.IDE0110.severity = none # covered by SST2213
+dotnet_diagnostic.IDE0150.severity = none # covered by SST2231
+dotnet_diagnostic.IDE0161.severity = none # covered by SST2237
+dotnet_diagnostic.IDE0170.severity = none # covered by SST2238
+dotnet_diagnostic.IDE0180.severity = none # covered by SST2215
+dotnet_diagnostic.IDE0200.severity = none # covered by SST2239
+dotnet_diagnostic.IDE0220.severity = none # covered by SST2225
+dotnet_diagnostic.IDE0230.severity = none # covered by SST2212
+dotnet_diagnostic.IDE0240.severity = none # covered by SST2210
+dotnet_diagnostic.IDE0241.severity = none # covered by SST2211
+dotnet_diagnostic.IDE0251.severity = none # covered by SST1460
+dotnet_diagnostic.IDE0270.severity = none # covered by SST1195
+dotnet_diagnostic.IDE0280.severity = none # covered by SST1463
+dotnet_diagnostic.IDE0290.severity = none # covered by SST2241
+dotnet_diagnostic.IDE0301.severity = none # covered by SST2100
+dotnet_diagnostic.IDE0302.severity = none # covered by SST2102
+dotnet_diagnostic.IDE0303.severity = none # covered by SST2103
+dotnet_diagnostic.IDE0304.severity = none # covered by SST2104
+dotnet_diagnostic.IDE0305.severity = none # covered by SST2105
+dotnet_diagnostic.IDE0340.severity = none # covered by SST2232
+dotnet_diagnostic.IDE0350.severity = none # covered by SST2218
+dotnet_diagnostic.IDE0380.severity = none # covered by SST1455
+dotnet_diagnostic.IDE1005.severity = none # covered by SST2240
+
###################
# PublicApiAnalyzers (RSxxxx) - public API surface tracking
###################
@@ -2140,15 +2251,15 @@ dotnet_diagnostic.S3927.severity = none # Serialization event handlers should be
dotnet_diagnostic.S3981.severity = none # Collection sizes and array length comparisons should make sense — covered by SST1479
dotnet_diagnostic.S3984.severity = none # Exceptions should not be created without being thrown — covered by SST1480
dotnet_diagnostic.S4143.severity = none # Collection elements should not be replaced unconditionally — covered by SST1487
-dotnet_diagnostic.S4210.severity = none # Windows Forms entry points should be marked with STAThread -> off: WinForms entry point; not applicable to this cross-platform library
+dotnet_diagnostic.S4210.severity = none # Windows Forms entry points should be marked with STAThread -> replaced by SST2706
dotnet_diagnostic.S4260.severity = none # "ConstructorArgument" parameters should exist in constructors -> replaced by SST2487
dotnet_diagnostic.S4428.severity = none # "PartCreationPolicyAttribute" should be used with "ExportAttribute" — covered by SST2474
dotnet_diagnostic.S6507.severity = none # Blocks should not be synchronized on local variables — covered by SST1903
dotnet_diagnostic.S6677.severity = none # Message template placeholders should be unique — covered by SST2442
-dotnet_diagnostic.S6797.severity = none # Blazor query parameter type should be supported -> off: Blazor-specific; no Blazor surface in this library
-dotnet_diagnostic.S6798.severity = none # [JSInvokable] attribute should only be used on public methods -> off: Blazor-specific; no Blazor surface in this library
-dotnet_diagnostic.S6800.severity = none # Component parameter type should match the route parameter type constraint -> off: Blazor-specific; no Blazor surface in this library
-dotnet_diagnostic.S6930.severity = none # Backslash should be avoided in route templates -> off: ASP.NET MVC-specific; no controllers in this library
+dotnet_diagnostic.S6797.severity = none # Blazor query parameter type should be supported -> replaced by SST2702
+dotnet_diagnostic.S6798.severity = none # [JSInvokable] attribute should only be used on public methods -> replaced by SST2701
+dotnet_diagnostic.S6800.severity = none # Component parameter type should match the route parameter type constraint -> replaced by SST2703
+dotnet_diagnostic.S6930.severity = none # Backslash should be avoided in route templates -> replaced by SST2700
###################
# SonarAnalyzer (Sxxxx) - Minor Bug
@@ -2335,7 +2446,7 @@ dotnet_diagnostic.S2925.severity = none # "Thread.Sleep" should not be used in t
dotnet_diagnostic.S2933.severity = none # Fields that are only assigned in the constructor should be "readonly" - DUPLICATE IDE0044
dotnet_diagnostic.S2971.severity = none # LINQ expressions should be simplified — covered by PSH1101/PSH1102
dotnet_diagnostic.S3010.severity = none # Static fields should not be updated in constructors — covered by SST2402
-dotnet_diagnostic.S3011.severity = none # Reflection should not be used to increase accessibility of classes, methods, or fields -> off: reflection-audit hotspot; not enforced here
+dotnet_diagnostic.S3011.severity = none # Reflection should not be used to increase accessibility of classes, methods, or fields -> replaced by SES1406
dotnet_diagnostic.S3059.severity = none # Types should not have members with visibility set higher than the type's visibility
dotnet_diagnostic.S3063.severity = none # "StringBuilder" data should be used — covered by SST2408
dotnet_diagnostic.S3169.severity = none # Multiple "OrderBy" calls should not be used — covered by PSH1108
@@ -2400,7 +2511,7 @@ dotnet_diagnostic.S6566.severity = none # Use "DateTimeOffset" instead of "DateT
dotnet_diagnostic.S6575.severity = none # Use "TimeZoneInfo.FindSystemTimeZoneById" without converting the timezones with "TimezoneConverter" -> replaced by PSH1419
dotnet_diagnostic.S6580.severity = none # Use a format provider when parsing date and time - DUPLICATE CA1305
dotnet_diagnostic.S6673.severity = none # Log message template placeholders should be in the right order — covered by SST2440
-dotnet_diagnostic.S6802.severity = none # Using lambda expressions in loops should be avoided in Blazor markup section -> off: Blazor-specific; no Blazor surface in this library
+dotnet_diagnostic.S6802.severity = none # Using lambda expressions in loops should be avoided in Blazor markup section -> replaced by PSH1600
dotnet_diagnostic.S6803.severity = none # Parameters with SupplyParameterFromQuery attribute should be used only in routable components -> off: Blazor-specific; no Blazor surface in this library
dotnet_diagnostic.S6931.severity = none # ASP.NET controller actions should not have a route template starting with "/" -> off: ASP.NET MVC-specific; no controllers in this library
dotnet_diagnostic.S6932.severity = none # Use model binding instead of reading raw request data -> off: ASP.NET MVC-specific; no controllers in this library
@@ -2408,8 +2519,8 @@ dotnet_diagnostic.S6934.severity = none # A Route attribute should be added to t
dotnet_diagnostic.S6960.severity = none # Controllers should not have mixed responsibilities -> off: ASP.NET MVC-specific; no controllers in this library
dotnet_diagnostic.S6961.severity = none # API Controllers should derive from ControllerBase instead of Controller -> off: ASP.NET MVC-specific; no controllers in this library
dotnet_diagnostic.S6962.severity = none # You should pool HTTP connections with HttpClientFactory — covered by PSH1418
-dotnet_diagnostic.S6964.severity = none # Value type property used as input in a controller action should be nullable, required or annotated with the JsonRequiredAttribute to avoid under-posting. -> off: ASP.NET MVC-specific; no controllers in this library
-dotnet_diagnostic.S6965.severity = none # REST API actions should be annotated with an HTTP verb attribute -> off: ASP.NET MVC-specific; no controllers in this library
+dotnet_diagnostic.S6964.severity = none # Value type property used as input in a controller action should be nullable, required or annotated with the JsonRequiredAttribute to avoid under-posting. -> replaced by SST2705 (opt-in)
+dotnet_diagnostic.S6965.severity = none # REST API actions should be annotated with an HTTP verb attribute -> replaced by SST2704
dotnet_diagnostic.S6966.severity = none # Awaitable method should be used — covered by PSH1313
dotnet_diagnostic.S6968.severity = none # Actions that return a value should be annotated with ProducesResponseTypeAttribute containing the return type -> off: ASP.NET MVC-specific; no controllers in this library
dotnet_diagnostic.S881.severity = none # Increment (++) and decrement (--) operators should not be used in a method call or mixed with other operators in an expression — covered by SST2015
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index 1d3b7ba..873efdb 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -5,7 +5,7 @@
true
- 3.33.0
+ 3.38.1
From 8621cef209310b57f22fd04228849c46a92f847b Mon Sep 17 00:00:00 2001
From: Glenn Watson <5834289+glennawatson@users.noreply.github.com>
Date: Sat, 25 Jul 2026 17:19:42 +1000
Subject: [PATCH 2/8] build: resolve analyzer upgrade fallout
- Update compatible analyzer, MAUI, and test dependencies.
- Fix new diagnostics while preserving established public API names.
---
.editorconfig | 3 ++-
src/Directory.Packages.props | 6 +++---
.../CancellationTokenPolyfillExtensions.cs | 2 +-
.../Advanced/StartSubscription.cs | 3 ++-
src/Primitives.Async.Shared/AsyncContext.cs | 10 ++++++++--
.../Advanced/FromAsyncExternalCancellation{T}.cs | 5 ++++-
.../Advanced/FromAsyncSubscription{T}.cs | 3 ++-
.../SignalOperatorMixins.StatefulSignals.cs | 11 ++++-------
src/Primitives.Shared/SignalOperatorMixins.cs | 2 +-
.../SignalOperatorParityMixins.cs | 2 +-
.../Signals/SignalExtensions{FromTask}.cs | 15 +++++++++++----
.../Signals/Signal{Factories}.cs | 2 +-
.../Signals/Signal{FromTask}.cs | 6 ++++--
.../Signals/Signal{GetAwaiter}.cs | 3 ++-
src/Primitives.Shared/Signals/TaskSignal{T}.cs | 6 +++++-
.../Advanced/BackgroundJobSignal{T}.cs | 3 ++-
.../Advanced/FlatMapWitness{TSource,TResult}.cs | 4 +++-
.../Advanced/IntervalSubscription.cs | 8 +++++---
.../Advanced/PooledDelaySource.cs | 3 ++-
.../Advanced/StartSubscription{TResult}.cs | 3 ++-
...testEnumerableCoordinator{TSource,TResult}.cs | 2 +-
.../Advanced/TakeUntilLifecycle.cs | 2 +-
.../Advanced/TaskResultCompletionSource.cs | 3 ++-
.../ConnectableSignalAsyncHelper.cs | 2 +-
.../Operators/Expire.cs | 3 ++-
.../Signals/CommandSignal{TResult}.cs | 12 +++++++++---
.../ConcurrencyLimiter.cs | 6 +++++-
.../Operators/SelectLatestAsyncObservable.cs | 10 +++++++++-
.../Concurrency/WasmScheduler.cs | 14 +++++++++++---
.../SynchronizationContextSequencer.cs | 5 ++++-
.../Concurrency/TaskPoolSequencer.cs | 3 ++-
.../Concurrency/ThreadPoolSequencer.cs | 6 ++++--
.../Concurrency/WasmSequencer.cs | 3 ++-
...sComparisonBenchmarks.Library.Supplemental.cs | 5 +----
.../TerminalCancellationBenchmarks.cs | 12 ++++++++----
.../CombiningOperatorTests.Multicast.cs | 7 ++-----
.../CombiningOperatorTests.cs | 2 +-
.../TakeUntilOperatorTests.CompletionDelegate.cs | 2 +-
.../TakeUntilOperatorTests.cs | 2 +-
.../TaskSignalSubscriptionTests.cs | 3 ++-
.../TransformationOperatorTests.cs | 3 ++-
.../MauiDispatcherSequencerTests.cs | 2 +-
.../MauiDispatcherSequencerTests.cs | 2 +-
.../AsyncSignalTests.cs | 2 +-
.../CommandExecutionTests.cs | 4 ++--
.../ConcurencyTests.cs | 2 +-
.../ConnectableSignalTests.cs | 6 +++---
.../ObservableMixinsTests.cs | 2 +-
.../PrioritySemaphoreSignalTests.cs | 6 +++---
.../SafeWitnessTests.cs | 4 ++--
.../ScheduledSignalTests.cs | 4 ++--
.../SignalFactoriesTests.DefaultSequencer.cs | 5 +----
.../SignalFactoriesTests.Scheduling.cs | 10 ++--------
.../SignalFactoriesTests.cs | 2 +-
.../SignalFromTaskTest.cs | 16 ++++++++--------
.../SignalOperatorMixinsTests.cs | 2 +-
.../SignalRecoverTests.cs | 2 +-
.../ReactiveUI.Primitives.Tests/SignalTests.cs | 4 ++--
.../SinkObserverTests.cs | 6 +++---
.../StateSignalTests.cs | 2 +-
.../SyncLatestTests.cs | 2 +-
.../TaskSignalTests.cs | 2 +-
.../UseSignalTests.cs | 2 +-
63 files changed, 176 insertions(+), 120 deletions(-)
diff --git a/.editorconfig b/.editorconfig
index 730fb50..dae5bee 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -556,6 +556,7 @@ dotnet_diagnostic.CA5367.severity = error # Do not serialize types with pointer
dotnet_diagnostic.S1075.severity = none # Hardcoded URI — canonical SourceLink hosts are the point
dotnet_diagnostic.S2436.severity = none # Too many generic parameters — needed for the projector overload
dotnet_diagnostic.S4036.severity = none # PATH-relative process spawn — benchmark only, trusted env
+dotnet_diagnostic.S8969.severity = none # Nullability inference is inconsistent across the repository's target frameworks
###################
# Microsoft .NET Runtime Obsoletions (SYSLIB0xxx)
@@ -1899,7 +1900,7 @@ dotnet_diagnostic.SES1710.severity = error # Antiforgery validation is disabled
dotnet_diagnostic.SST1101.severity = none # see docs/rules/SST1101.md
dotnet_diagnostic.SST1220.severity = error # An all-named argument list is in a different order than the parameters. Code fix reorders it to declaration order. Info.
dotnet_diagnostic.SST1221.severity = error # `where` constraint clauses are not ordered to match the type-parameter list. Code fix reorders them. Info.
-dotnet_diagnostic.SST1321.severity = error # A method whose name ends in `Async` returns nothing awaitable — the inverse of SST1317. Code fix (rename) drops the suffix.
+dotnet_diagnostic.SST1321.severity = none # Public APIs intentionally use Async to describe asynchronous observable behavior without returning an awaitable.
dotnet_diagnostic.SST1434.severity = error # see docs/rules/SST1434.md
dotnet_diagnostic.SST1525.severity = error # A multi-statement `switch` section has no braces; the braces-on policy extends to switch sections. Code fix wraps it.
dotnet_diagnostic.SST1526.severity = none # A wrapped binary expression places the operator inconsistently. Configurable (`before`/`after`, default before). Opt-in.
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index 873efdb..df0c0d4 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -18,7 +18,7 @@
-
+
@@ -45,7 +45,7 @@
-
+
@@ -65,7 +65,7 @@
-
+
diff --git a/src/Polyfills/CancellationTokenPolyfillExtensions.cs b/src/Polyfills/CancellationTokenPolyfillExtensions.cs
index a198a31..225c333 100644
--- a/src/Polyfills/CancellationTokenPolyfillExtensions.cs
+++ b/src/Polyfills/CancellationTokenPolyfillExtensions.cs
@@ -31,7 +31,7 @@ internal CancellationTokenRegistration
static boxed =>
{
var (inner, innerState, innerToken) =
- ((Action Callback, object? State, CancellationToken Token))boxed!;
+ ((Action Callback, object? State, CancellationToken Token))boxed;
inner(innerState, innerToken);
},
(callback, state, token),
diff --git a/src/Primitives.Async.Shared/Advanced/StartSubscription.cs b/src/Primitives.Async.Shared/Advanced/StartSubscription.cs
index 3c4c160..1ab2712 100644
--- a/src/Primitives.Async.Shared/Advanced/StartSubscription.cs
+++ b/src/Primitives.Async.Shared/Advanced/StartSubscription.cs
@@ -49,7 +49,8 @@ await Task.Factory.StartNew(
static s =>
{
var (self, observer, cancellationToken) =
- ((StartSubscription, IObserverAsync, CancellationToken))s!;
+ ((StartSubscription, IObserverAsync, CancellationToken))(
+ s ?? throw new InvalidOperationException("The start state is missing."));
return self.ExecuteActionAsync(observer, cancellationToken).AsTask();
},
(this, observer, cancellationToken),
diff --git a/src/Primitives.Async.Shared/AsyncContext.cs b/src/Primitives.Async.Shared/AsyncContext.cs
index 284e45d..795f80f 100644
--- a/src/Primitives.Async.Shared/AsyncContext.cs
+++ b/src/Primitives.Async.Shared/AsyncContext.cs
@@ -169,7 +169,10 @@ public void OnCompleted(Action continuation)
var sc = AsyncContext.SynchronizationContext;
if (sc is not null)
{
- sc.Post(static c => ((Action)c!).Invoke(), continuation);
+ sc.Post(
+ static state => ((Action)(
+ state ?? throw new InvalidOperationException("The continuation is missing."))).Invoke(),
+ continuation);
return;
}
@@ -196,7 +199,10 @@ public void OnCompleted(Action continuation)
// path Yield takes by default, so the saving lands on the operator's hot path.
if (ts is null || ts == TaskScheduler.Default)
{
- _ = ThreadPool.UnsafeQueueUserWorkItem(static c => ((Action)c!).Invoke(), continuation);
+ _ = ThreadPool.UnsafeQueueUserWorkItem(
+ static state => ((Action)(
+ state ?? throw new InvalidOperationException("The continuation is missing."))).Invoke(),
+ continuation);
}
}
diff --git a/src/Primitives.Shared/Advanced/FromAsyncExternalCancellation{T}.cs b/src/Primitives.Shared/Advanced/FromAsyncExternalCancellation{T}.cs
index 1c9c8f6..205172a 100644
--- a/src/Primitives.Shared/Advanced/FromAsyncExternalCancellation{T}.cs
+++ b/src/Primitives.Shared/Advanced/FromAsyncExternalCancellation{T}.cs
@@ -64,7 +64,10 @@ internal bool Start()
}
Registration =
- CancellationToken.Register(static state => ((FromAsyncExternalCancellation)state!).Cancel(), this);
+ CancellationToken.Register(
+ static state => ((FromAsyncExternalCancellation)(
+ state ?? throw new InvalidOperationException("The cancellation state is missing."))).Cancel(),
+ this);
return !Lifetime.IsCompleted;
}
diff --git a/src/Primitives.Shared/Advanced/FromAsyncSubscription{T}.cs b/src/Primitives.Shared/Advanced/FromAsyncSubscription{T}.cs
index 1655c02..73ebf79 100644
--- a/src/Primitives.Shared/Advanced/FromAsyncSubscription{T}.cs
+++ b/src/Primitives.Shared/Advanced/FromAsyncSubscription{T}.cs
@@ -101,7 +101,8 @@ internal IDisposable Start()
FromAsyncTaskObservation observation = new(Observer, Lifetime, ExternalCancellation, linkedSource);
_ = task.ContinueWith(
- static (completedTask, state) => ((FromAsyncTaskObservation)state!).Observe(completedTask),
+ static (completedTask, state) => ((FromAsyncTaskObservation)(
+ state ?? throw new InvalidOperationException("The observation state is missing."))).Observe(completedTask),
observation,
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
diff --git a/src/Primitives.Shared/SignalOperatorMixins.StatefulSignals.cs b/src/Primitives.Shared/SignalOperatorMixins.StatefulSignals.cs
index bfd2629..dc3e76f 100644
--- a/src/Primitives.Shared/SignalOperatorMixins.StatefulSignals.cs
+++ b/src/Primitives.Shared/SignalOperatorMixins.StatefulSignals.cs
@@ -317,20 +317,17 @@ public IDisposable Subscribe(IObserver observer)
/// Creates the duplicate-tracking set, pre-sized when the source has a known element count.
/// The set used to track already-observed values.
- private HashSet CreateSeen()
- {
+ private HashSet CreateSeen() =>
#if NET8_0_OR_GREATER
- var capacity = _source is RangeSignal range ? range.Count : 0;
- return capacity switch
+ (_source is RangeSignal range ? range.Count : 0) switch
{
- > 0 => new(capacity, _comparer),
+ var capacity when capacity > 0 => new(capacity, _comparer),
_ when _comparer is null => [],
_ => new(_comparer),
};
#else
- return new(_comparer);
+ new(_comparer);
#endif
- }
}
/// Dedicated signal for Unique (adjacent distinct).
diff --git a/src/Primitives.Shared/SignalOperatorMixins.cs b/src/Primitives.Shared/SignalOperatorMixins.cs
index 0d462f4..22b7414 100644
--- a/src/Primitives.Shared/SignalOperatorMixins.cs
+++ b/src/Primitives.Shared/SignalOperatorMixins.cs
@@ -687,7 +687,7 @@ public IObservable ToSignal()
}
return task.IsFaulted
- ? new ImmediateThrowSignal(task.Exception!.InnerException ?? task.Exception)
+ ? new ImmediateThrowSignal(task.Exception.InnerException ?? task.Exception)
: new TaskInstanceSignal(task);
}
}
diff --git a/src/Primitives.Shared/SignalOperatorParityMixins.cs b/src/Primitives.Shared/SignalOperatorParityMixins.cs
index 890a0aa..90c9a41 100644
--- a/src/Primitives.Shared/SignalOperatorParityMixins.cs
+++ b/src/Primitives.Shared/SignalOperatorParityMixins.cs
@@ -788,7 +788,7 @@ public IObservable ToObservable()
}
return task.IsFaulted
- ? new ImmediateThrowSignal(task.Exception!.InnerException ?? task.Exception)
+ ? new ImmediateThrowSignal(task.Exception.InnerException ?? task.Exception)
: new TaskInstanceSignal(task);
}
diff --git a/src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs b/src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs
index db9a5ee..0b6c9f3 100644
--- a/src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs
+++ b/src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs
@@ -102,10 +102,17 @@ public async Task HandleCancellation(Action? action)
internal async Task<(TResult Value, bool IsCanceled)> WhenCancelled(CancellationToken cancellationToken)
{
TaskCompletionSource tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
- var registration = cancellationToken.Register(
- static state => ((TaskCompletionSource)state!).TrySetCanceled(),
- tcs,
- false);
+ var registration = cancellationToken.UnsafeRegister(
+ static (state, token) =>
+ {
+ if (state is not TaskCompletionSource source)
+ {
+ throw new InvalidOperationException("The cancellation state is not a completion source.");
+ }
+
+ _ = source.TrySetCanceled(token);
+ },
+ tcs);
var cancellationTask = tcs.Task;
try
diff --git a/src/Primitives.Shared/Signals/Signal{Factories}.cs b/src/Primitives.Shared/Signals/Signal{Factories}.cs
index c59bfcc..2e28016 100644
--- a/src/Primitives.Shared/Signals/Signal{Factories}.cs
+++ b/src/Primitives.Shared/Signals/Signal{Factories}.cs
@@ -235,7 +235,7 @@ public static IObservable FromTask(Task task)
}
return task.IsFaulted
- ? new ImmediateThrowSignal(task.Exception!.InnerException ?? task.Exception)
+ ? new ImmediateThrowSignal(task.Exception.InnerException ?? task.Exception)
: new TaskInstanceSignal(task);
}
diff --git a/src/Primitives.Shared/Signals/Signal{FromTask}.cs b/src/Primitives.Shared/Signals/Signal{FromTask}.cs
index 5709405..fe39479 100644
--- a/src/Primitives.Shared/Signals/Signal{FromTask}.cs
+++ b/src/Primitives.Shared/Signals/Signal{FromTask}.cs
@@ -183,7 +183,7 @@ private static bool TryEmitSynchronously(
return false;
}
- observer.OnError(task.Exception!.InnerException ?? task.Exception);
+ observer.OnError(task.Exception.InnerException ?? task.Exception);
return true;
}
@@ -288,7 +288,9 @@ public void GetOperationCanceled(IObserver observer)
ArgumentExceptionHelper.ThrowIfNull(observer);
_ = SourceCore.Token.Register(
- static state => ((IObserver)state!).OnNext(new OperationCanceledException()),
+ static state => ((IObserver)(
+ state ?? throw new InvalidOperationException("The cancellation observer is missing."))).OnNext(
+ new OperationCanceledException()),
observer,
false);
}
diff --git a/src/Primitives.Shared/Signals/Signal{GetAwaiter}.cs b/src/Primitives.Shared/Signals/Signal{GetAwaiter}.cs
index 6aa4113..acf703c 100644
--- a/src/Primitives.Shared/Signals/Signal{GetAwaiter}.cs
+++ b/src/Primitives.Shared/Signals/Signal{GetAwaiter}.cs
@@ -121,7 +121,8 @@ internal static void RegisterCancelation(
var ctr = token.Register(
static state =>
{
- var (subscription, subject, token) = ((IDisposable, IAwaitSignal, CancellationToken))state!;
+ var (subscription, subject, token) = ((IDisposable, IAwaitSignal, CancellationToken))(
+ state ?? throw new InvalidOperationException("The await cancellation state is missing."));
subscription.Dispose();
_ = Cancel(subject, token);
},
diff --git a/src/Primitives.Shared/Signals/TaskSignal{T}.cs b/src/Primitives.Shared/Signals/TaskSignal{T}.cs
index 88070d4..cf5538a 100644
--- a/src/Primitives.Shared/Signals/TaskSignal{T}.cs
+++ b/src/Primitives.Shared/Signals/TaskSignal{T}.cs
@@ -56,7 +56,11 @@ private TaskSignal(ISequencer? sequencer, CancellationTokenSource? cancellationT
/// The observer.
public void GetOperationCanceled(IObserver observer) =>
CancellationTokenSource?.Token
- .Register(static o => ((IObserver)o!).OnNext(new OperationCanceledException()), observer)
+ .Register(
+ static state => ((IObserver)(
+ state ?? throw new InvalidOperationException("The cancellation observer is missing."))).OnNext(
+ new OperationCanceledException()),
+ observer)
.DisposeWith(_cleanUp);
/// Subscribes the specified observer.
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/BackgroundJobSignal{T}.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/BackgroundJobSignal{T}.cs
index 9f00898..3fedca7 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/BackgroundJobSignal{T}.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/BackgroundJobSignal{T}.cs
@@ -76,7 +76,8 @@ await Task.Factory.StartNew(
static s =>
{
var (self, observer, cancellationToken) =
- ((BackgroundJobSignal, IObserverAsync, CancellationToken))s!;
+ ((BackgroundJobSignal, IObserverAsync, CancellationToken))(
+ s ?? throw new InvalidOperationException("The background-job state is missing."));
return self.Job(observer, cancellationToken).AsTask();
},
(this, observer, cancellationToken),
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/FlatMapWitness{TSource,TResult}.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/FlatMapWitness{TSource,TResult}.cs
index 6f4fcbf..2969d91 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/FlatMapWitness{TSource,TResult}.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/FlatMapWitness{TSource,TResult}.cs
@@ -37,7 +37,9 @@ protected override async ValueTask OnNextAsyncCore(TSource value, CancellationTo
{
var inner = SyncSelector is not null
? SyncSelector(value)
- : await AsyncSelector!(value, cancellationToken).ConfigureAwait(false);
+ : await (AsyncSelector ?? throw new InvalidOperationException("The flat-map selector is missing."))(
+ value,
+ cancellationToken).ConfigureAwait(false);
await Coordinator.SubscribeInnerAsync(inner).ConfigureAwait(false);
}
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/IntervalSubscription.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/IntervalSubscription.cs
index e514439..312ed43 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/IntervalSubscription.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/IntervalSubscription.cs
@@ -54,7 +54,8 @@ private async ValueTask DelayWithProviderAsync(CancellationToken cancellationTok
{
TaskCompletionSource tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
await using var tp = TimeProvider!.CreateTimer(
- static x => ((TaskCompletionSource)x!).TrySetResult(true),
+ static state => ((TaskCompletionSource)(
+ state ?? throw new InvalidOperationException("The interval state is missing."))).TrySetResult(true),
tcs,
Period,
Timeout.InfiniteTimeSpan);
@@ -64,7 +65,8 @@ private async ValueTask DelayWithProviderAsync(CancellationToken cancellationTok
cancellationToken.Register(
static x =>
{
- var (tcs, ct) = ((TaskCompletionSource, CancellationToken))x!;
+ var (tcs, ct) = ((TaskCompletionSource, CancellationToken))(
+ x ?? throw new InvalidOperationException("The interval cancellation state is missing."));
_ = tcs.TrySetCanceled(ct);
},
(tcs, cancellationToken));
@@ -73,7 +75,7 @@ private async ValueTask DelayWithProviderAsync(CancellationToken cancellationTok
cancellationToken.Register(
static x =>
{
- var (tcs, ct) = ((TaskCompletionSource, CancellationToken))x!;
+ var (tcs, ct) = ((TaskCompletionSource, CancellationToken))x;
_ = tcs.TrySetCanceled(ct);
},
(tcs, cancellationToken));
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/PooledDelaySource.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/PooledDelaySource.cs
index 9c2f2f3..93000ca 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/PooledDelaySource.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/PooledDelaySource.cs
@@ -95,7 +95,8 @@ public ValueTask BeginAsync(TimeSpan delay, TimeProvider timeProvider, Cancellat
// some test / benchmark providers); in that case _completed flips to Claimed before this
// call returns.
_timer = timeProvider.CreateTimer(
- static state => ((PooledDelaySource)state!).OnTimerFired(),
+ static state => ((PooledDelaySource)(
+ state ?? throw new InvalidOperationException("The delay state is missing."))).OnTimerFired(),
this,
delay,
Timeout.InfiniteTimeSpan);
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/StartSubscription{TResult}.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/StartSubscription{TResult}.cs
index c4b0729..96dd8b8 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/StartSubscription{TResult}.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/StartSubscription{TResult}.cs
@@ -46,7 +46,8 @@ await Task.Factory.StartNew(
static s =>
{
var (self, observer, cancellationToken) =
- ((StartSubscription, IObserverAsync, CancellationToken))s!;
+ ((StartSubscription, IObserverAsync, CancellationToken))(
+ s ?? throw new InvalidOperationException("The start state is missing."));
return self.ExecuteFunctionAsync(observer, cancellationToken).AsTask();
},
(this, observer, cancellationToken),
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/SyncLatestEnumerableCoordinator{TSource,TResult}.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/SyncLatestEnumerableCoordinator{TSource,TResult}.cs
index 93d3c98..249462c 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/SyncLatestEnumerableCoordinator{TSource,TResult}.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/SyncLatestEnumerableCoordinator{TSource,TResult}.cs
@@ -121,7 +121,7 @@ internal async ValueTask OnNextAsync(int index, TSource indexValue, Cancellation
for (var i = 0; i < Values.Length; i++)
{
- SnapshotBuffer[i] = Values[i].Value!;
+ SnapshotBuffer[i] = Values[i].Value;
}
TResult projected;
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/TakeUntilLifecycle.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/TakeUntilLifecycle.cs
index 4d5a119..eafe9cf 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/TakeUntilLifecycle.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/TakeUntilLifecycle.cs
@@ -89,7 +89,7 @@ public async ValueTask RelayErrorAsync(Exception error)
/// A ValueTask representing the asynchronous forward.
public async ValueTask RelayCompletionAsync(Result result)
{
- using (await _gate.EnterAsync().ConfigureAwait(false))
+ using (await _gate.EnterAsync(CancellationToken.None).ConfigureAwait(false))
{
await _observer.OnCompletedAsync(result).ConfigureAwait(false);
}
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/TaskResultCompletionSource.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/TaskResultCompletionSource.cs
index ba0cfa3..e716e16 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/TaskResultCompletionSource.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/TaskResultCompletionSource.cs
@@ -76,7 +76,8 @@ private CancellationTokenRegistration RegisterCancellation() =>
_cancellationToken.Register(
static state =>
{
- var source = (TaskResultCompletionSource)state!;
+ var source = (TaskResultCompletionSource)(
+ state ?? throw new InvalidOperationException("The task result state is missing."));
_ = source._taskSource.TrySetException(new OperationCanceledException(source._cancellationToken));
},
this);
diff --git a/src/ReactiveUI.Primitives.Async.Core/ConnectableSignalAsyncHelper.cs b/src/ReactiveUI.Primitives.Async.Core/ConnectableSignalAsyncHelper.cs
index 0ec0f8b..5a38e6c 100644
--- a/src/ReactiveUI.Primitives.Async.Core/ConnectableSignalAsyncHelper.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/ConnectableSignalAsyncHelper.cs
@@ -95,7 +95,7 @@ internal static void Dispose(ConnectableSignalAsyncState state)
}
state.DisposedCts.Cancel();
- state.Connection?.DisposeAsync().AsTask().Wait();
+ state.Connection?.DisposeAsync().AsTask().Wait(CancellationToken.None);
state.Dispose();
}
diff --git a/src/ReactiveUI.Primitives.Async.Core/Operators/Expire.cs b/src/ReactiveUI.Primitives.Async.Core/Operators/Expire.cs
index 542823f..f7b6340 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Operators/Expire.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Operators/Expire.cs
@@ -89,7 +89,8 @@ internal void StartTimer(CancellationToken cancellationToken)
try
{
_timer = timeProvider.CreateTimer(
- static state => ((TimeoutWitness)state!).OnTimerFired(),
+ static state => ((TimeoutWitness)(
+ state ?? throw new InvalidOperationException("The timeout state is missing."))).OnTimerFired(),
this,
dueTime,
System.Threading.Timeout.InfiniteTimeSpan);
diff --git a/src/ReactiveUI.Primitives.Core/Signals/CommandSignal{TResult}.cs b/src/ReactiveUI.Primitives.Core/Signals/CommandSignal{TResult}.cs
index dd980e6..fb1c03b 100644
--- a/src/ReactiveUI.Primitives.Core/Signals/CommandSignal{TResult}.cs
+++ b/src/ReactiveUI.Primitives.Core/Signals/CommandSignal{TResult}.cs
@@ -157,7 +157,10 @@ public CommandExecution ExecuteAsync(CancellationToken cancellationToke
return _executeSync is not null
? new(ExecuteSync(cancellationToken))
- : new CommandExecution(ExecuteAsyncCore(cancellationToken));
+ : new CommandExecution(
+ ExecuteAsyncCore(
+ _executeAsync ?? throw new InvalidOperationException("The command has no execution delegate."),
+ cancellationToken));
}
catch (Exception error)
{
@@ -269,14 +272,17 @@ private TResult ExecuteSync(CancellationToken cancellationToken)
}
/// Executes the asynchronous command path.
+ /// The constructor-selected delegate, guaranteed non-null for this path.
/// Cancellation token for the operation.
/// The command result.
- private async Task ExecuteAsyncCore(CancellationToken cancellationToken)
+ private async Task ExecuteAsyncCore(
+ Func> executeAsync,
+ CancellationToken cancellationToken)
{
BeginExecution();
try
{
- var result = await _executeAsync!(cancellationToken).ConfigureAwait(false);
+ var result = await executeAsync(cancellationToken).ConfigureAwait(false);
PublishResult(result);
return result;
}
diff --git a/src/ReactiveUI.Primitives.Extensions.Core/ConcurrencyLimiter.cs b/src/ReactiveUI.Primitives.Extensions.Core/ConcurrencyLimiter.cs
index dd12056..881f6ff 100644
--- a/src/ReactiveUI.Primitives.Extensions.Core/ConcurrencyLimiter.cs
+++ b/src/ReactiveUI.Primitives.Extensions.Core/ConcurrencyLimiter.cs
@@ -155,7 +155,11 @@ private void PullNextTask(Subscription subscription)
_rator.Current?.ContinueWith(
static (ant, state) =>
{
- var sub = (Subscription)state!;
+ if (state is not Subscription sub)
+ {
+ throw new InvalidOperationException("The continuation state is not a subscription.");
+ }
+
sub.Limiter.ProcessTaskCompletion(sub, ant);
},
subscription,
diff --git a/src/ReactiveUI.Primitives.Extensions.Core/Operators/SelectLatestAsyncObservable.cs b/src/ReactiveUI.Primitives.Extensions.Core/Operators/SelectLatestAsyncObservable.cs
index 7385798..6ddf11d 100644
--- a/src/ReactiveUI.Primitives.Extensions.Core/Operators/SelectLatestAsyncObservable.cs
+++ b/src/ReactiveUI.Primitives.Extensions.Core/Operators/SelectLatestAsyncObservable.cs
@@ -111,7 +111,15 @@ public void OnCompleted()
}
_ = toAwait.ContinueWith(
- static (_, s) => ((SelectLatestAsyncSink)s!).SignalCompleted(),
+ static (_, state) =>
+ {
+ if (state is not SelectLatestAsyncSink sink)
+ {
+ throw new InvalidOperationException("The continuation state is not a select-latest sink.");
+ }
+
+ sink.SignalCompleted();
+ },
this,
TaskScheduler.Default);
}
diff --git a/src/ReactiveUI.Primitives.Reactive/Concurrency/WasmScheduler.cs b/src/ReactiveUI.Primitives.Reactive/Concurrency/WasmScheduler.cs
index 6fa9d2d..6d63e83 100644
--- a/src/ReactiveUI.Primitives.Reactive/Concurrency/WasmScheduler.cs
+++ b/src/ReactiveUI.Primitives.Reactive/Concurrency/WasmScheduler.cs
@@ -63,7 +63,8 @@ public sealed class WasmScheduler : LocalScheduler, ISchedulerPeriodic, IDisposa
"The drain timer is created disarmed, so nothing can call back into it until Schedule arms it after construction.")]
internal WasmScheduler() =>
_drainTimer = new(
- static state => ((WasmScheduler)state!).RunDrain(),
+ static state => ((WasmScheduler)(
+ state ?? throw new InvalidOperationException("The scheduler state is missing."))).RunDrain(),
this,
Timeout.InfiniteTimeSpan,
Timeout.InfiniteTimeSpan);
@@ -124,7 +125,13 @@ public override IDisposable Schedule(
// The timer roots itself while armed through the callback's target (the work item), which stores the
// timer; the item's Dispose cancels and releases it.
- item.AttachTimer(new(static s => ((IReadyWorkItem)s!).Run(), item, dt, Timeout.InfiniteTimeSpan));
+ item.AttachTimer(
+ new(
+ static state => ((IReadyWorkItem)(
+ state ?? throw new InvalidOperationException("The work-item state is missing."))).Run(),
+ item,
+ dt,
+ Timeout.InfiniteTimeSpan));
return item;
}
@@ -417,7 +424,8 @@ internal static PeriodicWorkItem Start(TState state, TimeSpan period, Fu
{
PeriodicWorkItem item = new(state, action);
Timer timer = new(
- static s => ((PeriodicWorkItem)s!).Tick(),
+ static state => ((PeriodicWorkItem)(
+ state ?? throw new InvalidOperationException("The periodic state is missing."))).Tick(),
item,
Timeout.InfiniteTimeSpan,
Timeout.InfiniteTimeSpan);
diff --git a/src/ReactiveUI.Primitives/Concurrency/SynchronizationContextSequencer.cs b/src/ReactiveUI.Primitives/Concurrency/SynchronizationContextSequencer.cs
index 85da073..a4cc66e 100644
--- a/src/ReactiveUI.Primitives/Concurrency/SynchronizationContextSequencer.cs
+++ b/src/ReactiveUI.Primitives/Concurrency/SynchronizationContextSequencer.cs
@@ -40,7 +40,10 @@ public void Schedule(IWorkItem item)
{
ArgumentExceptionHelper.ThrowIfNull(item);
- Context.Post(static state => ExecutePosted((IWorkItem)state!), item);
+ Context.Post(
+ static state => ExecutePosted((IWorkItem)(
+ state ?? throw new InvalidOperationException("The posted work item is missing."))),
+ item);
}
///
diff --git a/src/ReactiveUI.Primitives/Concurrency/TaskPoolSequencer.cs b/src/ReactiveUI.Primitives/Concurrency/TaskPoolSequencer.cs
index 1d928ef..770bbed 100644
--- a/src/ReactiveUI.Primitives/Concurrency/TaskPoolSequencer.cs
+++ b/src/ReactiveUI.Primitives/Concurrency/TaskPoolSequencer.cs
@@ -50,7 +50,8 @@ public void Schedule(IWorkItem item)
ArgumentExceptionHelper.ThrowIfNull(item);
_ = _taskFactory.StartNew(
- static state => ((DispatchState)state!).Run(),
+ static state => ((DispatchState)(
+ state ?? throw new InvalidOperationException("The dispatch state is missing."))).Run(),
new DispatchState(this, item),
_taskFactory.CancellationToken,
_taskFactory.CreationOptions,
diff --git a/src/ReactiveUI.Primitives/Concurrency/ThreadPoolSequencer.cs b/src/ReactiveUI.Primitives/Concurrency/ThreadPoolSequencer.cs
index af37f14..d5c8b27 100644
--- a/src/ReactiveUI.Primitives/Concurrency/ThreadPoolSequencer.cs
+++ b/src/ReactiveUI.Primitives/Concurrency/ThreadPoolSequencer.cs
@@ -17,7 +17,8 @@ public sealed class ThreadPoolSequencer : ISequencer, IDisposable
public static readonly ThreadPoolSequencer Instance = new();
/// Cached queue callback for immediate work.
- private static readonly WaitCallback ImmediateCallback = static state => ExecuteQueued((IWorkItem)state!);
+ private static readonly WaitCallback ImmediateCallback = static state => ExecuteQueued(
+ (IWorkItem)(state ?? throw new InvalidOperationException("The queued work item is missing.")));
/// Guards access to delayed work.
private readonly Lock _gate = new();
@@ -47,7 +48,8 @@ public sealed class ThreadPoolSequencer : ISequencer, IDisposable
"The timer is created disarmed, so nothing can call back into it until Schedule arms it after construction.")]
internal ThreadPoolSequencer() =>
_timer = new(
- static state => ((ThreadPoolSequencer)state!).RunDue(),
+ static state => ((ThreadPoolSequencer)(
+ state ?? throw new InvalidOperationException("The sequencer state is missing."))).RunDue(),
this,
Timeout.InfiniteTimeSpan,
Timeout.InfiniteTimeSpan);
diff --git a/src/ReactiveUI.Primitives/Concurrency/WasmSequencer.cs b/src/ReactiveUI.Primitives/Concurrency/WasmSequencer.cs
index 9f12b2d..aab3f19 100644
--- a/src/ReactiveUI.Primitives/Concurrency/WasmSequencer.cs
+++ b/src/ReactiveUI.Primitives/Concurrency/WasmSequencer.cs
@@ -49,7 +49,8 @@ public sealed class WasmSequencer : ISequencer, IDisposable
internal WasmSequencer()
{
_timer = new(
- static state => ((WasmSequencer)state!).RunDrain(),
+ static state => ((WasmSequencer)(
+ state ?? throw new InvalidOperationException("The sequencer state is missing."))).RunDrain(),
this,
Timeout.InfiniteTimeSpan,
Timeout.InfiniteTimeSpan);
diff --git a/src/benchmarks/ReactiveUI.Primitives.Benchmarks/ReactiveExtensionsComparisonBenchmarks.Library.Supplemental.cs b/src/benchmarks/ReactiveUI.Primitives.Benchmarks/ReactiveExtensionsComparisonBenchmarks.Library.Supplemental.cs
index 9a54e95..708bfb5 100644
--- a/src/benchmarks/ReactiveUI.Primitives.Benchmarks/ReactiveExtensionsComparisonBenchmarks.Library.Supplemental.cs
+++ b/src/benchmarks/ReactiveUI.Primitives.Benchmarks/ReactiveExtensionsComparisonBenchmarks.Library.Supplemental.cs
@@ -580,10 +580,7 @@ bool ShouldContinue()
return hasRemaining;
}
- void RecordIteration()
- {
- total++;
- }
+ void RecordIteration() => total++;
return library == ExtensionsLibrary.Primitives
? DrainPrimitiveUnit(PrimitivesExtensions.While(ShouldContinue, RecordIteration)) + total
diff --git a/src/benchmarks/ReactiveUI.Primitives.Benchmarks/TerminalCancellationBenchmarks.cs b/src/benchmarks/ReactiveUI.Primitives.Benchmarks/TerminalCancellationBenchmarks.cs
index 5468ae8..5946746 100644
--- a/src/benchmarks/ReactiveUI.Primitives.Benchmarks/TerminalCancellationBenchmarks.cs
+++ b/src/benchmarks/ReactiveUI.Primitives.Benchmarks/TerminalCancellationBenchmarks.cs
@@ -61,14 +61,16 @@ public Task SystemReactiveFirstAsyncWithToken() =>
[Benchmark]
public Task R3FirstAsyncWithToken() =>
R3.ObservableExtensions.FirstAsync(
- R3.ObservableExtensions.Select(R3.Observable.Range(Start, Count), static x => x),
+ R3.ObservableExtensions.Select(
+ R3.Observable.Range(Start, Count, _liveSource.Token),
+ static x => x),
_liveSource.Token);
/// Benchmarks the task-shim ToTask overload that wraps a token around an existing task.
/// The first value.
[Benchmark]
public Task PrimitivesTaskToTaskWithToken() =>
- Signal.Sequence(Start, Count).Map(static x => x).FirstAsync().ToTask(_liveSource.Token);
+ Signal.Sequence(Start, Count).Map(static x => x).FirstAsync(CancellationToken.None).ToTask(_liveSource.Token);
/// Benchmarks awaiting the last-or-default value with a live token.
/// The last value or default.
@@ -87,7 +89,7 @@ public Task SystemReactiveLastOrDefaultAsyncWithToken() =>
[Benchmark]
public Task R3LastOrDefaultAsyncWithToken() =>
R3.ObservableExtensions.LastOrDefaultAsync(
- R3.Observable.Range(Start, Count),
+ R3.Observable.Range(Start, Count, _liveSource.Token),
cancellationToken: _liveSource.Token);
/// Benchmarks forwarding a completing range through TakeUntil with a live token.
@@ -116,7 +118,9 @@ public int SystemReactiveTakeUntilToken()
public int R3TakeUntilToken()
{
IntR3Witness observer = new();
- using var subscription = R3.ObservableExtensions.TakeUntil(R3.Observable.Range(Start, Count), _liveSource.Token)
+ using var subscription = R3.ObservableExtensions.TakeUntil(
+ R3.Observable.Range(Start, Count, _liveSource.Token),
+ _liveSource.Token)
.Subscribe(observer);
return observer.Total;
}
diff --git a/src/tests/ReactiveUI.Primitives.Async.Tests/CombiningOperatorTests.Multicast.cs b/src/tests/ReactiveUI.Primitives.Async.Tests/CombiningOperatorTests.Multicast.cs
index dc744fd..ce0515f 100644
--- a/src/tests/ReactiveUI.Primitives.Async.Tests/CombiningOperatorTests.Multicast.cs
+++ b/src/tests/ReactiveUI.Primitives.Async.Tests/CombiningOperatorTests.Multicast.cs
@@ -86,11 +86,8 @@ public async Task WhenMulticastConnectHandleDisposedTwice_ThenCanReconnectSucces
await handle.DisposeAsync();
// After the double-dispose the connectable must accept a new connection.
- await using var sub = await connectable.SubscribeAsync(static (_, _) =>
- {
- // Signal is already completed from first connect, so no items arrive.
- return ValueTask.CompletedTask;
- });
+ // Signal is already completed from first connect, so no items arrive.
+ await using var sub = await connectable.SubscribeAsync(static (_, _) => ValueTask.CompletedTask);
// A new ConnectAsync succeeds, proving internal state was not corrupted.
await using var newHandle = await connectable.ConnectAsync(CancellationToken.None);
diff --git a/src/tests/ReactiveUI.Primitives.Async.Tests/CombiningOperatorTests.cs b/src/tests/ReactiveUI.Primitives.Async.Tests/CombiningOperatorTests.cs
index 29f7845..9b7f919 100644
--- a/src/tests/ReactiveUI.Primitives.Async.Tests/CombiningOperatorTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Async.Tests/CombiningOperatorTests.cs
@@ -152,7 +152,7 @@ private sealed class ThrowingEnumerator : IEnumerator>
public IObservableAsync Current => null!;
///
- object System.Collections.IEnumerator.Current => Current!;
+ object System.Collections.IEnumerator.Current => Current;
///
public bool MoveNext() => throw new InvalidOperationException("enumerator MoveNext boom");
diff --git a/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.CompletionDelegate.cs b/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.CompletionDelegate.cs
index 63e5d14..b5e243d 100644
--- a/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.CompletionDelegate.cs
+++ b/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.CompletionDelegate.cs
@@ -725,7 +725,7 @@ public async Task WhenTakeUntilCompletionDelegateNotifiesTwice_ThenSecondNotific
notifyStop!(Result.Success);
await firstCompletion.Task.WaitAsync(WaitTimeout);
- notifyStop!(Result.Failure(new InvalidOperationException("second stop")));
+ notifyStop(Result.Failure(new InvalidOperationException("second stop")));
var leaked = await AsyncTestHelpers.WaitForConditionAsync(
() => errors.Count > 0 || completions.Count > 1,
SecondNotificationSettleWindow);
diff --git a/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.cs b/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.cs
index 6d9f3fa..00d63db 100644
--- a/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.cs
@@ -204,7 +204,7 @@ public async Task WhenTakeUntilObservableDisposed_ThenStopsEmissions()
public void WhenTaskStopSignalNullSource_ThenThrowsArgumentNull()
{
const IObservableAsync Source = null!;
- _ = Assert.Throws(static () => Source!.TakeUntil(Task.CompletedTask));
+ _ = Assert.Throws(static () => Source.TakeUntil(Task.CompletedTask));
}
/// Tests that task failure with SourceFailsWhenOtherFails=true completes with failure.
diff --git a/src/tests/ReactiveUI.Primitives.Async.Tests/TaskSignalSubscriptionTests.cs b/src/tests/ReactiveUI.Primitives.Async.Tests/TaskSignalSubscriptionTests.cs
index 196814a..a4853a4 100644
--- a/src/tests/ReactiveUI.Primitives.Async.Tests/TaskSignalSubscriptionTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Async.Tests/TaskSignalSubscriptionTests.cs
@@ -24,7 +24,8 @@ public async Task WhenDisposedReentrantlyAfterThreadHop_ThenDoesNotDeadlock()
{
await subscriptionReady.Task.ConfigureAwait(false);
await Task.Yield();
- await subscription!.DisposeAsync().ConfigureAwait(false);
+ await (subscription ?? throw new InvalidOperationException("The subscription is not ready."))
+ .DisposeAsync().ConfigureAwait(false);
disposed.SetResult();
});
diff --git a/src/tests/ReactiveUI.Primitives.Async.Tests/TransformationOperatorTests.cs b/src/tests/ReactiveUI.Primitives.Async.Tests/TransformationOperatorTests.cs
index 2ba139d..ecf892b 100644
--- a/src/tests/ReactiveUI.Primitives.Async.Tests/TransformationOperatorTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Async.Tests/TransformationOperatorTests.cs
@@ -553,7 +553,8 @@ public async Task WhenPrependCancelledBeforeAllValues_ThenEarlyReturn()
received.Add(x);
if (received.Count == 3)
{
- await subscription!.DisposeAsync();
+ await (subscription ?? throw new InvalidOperationException("The subscription is not ready."))
+ .DisposeAsync();
}
},
null);
diff --git a/src/tests/ReactiveUI.Primitives.Maui.Reactive.Tests/MauiDispatcherSequencerTests.cs b/src/tests/ReactiveUI.Primitives.Maui.Reactive.Tests/MauiDispatcherSequencerTests.cs
index 8a2ae40..524f185 100644
--- a/src/tests/ReactiveUI.Primitives.Maui.Reactive.Tests/MauiDispatcherSequencerTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Maui.Reactive.Tests/MauiDispatcherSequencerTests.cs
@@ -29,7 +29,7 @@ public async Task ConstructorRejectsNullDispatcher() =>
public async Task ToSequencerValidatesAndAdaptsDispatcher()
{
const IDispatcher nullDispatcher = null!;
- await Assert.That(static () => nullDispatcher!.ToSequencer()).ThrowsExactly();
+ await Assert.That(static () => nullDispatcher.ToSequencer()).ThrowsExactly();
FakeDispatcher dispatcher = new();
var scheduler = dispatcher.ToSequencer();
diff --git a/src/tests/ReactiveUI.Primitives.Maui.Tests/MauiDispatcherSequencerTests.cs b/src/tests/ReactiveUI.Primitives.Maui.Tests/MauiDispatcherSequencerTests.cs
index b99a517..63bac59 100644
--- a/src/tests/ReactiveUI.Primitives.Maui.Tests/MauiDispatcherSequencerTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Maui.Tests/MauiDispatcherSequencerTests.cs
@@ -29,7 +29,7 @@ public async Task ConstructorRejectsNullDispatcher() =>
public async Task ToSequencerValidatesAndAdaptsDispatcher()
{
const IDispatcher nullDispatcher = null!;
- await Assert.That(static () => nullDispatcher!.ToSequencer()).ThrowsExactly();
+ await Assert.That(static () => nullDispatcher.ToSequencer()).ThrowsExactly();
FakeDispatcher dispatcher = new();
var sequencer = dispatcher.ToSequencer();
diff --git a/src/tests/ReactiveUI.Primitives.Tests/AsyncSignalTests.cs b/src/tests/ReactiveUI.Primitives.Tests/AsyncSignalTests.cs
index 5127451..78faedf 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/AsyncSignalTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/AsyncSignalTests.cs
@@ -248,7 +248,7 @@ public async Task AsyncSignalSubscriberChurnLateTerminalsAndDisposalCoverBranche
RecordingWitness asyncFirst = new();
RecordingWitness asyncSecond = new();
using var asyncSubscription = asyncSignal.Subscribe(asyncFirst);
- using var asyncSecondSubscription = asyncSignal.Subscribe(asyncSecond);
+ var asyncSecondSubscription = asyncSignal.Subscribe(asyncSecond);
asyncSecondSubscription.Dispose();
asyncSignal.OnNext(FirstEmittedValue);
asyncSignal.OnCompleted(() => completionFaults++);
diff --git a/src/tests/ReactiveUI.Primitives.Tests/CommandExecutionTests.cs b/src/tests/ReactiveUI.Primitives.Tests/CommandExecutionTests.cs
index 5d99dca..0277449 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/CommandExecutionTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/CommandExecutionTests.cs
@@ -46,7 +46,7 @@ public async Task AwaitingAFailedSynchronousCommandRethrowsTheOriginalException(
await Assert.That(execution.GetAwaiter().IsCompleted).IsTrue();
var thrown = Assert.Throws(() => execution.GetAwaiter().GetResult());
- await Assert.That(thrown!).IsSameReferenceAs(fault);
+ await Assert.That(thrown).IsSameReferenceAs(fault);
}
///
@@ -72,7 +72,7 @@ public async Task ConfigureAwaitPreservesTheOutcomeOfEveryExecutionShape()
using CommandSignal failing = new(() => throw fault);
var configured = failing.ExecuteAsync().ConfigureAwait(false);
var thrown = Assert.Throws(() => configured.GetAwaiter().GetResult());
- await Assert.That(thrown!).IsSameReferenceAs(fault);
+ await Assert.That(thrown).IsSameReferenceAs(fault);
}
///
diff --git a/src/tests/ReactiveUI.Primitives.Tests/ConcurencyTests.cs b/src/tests/ReactiveUI.Primitives.Tests/ConcurencyTests.cs
index 3f8a9e5..5fe4a3d 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/ConcurencyTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/ConcurencyTests.cs
@@ -91,7 +91,7 @@ public async Task TaskPoolScheduleActionCancel()
{
var nt = TaskPoolSequencer.Instance;
var probe = new CancellationProbe();
- using var scheduled = nt.Schedule(probe, CancelDueTime, static p => p.RecordExecution());
+ var scheduled = nt.Schedule(probe, CancelDueTime, static p => p.RecordExecution());
scheduled.Dispose();
var delay = Task.Delay(CancelObservationWindow);
var observed = await Task.WhenAny(probe.Completed.Task, delay);
diff --git a/src/tests/ReactiveUI.Primitives.Tests/ConnectableSignalTests.cs b/src/tests/ReactiveUI.Primitives.Tests/ConnectableSignalTests.cs
index 745bb73..6be8a4b 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/ConnectableSignalTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/ConnectableSignalTests.cs
@@ -56,8 +56,8 @@ public async Task ConnectableShareAndReplayLiveControlSourceSubscriptions()
var shared = cold.ShareLatest();
List first = [];
List second = [];
- using var firstSubscription = shared.Subscribe(first.Add);
- using var secondSubscription = shared.Subscribe(second.Add);
+ var firstSubscription = shared.Subscribe(first.Add);
+ var secondSubscription = shared.Subscribe(second.Add);
source.OnNext(FirstSharedValue);
firstSubscription.Dispose();
source.OnNext(SecondSharedValue);
@@ -263,7 +263,7 @@ public async Task AutoShareDisposesConnectionWhenRefcountDropsDuringConnect()
void OnNext(int _)
{
reentrantReleaseInvoked = true;
- using AutoShareSubscription reentrantRelease = new(shared, Scope.Empty);
+ AutoShareSubscription reentrantRelease = new(shared, Scope.Empty);
reentrantRelease.Dispose();
}
diff --git a/src/tests/ReactiveUI.Primitives.Tests/ObservableMixinsTests.cs b/src/tests/ReactiveUI.Primitives.Tests/ObservableMixinsTests.cs
index 47bcca8..d78a86c 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/ObservableMixinsTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/ObservableMixinsTests.cs
@@ -141,7 +141,7 @@ public async Task WhenSubscriptionIsDisposed_ThenSourceAndOtherAreDisposed()
var otherDisposable = new RecordingDisposable();
var source = new TrackingObservable(sourceDisposable);
var other = new TrackingObservable(otherDisposable);
- using var subscription = LinqExtensions.TakeUntil(source, other)
+ var subscription = LinqExtensions.TakeUntil(source, other)
.Subscribe(static _ => { }, ThrowUnexpectedError, static () => { });
subscription.Dispose();
diff --git a/src/tests/ReactiveUI.Primitives.Tests/PrioritySemaphoreSignalTests.cs b/src/tests/ReactiveUI.Primitives.Tests/PrioritySemaphoreSignalTests.cs
index 7c228e5..4f4fcb7 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/PrioritySemaphoreSignalTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/PrioritySemaphoreSignalTests.cs
@@ -80,7 +80,7 @@ public async Task QueuedValuesDrainByPriorityWhenCapacityIsAvailable()
{
using var signal = new PrioritySemaphoreSignal(0);
var observer = new RecordingObserver();
- using var subscription = signal.Subscribe(observer);
+ var subscription = signal.Subscribe(observer);
await Assert.That(signal.HasObservers).IsTrue();
signal.OnNext(ThirdValue);
@@ -132,7 +132,7 @@ public async Task ReleaseDoesNotAllowNegativeCount()
{
using var signal = new PrioritySemaphoreSignal(1);
var observer = new RecordingObserver();
- using var subscription = signal.Subscribe(observer);
+ var subscription = signal.Subscribe(observer);
signal.OnNext(FirstValue);
@@ -209,7 +209,7 @@ public async Task ConcurrentOperationsDoNotNotifyObserverConcurrently()
{
using var signal = new PrioritySemaphoreSignal(InitialDrainCapacity);
var observer = new ConcurrencyProbe();
- using var subscription = signal.Subscribe(observer);
+ var subscription = signal.Subscribe(observer);
for (var i = 0; i < SeededValueCount; i++)
{
signal.OnNext(i);
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SafeWitnessTests.cs b/src/tests/ReactiveUI.Primitives.Tests/SafeWitnessTests.cs
index 61e5557..7555363 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SafeWitnessTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SafeWitnessTests.cs
@@ -92,7 +92,7 @@ public async Task DelegateWitnessMadeSafeStopsAfterItsValueCallbackThrows()
// A second push must not reach the callback, so it must not throw either.
safe.OnNext(LateValue);
- await Assert.That(thrown!.Message).IsEqualTo("next-failed");
+ await Assert.That(thrown.Message).IsEqualTo("next-failed");
await Assert.That(calls).IsEqualTo(1);
}
@@ -153,6 +153,6 @@ public async Task CancelFreeSafeWitnessStopsAfterTheObserverThrows()
// The witness has latched stopped, so this must be a silent no-op rather than a second throw.
safe.OnNext(LateValue);
- await Assert.That(thrown!.Message).IsEqualTo("observer-next");
+ await Assert.That(thrown.Message).IsEqualTo("observer-next");
}
}
diff --git a/src/tests/ReactiveUI.Primitives.Tests/ScheduledSignalTests.cs b/src/tests/ReactiveUI.Primitives.Tests/ScheduledSignalTests.cs
index ae14971..3df19fd 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/ScheduledSignalTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/ScheduledSignalTests.cs
@@ -90,8 +90,8 @@ public async Task DefaultObserverIsRestoredAfterLastSubscriberDisposes()
var firstObserver = new RecordingObserver();
var secondObserver = new RecordingObserver();
- using var firstSubscription = signal.Subscribe(firstObserver);
- using var secondSubscription = signal.Subscribe(secondObserver);
+ var firstSubscription = signal.Subscribe(firstObserver);
+ var secondSubscription = signal.Subscribe(secondObserver);
signal.OnNext(SecondValue);
sequencer.DrainAll();
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SignalFactoriesTests.DefaultSequencer.cs b/src/tests/ReactiveUI.Primitives.Tests/SignalFactoriesTests.DefaultSequencer.cs
index 8e6384d..1cd4443 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SignalFactoriesTests.DefaultSequencer.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SignalFactoriesTests.DefaultSequencer.cs
@@ -78,10 +78,7 @@ public async Task StartWithoutASequencerRunsTheWorkOnTheDefaultSequencer()
// A void method group is what selects Start(Action); a lambda over 'actionRuns++' is a
// Func and would bind to the generic Start overload instead.
- void RunAction()
- {
- actionRuns++;
- }
+ void RunAction() => actionRuns++;
using var actionSubscription = Signal.Start(RunAction).Subscribe(actionValues.Add);
await TestPolling.SpinUntil(() => actionValues.Count == 1, DefaultSequencerTimeout);
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SignalFactoriesTests.Scheduling.cs b/src/tests/ReactiveUI.Primitives.Tests/SignalFactoriesTests.Scheduling.cs
index a4af059..dc084c7 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SignalFactoriesTests.Scheduling.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SignalFactoriesTests.Scheduling.cs
@@ -29,10 +29,7 @@ public async Task StartActionDefersToTheSequencerThenCompletesWithASingleUnit()
VirtualClock clock = new();
RecordingWitness witness = new();
var runCount = 0;
- void Run()
- {
- runCount++;
- }
+ void Run() => runCount++;
using var subscription = Signal.Start(Run, clock).Subscribe(witness);
@@ -78,10 +75,7 @@ public async Task StartActionOnTheCurrentThreadSequencerRunsThroughTheTrampoline
RecordingWitness witness = new();
var runCount = 0;
- void Run()
- {
- runCount++;
- }
+ void Run() => runCount++;
using var subscription = Signal.Start(Run, Sequencer.CurrentThread).Subscribe(witness);
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SignalFactoriesTests.cs b/src/tests/ReactiveUI.Primitives.Tests/SignalFactoriesTests.cs
index 5ab0f2b..e334489 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SignalFactoriesTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SignalFactoriesTests.cs
@@ -142,7 +142,7 @@ public async Task FactoryAliasesScheduledRangesTasksAndTimersCoverRemainderBranc
await TestPolling.SpinUntil(
() => taskValues.Count == One && taskErrors.Count == Two,
TimeSpan.FromSeconds(TimeoutSeconds));
- using var disposedTaskSubscription = Signal.FromTask(Task.FromResult(NinetyNine))
+ var disposedTaskSubscription = Signal.FromTask(Task.FromResult(NinetyNine))
.Subscribe(_ => taskValues.Add(NinetyNine));
disposedTaskSubscription.Dispose();
_ = Signal.After(TimeSpan.FromTicks(Two), clock).Subscribe(afterValues.Add);
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SignalFromTaskTest.cs b/src/tests/ReactiveUI.Primitives.Tests/SignalFromTaskTest.cs
index 4878c62..86be8b0 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SignalFromTaskTest.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SignalFromTaskTest.cs
@@ -542,7 +542,7 @@ await Task.Delay(CommandDelayMilliseconds, cts.Token)
return Signal.Fail(ex);
}).OnCleanup(() => RecordStatus(statusTrail, ref position, ShouldAlwaysComeHere));
var result = false;
- using var subscription = fixture.Subscribe(_ => result = true);
+ var subscription = fixture.Subscribe(_ => result = true);
await Task.Delay(InitialDelayMilliseconds).ConfigureAwait(true);
await Assert.That(StatusMessages(statusTrail)).Contains(StartedCommand);
await Task.Delay(CommandDelayMilliseconds).ConfigureAwait(true);
@@ -580,7 +580,7 @@ await Task.Delay(CommandDelayMilliseconds, cts.Token)
return Signal.Fail(ex);
}).OnCleanup(() => RecordStatus(statusTrail, ref position, ShouldAlwaysComeHere));
var result = false;
- using var subscription = fixture.Subscribe(_ => result = true);
+ var subscription = fixture.Subscribe(_ => result = true);
await Task.Delay(InitialDelayMilliseconds).ConfigureAwait(true);
await Assert.That(StatusMessages(statusTrail)).Contains(StartedCommand);
subscription.Dispose();
@@ -661,7 +661,7 @@ public async Task SignalFromTaskHandlesCancellationInBase()
RecordStatus(statusTrail, ref position, ExceptionShouldBeHere);
return Signal.Fail(ex);
}).OnCleanup(() => RecordStatus(statusTrail, ref position, ShouldAlwaysComeHere));
- using var subscription = fixture.Subscribe();
+ var subscription = fixture.Subscribe();
await Task.Delay(InitialDelayMilliseconds).ConfigureAwait(true);
await Assert.That(StatusMessages(statusTrail)).Contains(StartedCommand);
subscription.Dispose();
@@ -729,7 +729,7 @@ await Task.Delay(CommandDelayMilliseconds, cts.Token)
return Signal.Fail(ex);
}).OnCleanup(() => RecordStatus(statusTrail, ref position, ShouldAlwaysComeHere));
var result = false;
- using var subscription = fixture.Subscribe(_ => result = true);
+ var subscription = fixture.Subscribe(_ => result = true);
await Task.Delay(InitialDelayMilliseconds).ConfigureAwait(true);
await Assert.That(StatusMessages(statusTrail)).Contains(StartedCommand);
await Task.Delay(CommandDelayMilliseconds).ConfigureAwait(true);
@@ -767,7 +767,7 @@ await Task.Delay(CommandDelayMilliseconds, cts.Token)
return Signal.Fail(ex);
}).OnCleanup(() => RecordStatus(statusTrail, ref position, ShouldAlwaysComeHere));
var result = false;
- using var subscription = fixture.Subscribe(_ => result = true);
+ var subscription = fixture.Subscribe(_ => result = true);
await Task.Delay(InitialDelayMilliseconds).ConfigureAwait(true);
await Assert.That(StatusMessages(statusTrail)).Contains(StartedCommand);
subscription.Dispose();
@@ -848,7 +848,7 @@ public async Task SignalFromTask_T_HandlesCancellationInBase()
RecordStatus(statusTrail, ref position, ExceptionShouldBeHere);
return Signal.Fail(ex);
}).OnCleanup(() => RecordStatus(statusTrail, ref position, ShouldAlwaysComeHere));
- using var subscription = fixture.Subscribe();
+ var subscription = fixture.Subscribe();
await Task.Delay(InitialDelayMilliseconds).ConfigureAwait(true);
await Assert.That(StatusMessages(statusTrail)).Contains(StartedCommand);
subscription.Dispose();
@@ -909,7 +909,7 @@ public async Task ImmediateTaskSignalErrorsWhenTheTokenIsCancelledBeforeTheResul
ConcurrentQueue values = new();
ConcurrentQueue errors = new();
_ = taskSignal.Subscribe(values.Enqueue, errors.Enqueue, static () => { });
- await taskSignal.CancellationTokenSource!.CancelAsync();
+ await taskSignal.CancellationTokenSource.CancelAsync();
completion.SetResult(SuccessValue);
await TestPolling.SpinUntil(() => !errors.IsEmpty, PollTimeout).ConfigureAwait(false);
await Assert.That(errors.Count).IsEqualTo(1);
@@ -1067,7 +1067,7 @@ private static void RecordCancellationCleanup(StatusTrail statusTrail, ref int p
/// A representing the asynchronous operation.
private static async Task CancelAfterDelayAsync(CancellationTokenSource cts)
{
- await Task.Delay(TokenCancellationDelayMilliseconds).ConfigureAwait(false);
+ await Task.Delay(TokenCancellationDelayMilliseconds, cts.Token).ConfigureAwait(false);
await cts.CancelAsync().ConfigureAwait(false);
}
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SignalOperatorMixinsTests.cs b/src/tests/ReactiveUI.Primitives.Tests/SignalOperatorMixinsTests.cs
index 08ad7d9..99a8b0d 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SignalOperatorMixinsTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SignalOperatorMixinsTests.cs
@@ -566,8 +566,8 @@ public async Task TaskChainDirectSignalHandlesErrorsAndDisposal()
TaskCompletionSource pending = new(TaskCreationOptions.RunContinuationsAsynchronously);
Signal> disposableSource = new();
RecordingWitness disposed = new();
- using (var disposable = disposableSource.Chain().Subscribe(disposed))
{
+ var disposable = disposableSource.Chain().Subscribe(disposed);
disposableSource.OnNext(pending.Task);
disposable.Dispose();
pending.SetResult(Five);
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SignalRecoverTests.cs b/src/tests/ReactiveUI.Primitives.Tests/SignalRecoverTests.cs
index 26eb997..9a63ed6 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SignalRecoverTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SignalRecoverTests.cs
@@ -88,7 +88,7 @@ public async Task OnCleanupRunsTheActionWhenSubscribingToTheSourceThrows()
var caught = Assert.Throws(() =>
failingSource.OnCleanup(() => cleanupRuns++).Subscribe(static _ => { }));
- await Assert.That(caught!).IsSameReferenceAs(expected);
+ await Assert.That(caught).IsSameReferenceAs(expected);
await Assert.That(cleanupRuns).IsEqualTo(1);
}
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SignalTests.cs b/src/tests/ReactiveUI.Primitives.Tests/SignalTests.cs
index f5431be..7c465db 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SignalTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SignalTests.cs
@@ -477,9 +477,9 @@ public async Task SubjectsCoverMultipleSubscriberChurnLateTerminalsAndDisposalBr
RecordingWitness third = new();
RecordingWitness fourth = new();
List actionValues = [];
- using var action = subject.Subscribe(actionValues.Add);
+ var action = subject.Subscribe(actionValues.Add);
using var firstSubscription = subject.Subscribe(first);
- using var secondSubscription = subject.Subscribe(second);
+ var secondSubscription = subject.Subscribe(second);
using var thirdSubscription = subject.Subscribe(third);
using var fourthSubscription = subject.Subscribe(fourth);
secondSubscription.Dispose();
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SinkObserverTests.cs b/src/tests/ReactiveUI.Primitives.Tests/SinkObserverTests.cs
index a97c94a..6db45b4 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SinkObserverTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SinkObserverTests.cs
@@ -523,7 +523,7 @@ public async Task BufferSinkReleasesTheUpstreamWhenTheObserverThrowsOnACompleted
var thrown = Assert.Throws(() => sink.OnNext(Two));
- await Assert.That(thrown!.Message).IsEqualTo(ObserverNextMessage);
+ await Assert.That(thrown.Message).IsEqualTo(ObserverNextMessage);
await Assert.That(subscription.DisposeCount).IsEqualTo(1);
}
@@ -545,7 +545,7 @@ public async Task BufferSinkDropsValuesFromASourceThatKeepsPushingAfterTheObserv
source.Next(One);
var thrown = Assert.Throws(() => source.Next(Two));
- await Assert.That(thrown!.Message).IsEqualTo(ObserverNextMessage);
+ await Assert.That(thrown.Message).IsEqualTo(ObserverNextMessage);
await Assert.That(observer.NextCount).IsEqualTo(One);
// The sink disposed its upstream; this source ignores disposal and pushes on regardless.
@@ -683,7 +683,7 @@ private static async Task AssertObserverFailureReleasesUpstream(
{
var thrown = Assert.Throws(() => sink.OnNext(1));
- await Assert.That(thrown!.Message).IsEqualTo("observer-next");
+ await Assert.That(thrown.Message).IsEqualTo("observer-next");
await Assert.That(subscription.DisposeCount).IsEqualTo(1);
}
diff --git a/src/tests/ReactiveUI.Primitives.Tests/StateSignalTests.cs b/src/tests/ReactiveUI.Primitives.Tests/StateSignalTests.cs
index 208186f..b6f2203 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/StateSignalTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/StateSignalTests.cs
@@ -124,7 +124,7 @@ public async Task StatefulSignalsReportObserverValueErrorAndDisposalState()
await Assert.That(current).IsEqualTo(InitialStateValue);
Recorder observer = new();
- using var subscription = state.Subscribe(observer);
+ var subscription = state.Subscribe(observer);
await Assert.That(state.HasObservers).IsTrue();
state.OnNext(UpdatedStateValue);
await Assert.That(observer.Values.SequenceEqual([InitialStateValue, UpdatedStateValue])).IsTrue();
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SyncLatestTests.cs b/src/tests/ReactiveUI.Primitives.Tests/SyncLatestTests.cs
index 7bfb912..32b3afb 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SyncLatestTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SyncLatestTests.cs
@@ -242,7 +242,7 @@ public async Task SyncLatestUnsubscribesEarlierSourcesWhenALaterSourceThrowsOnSu
third,
static (a, b, c) => a + b + c);
var thrown = Assert.Throws(() => _ = combined.Subscribe(static _ => { }));
- await Assert.That(thrown!).IsSameReferenceAs(expected);
+ await Assert.That(thrown).IsSameReferenceAs(expected);
await Assert.That(first.HasObservers).IsFalse();
await Assert.That(third.HasObservers).IsFalse();
}
diff --git a/src/tests/ReactiveUI.Primitives.Tests/TaskSignalTests.cs b/src/tests/ReactiveUI.Primitives.Tests/TaskSignalTests.cs
index 26eb271..93dfe02 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/TaskSignalTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/TaskSignalTests.cs
@@ -38,7 +38,7 @@ public async Task TaskSignalCoversCancellationAndDisposeBranches()
[Test]
public async Task TaskSignalCreateWithASchedulerBuildsASignalThatCancelsOnDisposal()
{
- using var taskSignal = TaskSignal.Create(static _ => Signal.Silent(), Sequencer.CurrentThread);
+ var taskSignal = TaskSignal.Create(static _ => Signal.Silent(), Sequencer.CurrentThread);
await Assert.That(taskSignal.IsCancellationRequested).IsFalse();
await Assert.That(taskSignal.IsDisposed).IsFalse();
diff --git a/src/tests/ReactiveUI.Primitives.Tests/UseSignalTests.cs b/src/tests/ReactiveUI.Primitives.Tests/UseSignalTests.cs
index a625cec..a6807bf 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/UseSignalTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/UseSignalTests.cs
@@ -115,7 +115,7 @@ public async Task UseReleasesTheResourceWhenTheObserverThrows()
// The sink has stopped, so this must be a silent no-op rather than a second trip into the observer.
sink.OnNext(LateValue);
- await Assert.That(thrown!.Message).IsEqualTo("observer-next");
+ await Assert.That(thrown.Message).IsEqualTo("observer-next");
await Assert.That(resource.DisposeCount).IsEqualTo(1);
await Assert.That(source.DisposeCount).IsEqualTo(1);
}
From 7738196e9098a6298df2833a143376bc32e61d21 Mon Sep 17 00:00:00 2001
From: Glenn Watson <5834289+glennawatson@users.noreply.github.com>
Date: Sat, 25 Jul 2026 17:27:11 +1000
Subject: [PATCH 3/8] fix: restore null-forgiving expressions
- Revert S8969-driven callback and test rewrites.
- Keep established nullability assertions now that the rule is disabled.
---
.../CancellationTokenPolyfillExtensions.cs | 2 +-
.../Advanced/StartSubscription.cs | 3 +--
src/Primitives.Async.Shared/AsyncContext.cs | 10 ++--------
.../Advanced/FromAsyncExternalCancellation{T}.cs | 5 +----
.../Advanced/FromAsyncSubscription{T}.cs | 3 +--
src/Primitives.Shared/SignalOperatorMixins.cs | 2 +-
.../SignalOperatorParityMixins.cs | 2 +-
.../Signals/SignalExtensions{FromTask}.cs | 15 ++++-----------
.../Signals/Signal{Factories}.cs | 2 +-
src/Primitives.Shared/Signals/Signal{FromTask}.cs | 6 ++----
.../Signals/Signal{GetAwaiter}.cs | 3 +--
src/Primitives.Shared/Signals/TaskSignal{T}.cs | 6 +-----
.../Advanced/BackgroundJobSignal{T}.cs | 3 +--
.../Advanced/FlatMapWitness{TSource,TResult}.cs | 4 +---
.../Advanced/IntervalSubscription.cs | 8 +++-----
.../Advanced/PooledDelaySource.cs | 3 +--
.../Advanced/StartSubscription{TResult}.cs | 3 +--
...atestEnumerableCoordinator{TSource,TResult}.cs | 2 +-
.../Advanced/TaskResultCompletionSource.cs | 3 +--
.../Operators/Expire.cs | 3 +--
.../Signals/CommandSignal{TResult}.cs | 12 +++---------
.../ConcurrencyLimiter.cs | 6 +-----
.../Operators/SelectLatestAsyncObservable.cs | 10 +---------
.../Concurrency/WasmScheduler.cs | 14 +++-----------
.../SynchronizationContextSequencer.cs | 5 +----
.../Concurrency/TaskPoolSequencer.cs | 3 +--
.../Concurrency/ThreadPoolSequencer.cs | 6 ++----
.../Concurrency/WasmSequencer.cs | 3 +--
.../CombiningOperatorTests.cs | 2 +-
.../TakeUntilOperatorTests.CompletionDelegate.cs | 2 +-
.../TakeUntilOperatorTests.cs | 2 +-
.../TaskSignalSubscriptionTests.cs | 3 +--
.../TransformationOperatorTests.cs | 3 +--
.../MauiDispatcherSequencerTests.cs | 2 +-
.../MauiDispatcherSequencerTests.cs | 2 +-
.../CommandExecutionTests.cs | 4 ++--
.../SafeWitnessTests.cs | 4 ++--
.../SignalFromTaskTest.cs | 2 +-
.../SignalRecoverTests.cs | 2 +-
.../SinkObserverTests.cs | 6 +++---
.../SyncLatestTests.cs | 2 +-
.../ReactiveUI.Primitives.Tests/UseSignalTests.cs | 2 +-
42 files changed, 58 insertions(+), 127 deletions(-)
diff --git a/src/Polyfills/CancellationTokenPolyfillExtensions.cs b/src/Polyfills/CancellationTokenPolyfillExtensions.cs
index 225c333..a198a31 100644
--- a/src/Polyfills/CancellationTokenPolyfillExtensions.cs
+++ b/src/Polyfills/CancellationTokenPolyfillExtensions.cs
@@ -31,7 +31,7 @@ internal CancellationTokenRegistration
static boxed =>
{
var (inner, innerState, innerToken) =
- ((Action Callback, object? State, CancellationToken Token))boxed;
+ ((Action Callback, object? State, CancellationToken Token))boxed!;
inner(innerState, innerToken);
},
(callback, state, token),
diff --git a/src/Primitives.Async.Shared/Advanced/StartSubscription.cs b/src/Primitives.Async.Shared/Advanced/StartSubscription.cs
index 1ab2712..3c4c160 100644
--- a/src/Primitives.Async.Shared/Advanced/StartSubscription.cs
+++ b/src/Primitives.Async.Shared/Advanced/StartSubscription.cs
@@ -49,8 +49,7 @@ await Task.Factory.StartNew(
static s =>
{
var (self, observer, cancellationToken) =
- ((StartSubscription, IObserverAsync, CancellationToken))(
- s ?? throw new InvalidOperationException("The start state is missing."));
+ ((StartSubscription, IObserverAsync, CancellationToken))s!;
return self.ExecuteActionAsync(observer, cancellationToken).AsTask();
},
(this, observer, cancellationToken),
diff --git a/src/Primitives.Async.Shared/AsyncContext.cs b/src/Primitives.Async.Shared/AsyncContext.cs
index 795f80f..284e45d 100644
--- a/src/Primitives.Async.Shared/AsyncContext.cs
+++ b/src/Primitives.Async.Shared/AsyncContext.cs
@@ -169,10 +169,7 @@ public void OnCompleted(Action continuation)
var sc = AsyncContext.SynchronizationContext;
if (sc is not null)
{
- sc.Post(
- static state => ((Action)(
- state ?? throw new InvalidOperationException("The continuation is missing."))).Invoke(),
- continuation);
+ sc.Post(static c => ((Action)c!).Invoke(), continuation);
return;
}
@@ -199,10 +196,7 @@ public void OnCompleted(Action continuation)
// path Yield takes by default, so the saving lands on the operator's hot path.
if (ts is null || ts == TaskScheduler.Default)
{
- _ = ThreadPool.UnsafeQueueUserWorkItem(
- static state => ((Action)(
- state ?? throw new InvalidOperationException("The continuation is missing."))).Invoke(),
- continuation);
+ _ = ThreadPool.UnsafeQueueUserWorkItem(static c => ((Action)c!).Invoke(), continuation);
}
}
diff --git a/src/Primitives.Shared/Advanced/FromAsyncExternalCancellation{T}.cs b/src/Primitives.Shared/Advanced/FromAsyncExternalCancellation{T}.cs
index 205172a..1c9c8f6 100644
--- a/src/Primitives.Shared/Advanced/FromAsyncExternalCancellation{T}.cs
+++ b/src/Primitives.Shared/Advanced/FromAsyncExternalCancellation{T}.cs
@@ -64,10 +64,7 @@ internal bool Start()
}
Registration =
- CancellationToken.Register(
- static state => ((FromAsyncExternalCancellation)(
- state ?? throw new InvalidOperationException("The cancellation state is missing."))).Cancel(),
- this);
+ CancellationToken.Register(static state => ((FromAsyncExternalCancellation)state!).Cancel(), this);
return !Lifetime.IsCompleted;
}
diff --git a/src/Primitives.Shared/Advanced/FromAsyncSubscription{T}.cs b/src/Primitives.Shared/Advanced/FromAsyncSubscription{T}.cs
index 73ebf79..1655c02 100644
--- a/src/Primitives.Shared/Advanced/FromAsyncSubscription{T}.cs
+++ b/src/Primitives.Shared/Advanced/FromAsyncSubscription{T}.cs
@@ -101,8 +101,7 @@ internal IDisposable Start()
FromAsyncTaskObservation observation = new(Observer, Lifetime, ExternalCancellation, linkedSource);
_ = task.ContinueWith(
- static (completedTask, state) => ((FromAsyncTaskObservation)(
- state ?? throw new InvalidOperationException("The observation state is missing."))).Observe(completedTask),
+ static (completedTask, state) => ((FromAsyncTaskObservation)state!).Observe(completedTask),
observation,
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
diff --git a/src/Primitives.Shared/SignalOperatorMixins.cs b/src/Primitives.Shared/SignalOperatorMixins.cs
index 22b7414..0d462f4 100644
--- a/src/Primitives.Shared/SignalOperatorMixins.cs
+++ b/src/Primitives.Shared/SignalOperatorMixins.cs
@@ -687,7 +687,7 @@ public IObservable ToSignal()
}
return task.IsFaulted
- ? new ImmediateThrowSignal(task.Exception.InnerException ?? task.Exception)
+ ? new ImmediateThrowSignal(task.Exception!.InnerException ?? task.Exception)
: new TaskInstanceSignal(task);
}
}
diff --git a/src/Primitives.Shared/SignalOperatorParityMixins.cs b/src/Primitives.Shared/SignalOperatorParityMixins.cs
index 90c9a41..890a0aa 100644
--- a/src/Primitives.Shared/SignalOperatorParityMixins.cs
+++ b/src/Primitives.Shared/SignalOperatorParityMixins.cs
@@ -788,7 +788,7 @@ public IObservable ToObservable()
}
return task.IsFaulted
- ? new ImmediateThrowSignal(task.Exception.InnerException ?? task.Exception)
+ ? new ImmediateThrowSignal(task.Exception!.InnerException ?? task.Exception)
: new TaskInstanceSignal(task);
}
diff --git a/src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs b/src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs
index 0b6c9f3..db9a5ee 100644
--- a/src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs
+++ b/src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs
@@ -102,17 +102,10 @@ public async Task HandleCancellation(Action? action)
internal async Task<(TResult Value, bool IsCanceled)> WhenCancelled(CancellationToken cancellationToken)
{
TaskCompletionSource tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
- var registration = cancellationToken.UnsafeRegister(
- static (state, token) =>
- {
- if (state is not TaskCompletionSource source)
- {
- throw new InvalidOperationException("The cancellation state is not a completion source.");
- }
-
- _ = source.TrySetCanceled(token);
- },
- tcs);
+ var registration = cancellationToken.Register(
+ static state => ((TaskCompletionSource)state!).TrySetCanceled(),
+ tcs,
+ false);
var cancellationTask = tcs.Task;
try
diff --git a/src/Primitives.Shared/Signals/Signal{Factories}.cs b/src/Primitives.Shared/Signals/Signal{Factories}.cs
index 2e28016..c59bfcc 100644
--- a/src/Primitives.Shared/Signals/Signal{Factories}.cs
+++ b/src/Primitives.Shared/Signals/Signal{Factories}.cs
@@ -235,7 +235,7 @@ public static IObservable FromTask(Task task)
}
return task.IsFaulted
- ? new ImmediateThrowSignal(task.Exception.InnerException ?? task.Exception)
+ ? new ImmediateThrowSignal(task.Exception!.InnerException ?? task.Exception)
: new TaskInstanceSignal(task);
}
diff --git a/src/Primitives.Shared/Signals/Signal{FromTask}.cs b/src/Primitives.Shared/Signals/Signal{FromTask}.cs
index fe39479..5709405 100644
--- a/src/Primitives.Shared/Signals/Signal{FromTask}.cs
+++ b/src/Primitives.Shared/Signals/Signal{FromTask}.cs
@@ -183,7 +183,7 @@ private static bool TryEmitSynchronously(
return false;
}
- observer.OnError(task.Exception.InnerException ?? task.Exception);
+ observer.OnError(task.Exception!.InnerException ?? task.Exception);
return true;
}
@@ -288,9 +288,7 @@ public void GetOperationCanceled(IObserver observer)
ArgumentExceptionHelper.ThrowIfNull(observer);
_ = SourceCore.Token.Register(
- static state => ((IObserver)(
- state ?? throw new InvalidOperationException("The cancellation observer is missing."))).OnNext(
- new OperationCanceledException()),
+ static state => ((IObserver)state!).OnNext(new OperationCanceledException()),
observer,
false);
}
diff --git a/src/Primitives.Shared/Signals/Signal{GetAwaiter}.cs b/src/Primitives.Shared/Signals/Signal{GetAwaiter}.cs
index acf703c..6aa4113 100644
--- a/src/Primitives.Shared/Signals/Signal{GetAwaiter}.cs
+++ b/src/Primitives.Shared/Signals/Signal{GetAwaiter}.cs
@@ -121,8 +121,7 @@ internal static void RegisterCancelation(
var ctr = token.Register(
static state =>
{
- var (subscription, subject, token) = ((IDisposable, IAwaitSignal, CancellationToken))(
- state ?? throw new InvalidOperationException("The await cancellation state is missing."));
+ var (subscription, subject, token) = ((IDisposable, IAwaitSignal, CancellationToken))state!;
subscription.Dispose();
_ = Cancel(subject, token);
},
diff --git a/src/Primitives.Shared/Signals/TaskSignal{T}.cs b/src/Primitives.Shared/Signals/TaskSignal{T}.cs
index cf5538a..88070d4 100644
--- a/src/Primitives.Shared/Signals/TaskSignal{T}.cs
+++ b/src/Primitives.Shared/Signals/TaskSignal{T}.cs
@@ -56,11 +56,7 @@ private TaskSignal(ISequencer? sequencer, CancellationTokenSource? cancellationT
/// The observer.
public void GetOperationCanceled(IObserver observer) =>
CancellationTokenSource?.Token
- .Register(
- static state => ((IObserver)(
- state ?? throw new InvalidOperationException("The cancellation observer is missing."))).OnNext(
- new OperationCanceledException()),
- observer)
+ .Register(static o => ((IObserver)o!).OnNext(new OperationCanceledException()), observer)
.DisposeWith(_cleanUp);
/// Subscribes the specified observer.
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/BackgroundJobSignal{T}.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/BackgroundJobSignal{T}.cs
index 3fedca7..9f00898 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/BackgroundJobSignal{T}.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/BackgroundJobSignal{T}.cs
@@ -76,8 +76,7 @@ await Task.Factory.StartNew(
static s =>
{
var (self, observer, cancellationToken) =
- ((BackgroundJobSignal, IObserverAsync, CancellationToken))(
- s ?? throw new InvalidOperationException("The background-job state is missing."));
+ ((BackgroundJobSignal, IObserverAsync, CancellationToken))s!;
return self.Job(observer, cancellationToken).AsTask();
},
(this, observer, cancellationToken),
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/FlatMapWitness{TSource,TResult}.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/FlatMapWitness{TSource,TResult}.cs
index 2969d91..6f4fcbf 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/FlatMapWitness{TSource,TResult}.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/FlatMapWitness{TSource,TResult}.cs
@@ -37,9 +37,7 @@ protected override async ValueTask OnNextAsyncCore(TSource value, CancellationTo
{
var inner = SyncSelector is not null
? SyncSelector(value)
- : await (AsyncSelector ?? throw new InvalidOperationException("The flat-map selector is missing."))(
- value,
- cancellationToken).ConfigureAwait(false);
+ : await AsyncSelector!(value, cancellationToken).ConfigureAwait(false);
await Coordinator.SubscribeInnerAsync(inner).ConfigureAwait(false);
}
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/IntervalSubscription.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/IntervalSubscription.cs
index 312ed43..e514439 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/IntervalSubscription.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/IntervalSubscription.cs
@@ -54,8 +54,7 @@ private async ValueTask DelayWithProviderAsync(CancellationToken cancellationTok
{
TaskCompletionSource tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
await using var tp = TimeProvider!.CreateTimer(
- static state => ((TaskCompletionSource)(
- state ?? throw new InvalidOperationException("The interval state is missing."))).TrySetResult(true),
+ static x => ((TaskCompletionSource)x!).TrySetResult(true),
tcs,
Period,
Timeout.InfiniteTimeSpan);
@@ -65,8 +64,7 @@ private async ValueTask DelayWithProviderAsync(CancellationToken cancellationTok
cancellationToken.Register(
static x =>
{
- var (tcs, ct) = ((TaskCompletionSource, CancellationToken))(
- x ?? throw new InvalidOperationException("The interval cancellation state is missing."));
+ var (tcs, ct) = ((TaskCompletionSource, CancellationToken))x!;
_ = tcs.TrySetCanceled(ct);
},
(tcs, cancellationToken));
@@ -75,7 +73,7 @@ private async ValueTask DelayWithProviderAsync(CancellationToken cancellationTok
cancellationToken.Register(
static x =>
{
- var (tcs, ct) = ((TaskCompletionSource, CancellationToken))x;
+ var (tcs, ct) = ((TaskCompletionSource, CancellationToken))x!;
_ = tcs.TrySetCanceled(ct);
},
(tcs, cancellationToken));
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/PooledDelaySource.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/PooledDelaySource.cs
index 93000ca..9c2f2f3 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/PooledDelaySource.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/PooledDelaySource.cs
@@ -95,8 +95,7 @@ public ValueTask BeginAsync(TimeSpan delay, TimeProvider timeProvider, Cancellat
// some test / benchmark providers); in that case _completed flips to Claimed before this
// call returns.
_timer = timeProvider.CreateTimer(
- static state => ((PooledDelaySource)(
- state ?? throw new InvalidOperationException("The delay state is missing."))).OnTimerFired(),
+ static state => ((PooledDelaySource)state!).OnTimerFired(),
this,
delay,
Timeout.InfiniteTimeSpan);
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/StartSubscription{TResult}.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/StartSubscription{TResult}.cs
index 96dd8b8..c4b0729 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/StartSubscription{TResult}.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/StartSubscription{TResult}.cs
@@ -46,8 +46,7 @@ await Task.Factory.StartNew(
static s =>
{
var (self, observer, cancellationToken) =
- ((StartSubscription, IObserverAsync, CancellationToken))(
- s ?? throw new InvalidOperationException("The start state is missing."));
+ ((StartSubscription, IObserverAsync, CancellationToken))s!;
return self.ExecuteFunctionAsync(observer, cancellationToken).AsTask();
},
(this, observer, cancellationToken),
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/SyncLatestEnumerableCoordinator{TSource,TResult}.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/SyncLatestEnumerableCoordinator{TSource,TResult}.cs
index 249462c..93d3c98 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/SyncLatestEnumerableCoordinator{TSource,TResult}.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/SyncLatestEnumerableCoordinator{TSource,TResult}.cs
@@ -121,7 +121,7 @@ internal async ValueTask OnNextAsync(int index, TSource indexValue, Cancellation
for (var i = 0; i < Values.Length; i++)
{
- SnapshotBuffer[i] = Values[i].Value;
+ SnapshotBuffer[i] = Values[i].Value!;
}
TResult projected;
diff --git a/src/ReactiveUI.Primitives.Async.Core/Advanced/TaskResultCompletionSource.cs b/src/ReactiveUI.Primitives.Async.Core/Advanced/TaskResultCompletionSource.cs
index e716e16..ba0cfa3 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Advanced/TaskResultCompletionSource.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Advanced/TaskResultCompletionSource.cs
@@ -76,8 +76,7 @@ private CancellationTokenRegistration RegisterCancellation() =>
_cancellationToken.Register(
static state =>
{
- var source = (TaskResultCompletionSource)(
- state ?? throw new InvalidOperationException("The task result state is missing."));
+ var source = (TaskResultCompletionSource)state!;
_ = source._taskSource.TrySetException(new OperationCanceledException(source._cancellationToken));
},
this);
diff --git a/src/ReactiveUI.Primitives.Async.Core/Operators/Expire.cs b/src/ReactiveUI.Primitives.Async.Core/Operators/Expire.cs
index f7b6340..542823f 100644
--- a/src/ReactiveUI.Primitives.Async.Core/Operators/Expire.cs
+++ b/src/ReactiveUI.Primitives.Async.Core/Operators/Expire.cs
@@ -89,8 +89,7 @@ internal void StartTimer(CancellationToken cancellationToken)
try
{
_timer = timeProvider.CreateTimer(
- static state => ((TimeoutWitness)(
- state ?? throw new InvalidOperationException("The timeout state is missing."))).OnTimerFired(),
+ static state => ((TimeoutWitness)state!).OnTimerFired(),
this,
dueTime,
System.Threading.Timeout.InfiniteTimeSpan);
diff --git a/src/ReactiveUI.Primitives.Core/Signals/CommandSignal{TResult}.cs b/src/ReactiveUI.Primitives.Core/Signals/CommandSignal{TResult}.cs
index fb1c03b..dd980e6 100644
--- a/src/ReactiveUI.Primitives.Core/Signals/CommandSignal{TResult}.cs
+++ b/src/ReactiveUI.Primitives.Core/Signals/CommandSignal{TResult}.cs
@@ -157,10 +157,7 @@ public CommandExecution ExecuteAsync(CancellationToken cancellationToke
return _executeSync is not null
? new(ExecuteSync(cancellationToken))
- : new CommandExecution(
- ExecuteAsyncCore(
- _executeAsync ?? throw new InvalidOperationException("The command has no execution delegate."),
- cancellationToken));
+ : new CommandExecution(ExecuteAsyncCore(cancellationToken));
}
catch (Exception error)
{
@@ -272,17 +269,14 @@ private TResult ExecuteSync(CancellationToken cancellationToken)
}
/// Executes the asynchronous command path.
- /// The constructor-selected delegate, guaranteed non-null for this path.
/// Cancellation token for the operation.
/// The command result.
- private async Task ExecuteAsyncCore(
- Func> executeAsync,
- CancellationToken cancellationToken)
+ private async Task ExecuteAsyncCore(CancellationToken cancellationToken)
{
BeginExecution();
try
{
- var result = await executeAsync(cancellationToken).ConfigureAwait(false);
+ var result = await _executeAsync!(cancellationToken).ConfigureAwait(false);
PublishResult(result);
return result;
}
diff --git a/src/ReactiveUI.Primitives.Extensions.Core/ConcurrencyLimiter.cs b/src/ReactiveUI.Primitives.Extensions.Core/ConcurrencyLimiter.cs
index 881f6ff..dd12056 100644
--- a/src/ReactiveUI.Primitives.Extensions.Core/ConcurrencyLimiter.cs
+++ b/src/ReactiveUI.Primitives.Extensions.Core/ConcurrencyLimiter.cs
@@ -155,11 +155,7 @@ private void PullNextTask(Subscription subscription)
_rator.Current?.ContinueWith(
static (ant, state) =>
{
- if (state is not Subscription sub)
- {
- throw new InvalidOperationException("The continuation state is not a subscription.");
- }
-
+ var sub = (Subscription)state!;
sub.Limiter.ProcessTaskCompletion(sub, ant);
},
subscription,
diff --git a/src/ReactiveUI.Primitives.Extensions.Core/Operators/SelectLatestAsyncObservable.cs b/src/ReactiveUI.Primitives.Extensions.Core/Operators/SelectLatestAsyncObservable.cs
index 6ddf11d..7385798 100644
--- a/src/ReactiveUI.Primitives.Extensions.Core/Operators/SelectLatestAsyncObservable.cs
+++ b/src/ReactiveUI.Primitives.Extensions.Core/Operators/SelectLatestAsyncObservable.cs
@@ -111,15 +111,7 @@ public void OnCompleted()
}
_ = toAwait.ContinueWith(
- static (_, state) =>
- {
- if (state is not SelectLatestAsyncSink sink)
- {
- throw new InvalidOperationException("The continuation state is not a select-latest sink.");
- }
-
- sink.SignalCompleted();
- },
+ static (_, s) => ((SelectLatestAsyncSink)s!).SignalCompleted(),
this,
TaskScheduler.Default);
}
diff --git a/src/ReactiveUI.Primitives.Reactive/Concurrency/WasmScheduler.cs b/src/ReactiveUI.Primitives.Reactive/Concurrency/WasmScheduler.cs
index 6d63e83..6fa9d2d 100644
--- a/src/ReactiveUI.Primitives.Reactive/Concurrency/WasmScheduler.cs
+++ b/src/ReactiveUI.Primitives.Reactive/Concurrency/WasmScheduler.cs
@@ -63,8 +63,7 @@ public sealed class WasmScheduler : LocalScheduler, ISchedulerPeriodic, IDisposa
"The drain timer is created disarmed, so nothing can call back into it until Schedule arms it after construction.")]
internal WasmScheduler() =>
_drainTimer = new(
- static state => ((WasmScheduler)(
- state ?? throw new InvalidOperationException("The scheduler state is missing."))).RunDrain(),
+ static state => ((WasmScheduler)state!).RunDrain(),
this,
Timeout.InfiniteTimeSpan,
Timeout.InfiniteTimeSpan);
@@ -125,13 +124,7 @@ public override IDisposable Schedule(
// The timer roots itself while armed through the callback's target (the work item), which stores the
// timer; the item's Dispose cancels and releases it.
- item.AttachTimer(
- new(
- static state => ((IReadyWorkItem)(
- state ?? throw new InvalidOperationException("The work-item state is missing."))).Run(),
- item,
- dt,
- Timeout.InfiniteTimeSpan));
+ item.AttachTimer(new(static s => ((IReadyWorkItem)s!).Run(), item, dt, Timeout.InfiniteTimeSpan));
return item;
}
@@ -424,8 +417,7 @@ internal static PeriodicWorkItem Start(TState state, TimeSpan period, Fu
{
PeriodicWorkItem item = new(state, action);
Timer timer = new(
- static state => ((PeriodicWorkItem)(
- state ?? throw new InvalidOperationException("The periodic state is missing."))).Tick(),
+ static s => ((PeriodicWorkItem)s!).Tick(),
item,
Timeout.InfiniteTimeSpan,
Timeout.InfiniteTimeSpan);
diff --git a/src/ReactiveUI.Primitives/Concurrency/SynchronizationContextSequencer.cs b/src/ReactiveUI.Primitives/Concurrency/SynchronizationContextSequencer.cs
index a4cc66e..85da073 100644
--- a/src/ReactiveUI.Primitives/Concurrency/SynchronizationContextSequencer.cs
+++ b/src/ReactiveUI.Primitives/Concurrency/SynchronizationContextSequencer.cs
@@ -40,10 +40,7 @@ public void Schedule(IWorkItem item)
{
ArgumentExceptionHelper.ThrowIfNull(item);
- Context.Post(
- static state => ExecutePosted((IWorkItem)(
- state ?? throw new InvalidOperationException("The posted work item is missing."))),
- item);
+ Context.Post(static state => ExecutePosted((IWorkItem)state!), item);
}
///
diff --git a/src/ReactiveUI.Primitives/Concurrency/TaskPoolSequencer.cs b/src/ReactiveUI.Primitives/Concurrency/TaskPoolSequencer.cs
index 770bbed..1d928ef 100644
--- a/src/ReactiveUI.Primitives/Concurrency/TaskPoolSequencer.cs
+++ b/src/ReactiveUI.Primitives/Concurrency/TaskPoolSequencer.cs
@@ -50,8 +50,7 @@ public void Schedule(IWorkItem item)
ArgumentExceptionHelper.ThrowIfNull(item);
_ = _taskFactory.StartNew(
- static state => ((DispatchState)(
- state ?? throw new InvalidOperationException("The dispatch state is missing."))).Run(),
+ static state => ((DispatchState)state!).Run(),
new DispatchState(this, item),
_taskFactory.CancellationToken,
_taskFactory.CreationOptions,
diff --git a/src/ReactiveUI.Primitives/Concurrency/ThreadPoolSequencer.cs b/src/ReactiveUI.Primitives/Concurrency/ThreadPoolSequencer.cs
index d5c8b27..af37f14 100644
--- a/src/ReactiveUI.Primitives/Concurrency/ThreadPoolSequencer.cs
+++ b/src/ReactiveUI.Primitives/Concurrency/ThreadPoolSequencer.cs
@@ -17,8 +17,7 @@ public sealed class ThreadPoolSequencer : ISequencer, IDisposable
public static readonly ThreadPoolSequencer Instance = new();
/// Cached queue callback for immediate work.
- private static readonly WaitCallback ImmediateCallback = static state => ExecuteQueued(
- (IWorkItem)(state ?? throw new InvalidOperationException("The queued work item is missing.")));
+ private static readonly WaitCallback ImmediateCallback = static state => ExecuteQueued((IWorkItem)state!);
/// Guards access to delayed work.
private readonly Lock _gate = new();
@@ -48,8 +47,7 @@ public sealed class ThreadPoolSequencer : ISequencer, IDisposable
"The timer is created disarmed, so nothing can call back into it until Schedule arms it after construction.")]
internal ThreadPoolSequencer() =>
_timer = new(
- static state => ((ThreadPoolSequencer)(
- state ?? throw new InvalidOperationException("The sequencer state is missing."))).RunDue(),
+ static state => ((ThreadPoolSequencer)state!).RunDue(),
this,
Timeout.InfiniteTimeSpan,
Timeout.InfiniteTimeSpan);
diff --git a/src/ReactiveUI.Primitives/Concurrency/WasmSequencer.cs b/src/ReactiveUI.Primitives/Concurrency/WasmSequencer.cs
index aab3f19..9f12b2d 100644
--- a/src/ReactiveUI.Primitives/Concurrency/WasmSequencer.cs
+++ b/src/ReactiveUI.Primitives/Concurrency/WasmSequencer.cs
@@ -49,8 +49,7 @@ public sealed class WasmSequencer : ISequencer, IDisposable
internal WasmSequencer()
{
_timer = new(
- static state => ((WasmSequencer)(
- state ?? throw new InvalidOperationException("The sequencer state is missing."))).RunDrain(),
+ static state => ((WasmSequencer)state!).RunDrain(),
this,
Timeout.InfiniteTimeSpan,
Timeout.InfiniteTimeSpan);
diff --git a/src/tests/ReactiveUI.Primitives.Async.Tests/CombiningOperatorTests.cs b/src/tests/ReactiveUI.Primitives.Async.Tests/CombiningOperatorTests.cs
index 9b7f919..29f7845 100644
--- a/src/tests/ReactiveUI.Primitives.Async.Tests/CombiningOperatorTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Async.Tests/CombiningOperatorTests.cs
@@ -152,7 +152,7 @@ private sealed class ThrowingEnumerator : IEnumerator>
public IObservableAsync Current => null!;
///
- object System.Collections.IEnumerator.Current => Current;
+ object System.Collections.IEnumerator.Current => Current!;
///
public bool MoveNext() => throw new InvalidOperationException("enumerator MoveNext boom");
diff --git a/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.CompletionDelegate.cs b/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.CompletionDelegate.cs
index b5e243d..63e5d14 100644
--- a/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.CompletionDelegate.cs
+++ b/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.CompletionDelegate.cs
@@ -725,7 +725,7 @@ public async Task WhenTakeUntilCompletionDelegateNotifiesTwice_ThenSecondNotific
notifyStop!(Result.Success);
await firstCompletion.Task.WaitAsync(WaitTimeout);
- notifyStop(Result.Failure(new InvalidOperationException("second stop")));
+ notifyStop!(Result.Failure(new InvalidOperationException("second stop")));
var leaked = await AsyncTestHelpers.WaitForConditionAsync(
() => errors.Count > 0 || completions.Count > 1,
SecondNotificationSettleWindow);
diff --git a/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.cs b/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.cs
index 00d63db..6d9f3fa 100644
--- a/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Async.Tests/TakeUntilOperatorTests.cs
@@ -204,7 +204,7 @@ public async Task WhenTakeUntilObservableDisposed_ThenStopsEmissions()
public void WhenTaskStopSignalNullSource_ThenThrowsArgumentNull()
{
const IObservableAsync Source = null!;
- _ = Assert.Throws(static () => Source.TakeUntil(Task.CompletedTask));
+ _ = Assert.Throws(static () => Source!.TakeUntil(Task.CompletedTask));
}
/// Tests that task failure with SourceFailsWhenOtherFails=true completes with failure.
diff --git a/src/tests/ReactiveUI.Primitives.Async.Tests/TaskSignalSubscriptionTests.cs b/src/tests/ReactiveUI.Primitives.Async.Tests/TaskSignalSubscriptionTests.cs
index a4853a4..196814a 100644
--- a/src/tests/ReactiveUI.Primitives.Async.Tests/TaskSignalSubscriptionTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Async.Tests/TaskSignalSubscriptionTests.cs
@@ -24,8 +24,7 @@ public async Task WhenDisposedReentrantlyAfterThreadHop_ThenDoesNotDeadlock()
{
await subscriptionReady.Task.ConfigureAwait(false);
await Task.Yield();
- await (subscription ?? throw new InvalidOperationException("The subscription is not ready."))
- .DisposeAsync().ConfigureAwait(false);
+ await subscription!.DisposeAsync().ConfigureAwait(false);
disposed.SetResult();
});
diff --git a/src/tests/ReactiveUI.Primitives.Async.Tests/TransformationOperatorTests.cs b/src/tests/ReactiveUI.Primitives.Async.Tests/TransformationOperatorTests.cs
index ecf892b..2ba139d 100644
--- a/src/tests/ReactiveUI.Primitives.Async.Tests/TransformationOperatorTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Async.Tests/TransformationOperatorTests.cs
@@ -553,8 +553,7 @@ public async Task WhenPrependCancelledBeforeAllValues_ThenEarlyReturn()
received.Add(x);
if (received.Count == 3)
{
- await (subscription ?? throw new InvalidOperationException("The subscription is not ready."))
- .DisposeAsync();
+ await subscription!.DisposeAsync();
}
},
null);
diff --git a/src/tests/ReactiveUI.Primitives.Maui.Reactive.Tests/MauiDispatcherSequencerTests.cs b/src/tests/ReactiveUI.Primitives.Maui.Reactive.Tests/MauiDispatcherSequencerTests.cs
index 524f185..8a2ae40 100644
--- a/src/tests/ReactiveUI.Primitives.Maui.Reactive.Tests/MauiDispatcherSequencerTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Maui.Reactive.Tests/MauiDispatcherSequencerTests.cs
@@ -29,7 +29,7 @@ public async Task ConstructorRejectsNullDispatcher() =>
public async Task ToSequencerValidatesAndAdaptsDispatcher()
{
const IDispatcher nullDispatcher = null!;
- await Assert.That(static () => nullDispatcher.ToSequencer()).ThrowsExactly();
+ await Assert.That(static () => nullDispatcher!.ToSequencer()).ThrowsExactly();
FakeDispatcher dispatcher = new();
var scheduler = dispatcher.ToSequencer();
diff --git a/src/tests/ReactiveUI.Primitives.Maui.Tests/MauiDispatcherSequencerTests.cs b/src/tests/ReactiveUI.Primitives.Maui.Tests/MauiDispatcherSequencerTests.cs
index 63bac59..b99a517 100644
--- a/src/tests/ReactiveUI.Primitives.Maui.Tests/MauiDispatcherSequencerTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Maui.Tests/MauiDispatcherSequencerTests.cs
@@ -29,7 +29,7 @@ public async Task ConstructorRejectsNullDispatcher() =>
public async Task ToSequencerValidatesAndAdaptsDispatcher()
{
const IDispatcher nullDispatcher = null!;
- await Assert.That(static () => nullDispatcher.ToSequencer()).ThrowsExactly();
+ await Assert.That(static () => nullDispatcher!.ToSequencer()).ThrowsExactly();
FakeDispatcher dispatcher = new();
var sequencer = dispatcher.ToSequencer();
diff --git a/src/tests/ReactiveUI.Primitives.Tests/CommandExecutionTests.cs b/src/tests/ReactiveUI.Primitives.Tests/CommandExecutionTests.cs
index 0277449..5d99dca 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/CommandExecutionTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/CommandExecutionTests.cs
@@ -46,7 +46,7 @@ public async Task AwaitingAFailedSynchronousCommandRethrowsTheOriginalException(
await Assert.That(execution.GetAwaiter().IsCompleted).IsTrue();
var thrown = Assert.Throws(() => execution.GetAwaiter().GetResult());
- await Assert.That(thrown).IsSameReferenceAs(fault);
+ await Assert.That(thrown!).IsSameReferenceAs(fault);
}
///
@@ -72,7 +72,7 @@ public async Task ConfigureAwaitPreservesTheOutcomeOfEveryExecutionShape()
using CommandSignal failing = new(() => throw fault);
var configured = failing.ExecuteAsync().ConfigureAwait(false);
var thrown = Assert.Throws(() => configured.GetAwaiter().GetResult());
- await Assert.That(thrown).IsSameReferenceAs(fault);
+ await Assert.That(thrown!).IsSameReferenceAs(fault);
}
///
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SafeWitnessTests.cs b/src/tests/ReactiveUI.Primitives.Tests/SafeWitnessTests.cs
index 7555363..61e5557 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SafeWitnessTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SafeWitnessTests.cs
@@ -92,7 +92,7 @@ public async Task DelegateWitnessMadeSafeStopsAfterItsValueCallbackThrows()
// A second push must not reach the callback, so it must not throw either.
safe.OnNext(LateValue);
- await Assert.That(thrown.Message).IsEqualTo("next-failed");
+ await Assert.That(thrown!.Message).IsEqualTo("next-failed");
await Assert.That(calls).IsEqualTo(1);
}
@@ -153,6 +153,6 @@ public async Task CancelFreeSafeWitnessStopsAfterTheObserverThrows()
// The witness has latched stopped, so this must be a silent no-op rather than a second throw.
safe.OnNext(LateValue);
- await Assert.That(thrown.Message).IsEqualTo("observer-next");
+ await Assert.That(thrown!.Message).IsEqualTo("observer-next");
}
}
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SignalFromTaskTest.cs b/src/tests/ReactiveUI.Primitives.Tests/SignalFromTaskTest.cs
index 86be8b0..2c873ab 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SignalFromTaskTest.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SignalFromTaskTest.cs
@@ -909,7 +909,7 @@ public async Task ImmediateTaskSignalErrorsWhenTheTokenIsCancelledBeforeTheResul
ConcurrentQueue values = new();
ConcurrentQueue errors = new();
_ = taskSignal.Subscribe(values.Enqueue, errors.Enqueue, static () => { });
- await taskSignal.CancellationTokenSource.CancelAsync();
+ await taskSignal.CancellationTokenSource!.CancelAsync();
completion.SetResult(SuccessValue);
await TestPolling.SpinUntil(() => !errors.IsEmpty, PollTimeout).ConfigureAwait(false);
await Assert.That(errors.Count).IsEqualTo(1);
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SignalRecoverTests.cs b/src/tests/ReactiveUI.Primitives.Tests/SignalRecoverTests.cs
index 9a63ed6..26eb997 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SignalRecoverTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SignalRecoverTests.cs
@@ -88,7 +88,7 @@ public async Task OnCleanupRunsTheActionWhenSubscribingToTheSourceThrows()
var caught = Assert.Throws(() =>
failingSource.OnCleanup(() => cleanupRuns++).Subscribe(static _ => { }));
- await Assert.That(caught).IsSameReferenceAs(expected);
+ await Assert.That(caught!).IsSameReferenceAs(expected);
await Assert.That(cleanupRuns).IsEqualTo(1);
}
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SinkObserverTests.cs b/src/tests/ReactiveUI.Primitives.Tests/SinkObserverTests.cs
index 6db45b4..a97c94a 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SinkObserverTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SinkObserverTests.cs
@@ -523,7 +523,7 @@ public async Task BufferSinkReleasesTheUpstreamWhenTheObserverThrowsOnACompleted
var thrown = Assert.Throws(() => sink.OnNext(Two));
- await Assert.That(thrown.Message).IsEqualTo(ObserverNextMessage);
+ await Assert.That(thrown!.Message).IsEqualTo(ObserverNextMessage);
await Assert.That(subscription.DisposeCount).IsEqualTo(1);
}
@@ -545,7 +545,7 @@ public async Task BufferSinkDropsValuesFromASourceThatKeepsPushingAfterTheObserv
source.Next(One);
var thrown = Assert.Throws(() => source.Next(Two));
- await Assert.That(thrown.Message).IsEqualTo(ObserverNextMessage);
+ await Assert.That(thrown!.Message).IsEqualTo(ObserverNextMessage);
await Assert.That(observer.NextCount).IsEqualTo(One);
// The sink disposed its upstream; this source ignores disposal and pushes on regardless.
@@ -683,7 +683,7 @@ private static async Task AssertObserverFailureReleasesUpstream(
{
var thrown = Assert.Throws(() => sink.OnNext(1));
- await Assert.That(thrown.Message).IsEqualTo("observer-next");
+ await Assert.That(thrown!.Message).IsEqualTo("observer-next");
await Assert.That(subscription.DisposeCount).IsEqualTo(1);
}
diff --git a/src/tests/ReactiveUI.Primitives.Tests/SyncLatestTests.cs b/src/tests/ReactiveUI.Primitives.Tests/SyncLatestTests.cs
index 32b3afb..7bfb912 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/SyncLatestTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/SyncLatestTests.cs
@@ -242,7 +242,7 @@ public async Task SyncLatestUnsubscribesEarlierSourcesWhenALaterSourceThrowsOnSu
third,
static (a, b, c) => a + b + c);
var thrown = Assert.Throws(() => _ = combined.Subscribe(static _ => { }));
- await Assert.That(thrown).IsSameReferenceAs(expected);
+ await Assert.That(thrown!).IsSameReferenceAs(expected);
await Assert.That(first.HasObservers).IsFalse();
await Assert.That(third.HasObservers).IsFalse();
}
diff --git a/src/tests/ReactiveUI.Primitives.Tests/UseSignalTests.cs b/src/tests/ReactiveUI.Primitives.Tests/UseSignalTests.cs
index a6807bf..a625cec 100644
--- a/src/tests/ReactiveUI.Primitives.Tests/UseSignalTests.cs
+++ b/src/tests/ReactiveUI.Primitives.Tests/UseSignalTests.cs
@@ -115,7 +115,7 @@ public async Task UseReleasesTheResourceWhenTheObserverThrows()
// The sink has stopped, so this must be a silent no-op rather than a second trip into the observer.
sink.OnNext(LateValue);
- await Assert.That(thrown.Message).IsEqualTo("observer-next");
+ await Assert.That(thrown!.Message).IsEqualTo("observer-next");
await Assert.That(resource.DisposeCount).IsEqualTo(1);
await Assert.That(source.DisposeCount).IsEqualTo(1);
}
From 136182a077b6445232c042de874dbd9e1bac51e8 Mon Sep 17 00:00:00 2001
From: Glenn Watson <5834289+glennawatson@users.noreply.github.com>
Date: Sat, 25 Jul 2026 17:41:11 +1000
Subject: [PATCH 4/8] build: organize analyzer configuration
- Group diagnostics by analyzer source and category with official IDE rule names.
- Preserve the null-forgiving callback cast while forwarding cancellation tokens.
---
.editorconfig | 513 ++++++++----------
.../Signals/SignalExtensions{FromTask}.cs | 7 +-
2 files changed, 229 insertions(+), 291 deletions(-)
diff --git a/.editorconfig b/.editorconfig
index dae5bee..2057a87 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -183,8 +183,9 @@ csharp_space_between_square_brackets = false
dotnet_diagnostic.AvoidAsyncVoid.severity = suggestion
###################
-# Microsoft .NET Analyzers (CA) - Design Rules
+# Microsoft.CodeAnalysis.NetAnalyzers (CA)
###################
+# Design
dotnet_diagnostic.CA1000.severity = none # Do not declare static members on generic types — common factory pattern
dotnet_diagnostic.CA1001.severity = error # Types that own disposable fields should be disposable
dotnet_diagnostic.CA1002.severity = none # Do not expose generic lists — we deliberately expose List; interface-based collections are an older convention we don't follow
@@ -237,22 +238,16 @@ dotnet_diagnostic.CA1068.severity = error # CancellationToken parameters must co
dotnet_diagnostic.CA1069.severity = error # Enums should not have duplicate values
dotnet_diagnostic.CA1070.severity = error # Do not declare event fields as virtual
-###################
-# Microsoft .NET Analyzers (CA) - Globalization Rules
-###################
+# Globalization
dotnet_diagnostic.CA1303.severity = none # Do not pass literals as localized parameters — we don't ship localized resources
dotnet_diagnostic.CA1307.severity = none # Covered by PSH1207 (canonical)
dotnet_diagnostic.CA1308.severity = none # Normalize strings to uppercase — ToLowerInvariant is correct for filesystem path / cache key normalization
dotnet_diagnostic.CA1310.severity = none # Covered by PSH1207 (canonical)
-###################
-# Microsoft .NET Analyzers (CA) - Interoperability Rules
-###################
+# Interoperability
dotnet_diagnostic.CA1401.severity = error # P/Invokes should not be visible
-###################
-# Microsoft .NET Analyzers (CA) - Maintainability Rules
-###################
+# Maintainability
dotnet_diagnostic.CA1500.severity = none # Variable names should not match field names — covered by SST1484
dotnet_diagnostic.CA1501.severity = none # Covered by SST1446 (canonical)
dotnet_diagnostic.CA1502.severity = none # Covered by SST1442 (canonical)
@@ -269,15 +264,11 @@ dotnet_diagnostic.CA1514.severity = none # Avoid redundant length argument — c
dotnet_diagnostic.CA1515.severity = none # Consider making public types internal — interferes with tests and reflection-discovered types (BenchmarkDotNet, TUnit, etc.)
dotnet_diagnostic.CA1516.severity = error # Use cross-platform intrinsics
-###################
-# Microsoft .NET Analyzers (CA) - Naming Rules
-###################
+# Naming
dotnet_diagnostic.CA1710.severity = suggestion # Identifiers should have correct suffix
dotnet_diagnostic.CA1724.severity = none # Type Names Should Not Match Namespaces — namespace/type name overlap is intentional API surface
-###################
-# Microsoft .NET Analyzers (CA) - Performance Rules
-###################
+# Performance
dotnet_diagnostic.CA1802.severity = none # Use literals where appropriate — covered by PSH1402
dotnet_diagnostic.CA1805.severity = none # Do not initialize unnecessarily — covered by PSH1403
dotnet_diagnostic.CA1806.severity = error # Do not ignore method results
@@ -346,9 +337,7 @@ dotnet_diagnostic.CA1874.severity = none # Use 'Regex.IsMatch' — covered by PS
dotnet_diagnostic.CA1875.severity = none # Use 'Regex.Count' — covered by PSH1406
dotnet_diagnostic.CA1877.severity = none # Use 'Encoding.GetString' instead of 'Encoding.GetChars' — covered by PSH1225
-###################
-# Microsoft .NET Analyzers (CA) - Reliability Rules
-###################
+# Reliability
dotnet_diagnostic.CA2000.severity = suggestion # Dispose objects before losing scope
dotnet_diagnostic.CA2002.severity = error # Do not lock on objects with weak identity
dotnet_diagnostic.CA2007.severity = none # Do not directly await a Task — Rx and library callers drive synchronization context themselves
@@ -371,9 +360,7 @@ dotnet_diagnostic.CA2024.severity = error # Do not use 'StreamReader.EndOfStream
dotnet_diagnostic.CA2025.severity = error # Do not pass 'IDisposable' instances into unawaited tasks
dotnet_diagnostic.CA2026.severity = error # Do not use methods or types annotated with [RequiresDynamicCode] in code that uses [RequiresDynamicCode]
-###################
-# Microsoft .NET Analyzers (CA) - Usage Rules
-###################
+# Usage
dotnet_diagnostic.CA1801.severity = error # Review unused parameters
dotnet_code_quality.CA1801.api_surface = private, internal # only flag non-public APIs so we don't break public signatures
dotnet_diagnostic.CA1816.severity = error # Call GC.SuppressFinalize correctly
@@ -426,9 +413,7 @@ dotnet_diagnostic.CA2268.severity = error # Use 'string.Equals(string, string, S
# Skipped (deprecated ISerializable formatter): CA2229 Implement serialization constructors,
# CA2235 Mark all non-serializable fields, CA2237 Mark ISerializable types with SerializableAttribute.
-###################
-# Microsoft .NET Analyzers (CA) - Security Rules
-###################
+# Security
# SQL Injection & Command Injection
dotnet_diagnostic.CA2100.severity = error # Review SQL queries for security vulnerabilities
@@ -551,16 +536,9 @@ dotnet_diagnostic.CA2153.severity = error # Do not catch corrupted state excepti
dotnet_diagnostic.CA5367.severity = error # Do not serialize types with pointer fields
###################
-# SonarAnalyzer (Sxxxx) — global suppressions
-###################
-dotnet_diagnostic.S1075.severity = none # Hardcoded URI — canonical SourceLink hosts are the point
-dotnet_diagnostic.S2436.severity = none # Too many generic parameters — needed for the projector overload
-dotnet_diagnostic.S4036.severity = none # PATH-relative process spawn — benchmark only, trusted env
-dotnet_diagnostic.S8969.severity = none # Nullability inference is inconsistent across the repository's target frameworks
-
-###################
-# Microsoft .NET Runtime Obsoletions (SYSLIB0xxx)
+# Microsoft .NET SDK Diagnostics (SYSLIB)
###################
+# Runtime obsoletions
dotnet_diagnostic.SYSLIB0001.severity = error # The UTF-7 encoding is insecure and should not be used
dotnet_diagnostic.SYSLIB0002.severity = error # PrincipalPermissionAttribute is not honored by the runtime and must not be used
dotnet_diagnostic.SYSLIB0003.severity = error # Code Access Security (CAS) is not supported or honored by the runtime
@@ -623,9 +601,7 @@ dotnet_diagnostic.SYSLIB0059.severity = error # SystemEvents.EventsThreadShutdow
dotnet_diagnostic.SYSLIB0060.severity = error # Constructors of DirectoryServices.ActiveDirectory.ConfigurationContext are obsolete
dotnet_diagnostic.SYSLIB0061.severity = error # CryptographyConfig.AddOID and AddAlgorithm methods are obsolete
-###################
-# Microsoft .NET Source Generator Diagnostics (SYSLIB1xxx)
-###################
+# Source generators
# LoggerMessage source generator
dotnet_diagnostic.SYSLIB1001.severity = error # Logging method names cannot start with _
dotnet_diagnostic.SYSLIB1002.severity = error # Don't include log level parameters as templates in the logging message
@@ -713,8 +689,9 @@ dotnet_diagnostic.SYSLIB1103.severity = error # Configuration binding source gen
dotnet_diagnostic.SYSLIB1104.severity = error # Configuration binding source generator: language version is too low
###################
-# Microsoft .NET Style Rules (IDExxxx) - Language Rules
+# Microsoft .NET Code Style Analyzers (IDE)
###################
+# Language rules
# EnforceCodeStyleInBuild=true (set in Directory.Build.props) promotes these
# IDE rules into `dotnet build` so they fire at compile time, not just in the
# IDE. We enable the ones that are unambiguous wins and skip the rules that
@@ -779,9 +756,71 @@ dotnet_diagnostic.IDE0310.severity = none # Convert lambda expression to method
dotnet_diagnostic.IDE0360.severity = none # Simplify property accessor — covered by SST2219
dotnet_diagnostic.IDE0370.severity = none # Remove unnecessary suppression (null-forgiving operator) — disabled for the same reason as RCS1249: multi-TFM nullability annotations can differ per platform
-###################
-# Microsoft .NET Style Rules (IDE1xxx / IDE3xxx) - Naming & Miscellaneous
-###################
+# Language and unnecessary code rules.
+dotnet_diagnostic.IDE0001.severity = none # Simplify name
+dotnet_diagnostic.IDE0003.severity = none # Name can be simplified
+dotnet_diagnostic.IDE0005.severity = none # Remove unnecessary import
+dotnet_diagnostic.IDE0010.severity = none # Add missing cases to switch statement
+dotnet_diagnostic.IDE0011.severity = none # Add braces
+dotnet_diagnostic.IDE0017.severity = none # Use object initializers
+dotnet_diagnostic.IDE0018.severity = none # Inline variable declaration
+dotnet_diagnostic.IDE0020.severity = none # Use pattern matching to avoid is check followed by a cast (with variable)
+dotnet_diagnostic.IDE0027.severity = none # Use expression body for accessors
+dotnet_diagnostic.IDE0029.severity = none # Null check can be simplified
+dotnet_diagnostic.IDE0030.severity = none # Null check can be simplified
+dotnet_diagnostic.IDE0032.severity = none # Use auto property
+dotnet_diagnostic.IDE0033.severity = none # Use explicitly provided tuple name
+dotnet_diagnostic.IDE0034.severity = none # Simplify default expression
+dotnet_diagnostic.IDE0036.severity = none # Order modifiers
+dotnet_diagnostic.IDE0037.severity = none # Use inferred member name
+dotnet_diagnostic.IDE0039.severity = none # Use local function instead of lambda
+dotnet_diagnostic.IDE0040.severity = none # Add accessibility modifiers
+dotnet_diagnostic.IDE0045.severity = none # Use conditional expression for assignment
+dotnet_diagnostic.IDE0046.severity = none # Use conditional expression for return
+dotnet_diagnostic.IDE0051.severity = none # Remove unused private member
+dotnet_diagnostic.IDE0053.severity = none # Use expression body for lambdas
+dotnet_diagnostic.IDE0054.severity = none # Use compound assignment
+dotnet_diagnostic.IDE0056.severity = none # Use index operator
+dotnet_diagnostic.IDE0062.severity = none # Make local function static
+dotnet_diagnostic.IDE0063.severity = none # Use simple using statement
+dotnet_diagnostic.IDE0065.severity = none # Using directive placement
+dotnet_diagnostic.IDE0070.severity = none # Use System.HashCode.Combine
+dotnet_diagnostic.IDE0071.severity = none # Simplify interpolation
+dotnet_diagnostic.IDE0072.severity = none # Add missing cases to switch expression
+dotnet_diagnostic.IDE0073.severity = none # Use file header
+dotnet_diagnostic.IDE0074.severity = none # Use coalesce compound assignment
+dotnet_diagnostic.IDE0076.severity = none # Remove invalid global SuppressMessageAttribute
+dotnet_diagnostic.IDE0077.severity = none # Avoid legacy format target in global SuppressMessageAttribute
+dotnet_diagnostic.IDE0080.severity = none # Remove unnecessary suppression operator
+dotnet_diagnostic.IDE0082.severity = none # Convert typeof to nameof
+dotnet_diagnostic.IDE0083.severity = none # Use pattern matching (not operator)
+dotnet_diagnostic.IDE0090.severity = none # Simplify new expression
+dotnet_diagnostic.IDE0100.severity = none # Remove unnecessary equality operator
+dotnet_diagnostic.IDE0110.severity = none # Remove unnecessary discard
+dotnet_diagnostic.IDE0150.severity = none # Prefer null check over type check
+dotnet_diagnostic.IDE0161.severity = none # Use file-scoped namespace
+dotnet_diagnostic.IDE0170.severity = none # Simplify property pattern
+dotnet_diagnostic.IDE0180.severity = none # Use tuple to swap values
+dotnet_diagnostic.IDE0200.severity = none # Remove unnecessary lambda expression
+dotnet_diagnostic.IDE0220.severity = none # Add explicit cast in foreach loop
+dotnet_diagnostic.IDE0230.severity = none # Use UTF-8 string literal
+dotnet_diagnostic.IDE0240.severity = none # Nullable directive is redundant
+dotnet_diagnostic.IDE0241.severity = none # Nullable directive is unnecessary
+dotnet_diagnostic.IDE0251.severity = none # Member can be made readonly
+dotnet_diagnostic.IDE0270.severity = none # Null check can be simplified
+dotnet_diagnostic.IDE0280.severity = none # Use nameof
+dotnet_diagnostic.IDE0290.severity = none # Use primary constructor
+dotnet_diagnostic.IDE0301.severity = none # Use collection expression for empty
+dotnet_diagnostic.IDE0302.severity = none # Use collection expression for stackalloc
+dotnet_diagnostic.IDE0303.severity = none # Use collection expression for Create()
+dotnet_diagnostic.IDE0304.severity = none # Use collection expression for builder
+dotnet_diagnostic.IDE0305.severity = none # Use collection expression for fluent
+dotnet_diagnostic.IDE0340.severity = none # Use unbound generic type
+dotnet_diagnostic.IDE0350.severity = none # Use implicitly typed lambda
+dotnet_diagnostic.IDE0380.severity = none # Remove unnecessary unsafe modifier
+dotnet_diagnostic.IDE1005.severity = none # Use conditional delegate call
+
+# Naming and miscellaneous
# Naming conventions — SA1300 family already enforces PascalCase / interface
# prefix / field casing (with our _underscore convention on SA1306/1309/1311
# deliberately disabled). Leaving IDE1006 off because configuring
@@ -791,8 +830,9 @@ dotnet_diagnostic.IDE1006.severity = none # Naming rule violation — SA1300 fam
dotnet_diagnostic.IDE3000.severity = none # Disabled per project convention — not enforced
###################
-# Roslynator Analyzers (RCS1xxx) - Code Simplification
+# Roslynator.CSharp.Analyzers (RCS)
###################
+# Code simplification
dotnet_diagnostic.RCS1001.severity = none # Add braces (when expression spans over multiple lines) — covered by SST1519
dotnet_diagnostic.RCS1003.severity = none # Add braces to if-else (when expression spans over multiple lines) — covered by SST1519
dotnet_diagnostic.RCS1005.severity = error # Simplify nested using statement
@@ -802,6 +842,7 @@ dotnet_diagnostic.RCS1031.severity = none # Remove unnecessary braces in switch
dotnet_diagnostic.RCS1032.severity = error # Remove redundant parentheses
dotnet_diagnostic.RCS1033.severity = none # Remove redundant boolean literal — covered by SST1143
dotnet_diagnostic.RCS1039.severity = none # Remove argument list from attribute — covered by SST1411
+dotnet_diagnostic.RCS1040.severity = none # Remove empty statement — covered by SST1180
dotnet_diagnostic.RCS1042.severity = none # Remove enum default underlying type — covered by SST1177
dotnet_diagnostic.RCS1043.severity = error # Remove 'partial' modifier from type with a single part
dotnet_diagnostic.RCS1049.severity = none # Simplify boolean comparison — covered by SST1143
@@ -863,9 +904,7 @@ dotnet_diagnostic.RCS1262.severity = error # Unnecessary raw string literal
dotnet_diagnostic.RCS1265.severity = none # Remove redundant catch block — covered by SST1470
dotnet_diagnostic.RCS1268.severity = error # Simplify numeric comparison
-###################
-# Roslynator Analyzers (RCS1xxx) - Code Quality
-###################
+# Code quality
dotnet_diagnostic.RCS1013.severity = none # Use predefined type — covered by SST1121
dotnet_diagnostic.RCS1014.severity = error # Use explicitly/implicitly typed array
dotnet_diagnostic.RCS1015.severity = error # Use nameof operator
@@ -950,9 +989,7 @@ dotnet_diagnostic.RCS1264.severity = error # Use 'var' or explicit type (replace
dotnet_diagnostic.RCS1266.severity = none # Use raw string literal — covered by SST2243
dotnet_diagnostic.RCS1267.severity = error # Use string interpolation instead of 'string.Concat'
-###################
-# Roslynator Analyzers (RCS1xxx) - Performance
-###################
+# Performance
dotnet_diagnostic.RCS1077.severity = none # Covered by the PSH1101-PSH1111 family (canonical)
dotnet_diagnostic.RCS1080.severity = none # Covered by PSH1106 (canonical)
dotnet_diagnostic.RCS1112.severity = none # Combine 'Enumerable.Where' method chain — covered by PSH1109
@@ -966,9 +1003,7 @@ dotnet_diagnostic.RCS1235.severity = error # Optimize method call
dotnet_diagnostic.RCS1236.severity = none # Use exception filter — covered by SST2009
dotnet_diagnostic.RCS1246.severity = none # Use element access — covered by PSH1106
-###################
-# Roslynator Analyzers (RCS1xxx) - Maintainability
-###################
+# Maintainability
dotnet_diagnostic.RCS1158.severity = none # Static member in generic type should use a type parameter — common factory pattern — covered by SST1431
dotnet_diagnostic.RCS1163.severity = none # Unused parameter — interface implementations and Rx selectors often have unused parameters
dotnet_diagnostic.RCS1164.severity = none # Unused type parameter - DUPLICATE IDE0060 (UnusedParameter analyzer 210ms; IDE0060 bundled at lower cost)
@@ -978,9 +1013,7 @@ dotnet_diagnostic.RCS1213.severity = none # Remove unused member declaration - D
dotnet_diagnostic.RCS1241.severity = error # Implement non-generic counterpart
dotnet_diagnostic.RCS1256.severity = none # Invalid argument null check — conflicts with our ArgumentExceptionHelper helper pattern
-###################
-# Roslynator Analyzers (RCS1xxx) - Documentation
-###################
+# Documentation
dotnet_diagnostic.RCS1181.severity = error # Convert comment to documentation comment
dotnet_diagnostic.RCS1189.severity = error # Add or remove region name
dotnet_diagnostic.RCS1226.severity = none # Add paragraph to documentation comment — <para> wrapping is subjective and adds noise
@@ -989,9 +1022,7 @@ dotnet_diagnostic.RCS1232.severity = error # Order elements in documentation com
dotnet_diagnostic.RCS1253.severity = error # Format documentation comment summary
dotnet_diagnostic.RCS1263.severity = none # Invalid reference in a documentation comment
-###################
-# Roslynator Analyzers (RCS1xxx) - Disabled (covered by CA/SA equivalent)
-###################
+# Disabled
dotnet_diagnostic.RCS1018.severity = none # Add/remove accessibility modifiers — covered by SA1400
dotnet_diagnostic.RCS1019.severity = none # Order modifiers — covered by SA1206 / SA1208
dotnet_diagnostic.RCS1037.severity = none # Remove trailing white-space — covered by SA1028
@@ -1009,9 +1040,7 @@ dotnet_diagnostic.RCS1175.severity = none # Unused 'this' parameter — covered
dotnet_diagnostic.RCS1194.severity = none # Implement exception constructors — covered by CA1032
dotnet_diagnostic.RCS1203.severity = none # Use AttributeUsageAttribute — covered by CA1018
-###################
-# Roslynator Formatting Analyzers (RCS0xxx) - covered by StyleCop SA equivalents
-###################
+# Formatting
dotnet_diagnostic.RCS0001.severity = none # Add blank line after embedded statement — covered by StyleCop layout rules
dotnet_diagnostic.RCS0002.severity = none # Add blank line after #region — covered by StyleCop SA1517 family
dotnet_diagnostic.RCS0003.severity = none # Add blank line after using directive list — covered by SA1516
@@ -1095,10 +1124,6 @@ stylesharp.max_file_lines = 1000 # SST1522 (code lines
# stylesharp.include_internal = true # SST1499 (set false to report only fields visible outside the assembly)
# stylesharp.require_parameterless = true # SST1488 (set false where every exception must carry a message)
# stylesharp.include_non_public_types = true # SST1488 (set false to check only externally visible exceptions)
-# performancesharp.empty_string_style = pattern # PSH1204 (pattern | length | is_null_or_empty; the last two are only offered where the string is provably not null)
-# performancesharp.include_public = false # PSH1411 (set true in an app to seal public types too; a break in a library)
-# performancesharp.excluded_properties = Items, Keys # PSH1017 (comma-separated; properties allowed to copy on read)
-
# Spacing
dotnet_diagnostic.SST1000.severity = error # A control-flow keyword is not followed by a space
dotnet_diagnostic.SST1001.severity = error # A comma is spaced incorrectly
@@ -1132,6 +1157,7 @@ dotnet_diagnostic.SST1028.severity = error # A line ends with trailing whitespac
# Readability and maintainability
dotnet_diagnostic.SST1100.severity = error # A base. prefix is used where the type does not override the member
+dotnet_diagnostic.SST1101.severity = none # see docs/rules/SST1101.md
dotnet_diagnostic.SST1102.severity = error # A query clause is separated from the previous clause by a blank line
dotnet_diagnostic.SST1103.severity = error # Query clauses mix single-line and multi-line layout
dotnet_diagnostic.SST1104.severity = error # A query clause shares the last line of a multi-line previous clause
@@ -1249,6 +1275,8 @@ dotnet_diagnostic.SST1216.severity = error # Using static directives should be p
dotnet_diagnostic.SST1217.severity = error # Using static directives should be ordered alphabetically
dotnet_diagnostic.SST1218.severity = error # Other members separate a method's overloads
dotnet_diagnostic.SST1219.severity = error # A switch default clause is not placed last
+dotnet_diagnostic.SST1220.severity = error # An all-named argument list is in a different order than the parameters. Code fix reorders it to declaration order. Info.
+dotnet_diagnostic.SST1221.severity = error # `where` constraint clauses are not ordered to match the type-parameter list. Code fix reorders them. Info.
# Naming
dotnet_diagnostic.SST1300.severity = none # Types and members should be PascalCase — naming duplicates existing analyzers
@@ -1271,6 +1299,7 @@ dotnet_diagnostic.SST1317.severity = none # Asynchronous method names should end
dotnet_diagnostic.SST1318.severity = error # Overriding parameter names should match the base declaration
dotnet_diagnostic.SST1319.severity = error # An enumeration's type name is not PascalCase
dotnet_diagnostic.SST1320.severity = error # A parameter name matches its method's name
+dotnet_diagnostic.SST1321.severity = none # Public APIs intentionally use Async to describe asynchronous observable behavior without returning an awaitable.
# Maintainability
dotnet_diagnostic.SST1400.severity = error # An element does not declare an access modifier
@@ -1306,6 +1335,7 @@ dotnet_diagnostic.SST1430.severity = error # Rethrow with 'throw;' to preserve t
dotnet_diagnostic.SST1431.severity = error # Static members of a generic type should use a type parameter
dotnet_diagnostic.SST1432.severity = error # Classes with only static members should be static
dotnet_diagnostic.SST1433.severity = error # Redundant constructors should be removed
+dotnet_diagnostic.SST1434.severity = error # see docs/rules/SST1434.md
dotnet_diagnostic.SST1435.severity = error # Empty namespace declarations should be removed
dotnet_diagnostic.SST1436.severity = error # Empty types should not be declared
dotnet_diagnostic.SST1437.severity = error # Empty interfaces should not be declared
@@ -1398,6 +1428,15 @@ dotnet_diagnostic.SST1521.severity = error # A line is longer than the configure
dotnet_diagnostic.SST1522.severity = error # A file has more code lines than the configured maximum (default 500)
dotnet_diagnostic.SST1523.severity = error # A member has more code lines than the configured maximum (default 60)
dotnet_diagnostic.SST1524.severity = error # A switch section has more code lines than the configured maximum (default 20)
+dotnet_diagnostic.SST1525.severity = error # A multi-statement `switch` section has no braces; the braces-on policy extends to switch sections. Code fix wraps it.
+dotnet_diagnostic.SST1526.severity = none # A wrapped binary expression places the operator inconsistently. Configurable (`before`/`after`, default before). Opt-in.
+dotnet_diagnostic.SST1527.severity = none # The `=>` of an expression-bodied member wraps inconsistently. Configurable. Opt-in.
+dotnet_diagnostic.SST1528.severity = none # The `=` of a wrapped initializer wraps inconsistently. Configurable. Opt-in.
+dotnet_diagnostic.SST1529.severity = none # A wrapped `?.`/`.` call chain places the break inconsistently. Configurable. Opt-in.
+dotnet_diagnostic.SST1530.severity = none # A newline sits between a type declaration and its base list. Code fix pulls the base list onto the declaration line. Opt-in.
+dotnet_diagnostic.SST1531.severity = none # A short object initializer is split across lines. Code fix collapses it when it fits. Opt-in.
+dotnet_diagnostic.SST1532.severity = none # A file mixes line endings. Configurable (`lf`/`crlf`, default lf). Opt-in.
+dotnet_diagnostic.SST1533.severity = none # A source file contains no code. Opt-in.
# Documentation
dotnet_diagnostic.SST1600.severity = error # Externally visible members should be documented
@@ -1447,8 +1486,14 @@ dotnet_diagnostic.SST1656.severity = error # Extension block type parameters sho
dotnet_diagnostic.SST1657.severity = error # Extension block documentation should reference a real parameter or type parameter
dotnet_diagnostic.SST1658.severity = error # Documentation text repeats a word
dotnet_diagnostic.SST1659.severity = error # A comment has no text at all
+dotnet_diagnostic.SST1660.severity = error # The ` ` tags are not in parameter order. Code fix reorders them. Info.
+dotnet_diagnostic.SST1661.severity = error # A snippet uses ``/`` mismatched to single- vs multi-line content. Code fix swaps the tag. Info.
+dotnet_diagnostic.SST1662.severity = none # A thrown exception type has no `` documentation. Code fix adds the skeleton. Opt-in.
+dotnet_diagnostic.SST1663.severity = none # A `//` comment before a public member reads like a summary; use `///`. Code fix converts it. Opt-in.
+dotnet_diagnostic.SST1664.severity = none # A summary separates paragraphs with blank lines instead of ``. Code fix wraps them. Opt-in.
# Concurrency and modernization
+dotnet_diagnostic.SST1900.severity = error # see docs/rules/SST1900.md
dotnet_diagnostic.SST1901.severity = error # A lock targets a field or property reachable from outside the declaring type
dotnet_diagnostic.SST1902.severity = error # Do not lock on 'this', a Type, or a string
dotnet_diagnostic.SST1903.severity = error # Do not lock on a newly-created object
@@ -1483,10 +1528,13 @@ dotnet_diagnostic.SST1704.severity = error # A class declaring extension blocks
dotnet_diagnostic.SST1705.severity = error # A class mixes classic extension methods with extension blocks
dotnet_diagnostic.SST1706.severity = error # An extension block targets a broad receiver type such as object or dynamic
dotnet_diagnostic.SST1707.severity = error # Extension blocks should be ordered by receiver type
+dotnet_diagnostic.SST1708.severity = error # An extension method never uses its `this` receiver, so it need not be an extension.
+dotnet_diagnostic.SST1709.severity = none # A method in a `*Extensions` class whose first parameter lacks `this`. Code fix converts it to an extension block. Opt-in.
dotnet_diagnostic.SST1800.severity = error # Record classes should be sealed
dotnet_diagnostic.SST1801.severity = error # A positional record parameter does not match the configured casing
dotnet_diagnostic.SST1802.severity = error # A record declares a settable rather than init-only instance property
dotnet_diagnostic.SST1803.severity = error # A record struct is not declared readonly
+dotnet_diagnostic.SST1804.severity = error # A positional record has an empty `{ }` body where `;` would do. Code fix rewrites it. Info.
dotnet_diagnostic.SST2100.severity = error # An empty collection creation can use []
dotnet_diagnostic.SST2101.severity = error # An explicit collection creation can use [...]
dotnet_diagnostic.SST2102.severity = error # A span-targeted stackalloc initializer can use a collection expression
@@ -1522,8 +1570,11 @@ dotnet_diagnostic.SST2225.severity = error # A foreach loop hides an explicit el
dotnet_diagnostic.SST2226.severity = error # A cast hides an inner explicit conversion
dotnet_diagnostic.SST2227.severity = error # A post-assignment null fallback can be folded into the assigned expression
dotnet_diagnostic.SST2228.severity = error # A delegate local used only as a call target can be a local function
+dotnet_diagnostic.SST2229.severity = error # see docs/rules/SST2229.md
+dotnet_diagnostic.SST2230.severity = error # see docs/rules/SST2230.md
dotnet_diagnostic.SST2231.severity = error # A broad object pattern can use a direct null pattern
dotnet_diagnostic.SST2232.severity = error # nameof does not need concrete generic type arguments
+dotnet_diagnostic.SST2233.severity = none # see docs/rules/SST2233.md
dotnet_diagnostic.SST2234.severity = error # Nullable should use the T? shorthand
dotnet_diagnostic.SST2235.severity = error # Capture-free local functions should be static
dotnet_diagnostic.SST2236.severity = error # Tail-position using blocks can use using declarations
@@ -1543,8 +1594,36 @@ dotnet_diagnostic.SST2249.severity = error # A literal-format string.Format or l
dotnet_diagnostic.SST2250.severity = error # A bare local assigned once by the next statement can be an initialized declaration
dotnet_diagnostic.SST2251.severity = error # A method call names type arguments that inference would supply
dotnet_diagnostic.SST2252.severity = error # A switch statement is nested inside another switch statement
-dotnet_diagnostic.RCS1040.severity = none # covered by SST1180
-
+dotnet_diagnostic.SST2254.severity = none # A target-typed `new()` is written where an explicit type reads more clearly; the code fix restores `new TypeName(...)`. Opt-in — the counterpart to SST2202's target-typed direction, so a team enables at most one.
+dotnet_diagnostic.SST2255.severity = error # A hand-written null-or-empty string test. Code fix uses `string.IsNullOrEmpty`.
+dotnet_diagnostic.SST2256.severity = error # An extension method called in static form. Code fix rewrites to instance form. Info.
+dotnet_diagnostic.SST2257.severity = error # A lambda block body that is a single `return`. Code fix uses an expression body. Info.
+dotnet_diagnostic.SST2258.severity = error # A redundant explicit delegate wrapper (`new EventHandler(M)`). Code fix drops it. Info.
+dotnet_diagnostic.SST2259.severity = error # A stray `;` after a type declaration. Code fix removes it. Info.
+dotnet_diagnostic.SST2260.severity = error # An `as` cast to a type the operand already has. Code fix removes it. Info.
+dotnet_diagnostic.SST2261.severity = error # `(x && !y)
+dotnet_diagnostic.SST2262.severity = error # A raw string literal whose content needs no raw syntax. Code fix demotes it. Info.
+dotnet_diagnostic.SST2263.severity = error # An infinite loop whose body re-derives its stop condition. Code fix hoists the condition into the header. Info.
+dotnet_diagnostic.SST2264.severity = error # A numeric literal cast to an enum. Code fix names the member.
+dotnet_diagnostic.SST2265.severity = none # Consecutive fluent calls on one receiver can fold into a chain. Opt-in.
+dotnet_diagnostic.SST2266.severity = none # A local read exactly once can be inlined into that use. Opt-in.
+dotnet_diagnostic.SST2267.severity = none # Infinite loops written in mixed `while(true)`/`for(;;)` styles. Configurable. Opt-in.
+dotnet_diagnostic.SST2268.severity = none # Inconsistent `()` on object creation with an initializer. Configurable. Opt-in.
+dotnet_diagnostic.SST2269.severity = none # Inconsistent parentheses around a conditional's condition. Configurable. Opt-in.
+dotnet_diagnostic.SST2270.severity = none # Inconsistent explicit-vs-implicit array-creation type. Configurable. Opt-in.
+dotnet_diagnostic.SST2271.severity = none # `var`-vs-explicit local type per the configured preference. Configurable. Opt-in.
+dotnet_diagnostic.SST2272.severity = none # `[Flags]` member values written as mixed decimals and shifts. Configurable. Opt-in.
+dotnet_diagnostic.SST2273.severity = none # A function or loop body wraps its work in a trailing `if` that could be an early-exit guard clause. Code fix inverts it. Configurable threshold. Opt-in.
+dotnet_diagnostic.SST2274.severity = error # A value assigned with `as` and then null-checked is an `is` declaration pattern in one step. Code fix rewrites it.
+dotnet_diagnostic.SST2275.severity = error # A method whose block body is a single statement can use an expression body `=> expr`. Code fix rewrites it.
+dotnet_diagnostic.SST2276.severity = none # A constructor whose block body is a single statement can use an expression body. Code fix rewrites it. Opt-in.
+dotnet_diagnostic.SST2277.severity = none # An operator whose block body is a single `return` can use an expression body. Code fix rewrites it. Opt-in.
+dotnet_diagnostic.SST2278.severity = none # A conversion operator whose block body is a single `return` can use an expression body. Code fix rewrites it. Opt-in.
+dotnet_diagnostic.SST2279.severity = error # A get-only property whose getter is a single `return` can use a whole-member expression body. Code fix rewrites it.
+dotnet_diagnostic.SST2280.severity = error # A get-only indexer whose getter is a single `return` can use a whole-member expression body. Code fix rewrites it.
+dotnet_diagnostic.SST2281.severity = error # A local function whose block body is a single statement can use an expression body. Code fix rewrites it.
+dotnet_diagnostic.SST2282.severity = error # A reference-type `ReferenceEquals` check against `null` reads as an `is null` / `is not null` pattern. Code fix rewrites it.
+dotnet_diagnostic.SST2283.severity = error # A null guard that throws right before assigning the guarded value can fold into the assignment as `?? throw`. Code fix rewrites it.
# Design
dotnet_diagnostic.SST2300.severity = error # A class implements IDisposable but builds only half of the disposal pattern
dotnet_diagnostic.SST2301.severity = error # A class implementing IEquatable for itself can still be derived from
@@ -1575,6 +1654,13 @@ dotnet_diagnostic.SST2325.severity = error # An async method checks an argument
dotnet_diagnostic.SST2326.severity = none # An interface-typed value is narrowed to a concrete implementation — this is a high-performance core library, not strictly SOLID code, and narrowing to a known runtime type is a normal fast-path technique here: foreach over IEnumerable boxes List's struct enumerator (40 bytes per call, measured) where the indexed loop behind the type test allocates nothing
dotnet_diagnostic.SST2327.severity = error # A type tests its own runtime type against a class instead of dispatching through a virtual member
dotnet_diagnostic.SST2328.severity = error # A raw native pointer handle is exposed instead of a SafeHandle
+dotnet_diagnostic.SST2329.severity = error # A `[Flags]` enum declares no zero-valued member. Code fix adds `None = 0`.
+dotnet_diagnostic.SST2330.severity = error # A `[Flags]` member is a numeric literal equal to a combination of others (`All = 7`). Code fix writes `A
+dotnet_diagnostic.SST2331.severity = none # An enum leaves member values implicit, so their numbers depend on declaration order. Opt-in.
+dotnet_diagnostic.SST2332.severity = error # An auto-property's `private set` is only written during construction; make it get-only.
+dotnet_diagnostic.SST2333.severity = none # A generic comparison/equality contract is implemented without its non-generic counterpart. Opt-in.
+dotnet_diagnostic.SST2334.severity = none # A publicly visible type has no `[DebuggerDisplay]`. Opt-in.
+dotnet_diagnostic.SST2335.severity = none # Parts of a partial type disagree on the `static` modifier. Opt-in.
# Correctness
dotnet_diagnostic.SST2400.severity = error # Two arguments name each other's parameters and have been transposed
@@ -1654,6 +1740,12 @@ dotnet_diagnostic.SST2487.severity = error # A [ConstructorArgument] does not na
dotnet_diagnostic.SST2488.severity = error # An exception is logged and rethrown, duplicating the record
dotnet_diagnostic.SST2489.severity = error # A relational comparison is decided by the operand's type rather than its value
dotnet_diagnostic.SST2490.severity = error # Adjacent try statements with identical handling should be merged
+dotnet_diagnostic.SST2491.severity = error # A non-`async` method returns an awaitable from inside `using`/`try-finally`/`lock`, so the resource is torn down before the task completes. Code fix makes it `async`.
+dotnet_diagnostic.SST2492.severity = error # A null-guard throws on a parameter the signature declares may be null.
+dotnet_diagnostic.SST2493.severity = error # `== null`/`!= null` on an unconstrained generic `T`. Code fix uses `is null`/`is not null`.
+dotnet_diagnostic.SST2494.severity = error # A `??` whose left operand is a constant null, so the right is always taken. Code fix folds it.
+dotnet_diagnostic.SST2495.severity = error # A `[Flags]` combination includes an operand whose bits another already covers. Code fix removes it.
+dotnet_diagnostic.SST2496.severity = error # An explicit `Dispose`/`Close` on a resource an enclosing `using` already disposes. Code fix removes it. Info.
# Testing
dotnet_diagnostic.SST2500.severity = error # A test method contains no assertion and no expected-exception check
@@ -1671,11 +1763,29 @@ dotnet_diagnostic.SST2509.severity = error # A test method has a shape the runne
dotnet_diagnostic.SST2600.severity = error # Application output is written through legacy Trace instead of a structured logger
dotnet_diagnostic.SST2601.severity = error # A logger field or property does not follow the logger naming convention
+# Frameworks
+dotnet_diagnostic.SST2700.severity = error # An MVC route template contains a backslash; route segments are separated by `/`, so the route is unreachable. Code fix replaces `\` with `/`.
+dotnet_diagnostic.SST2701.severity = error # A `[JSInvokable]` method is not public, so JavaScript interop cannot call it. Code fix makes it public.
+dotnet_diagnostic.SST2702.severity = error # A `[SupplyParameterFromQuery]` property has a type the framework cannot bind from the query string, which throws at runtime.
+dotnet_diagnostic.SST2703.severity = error # A routable component's route constraint (`{id:int}`) disagrees with the matching `[Parameter]` CLR type, so the route silently fails to match.
+dotnet_diagnostic.SST2704.severity = error # A public action on an `[ApiController]` declares no HTTP-verb attribute, so it answers every verb and can make routing ambiguous.
+dotnet_diagnostic.SST2705.severity = none # A bound model member is a non-nullable value type with no required marker, so a request that omits it binds the default with no error. Opt-in.
+dotnet_diagnostic.SST2706.severity = error # A Windows Forms entry point carries neither `[STAThread]` nor `[MTAThread]`; without STA, clipboard, drag-and-drop, and common dialogs misbehave. Code fix adds `[STAThread]`.
+dotnet_diagnostic.SST2707.severity = none # A fire-and-forget `Task.Run` in a controller captures the request's `HttpContext`, which is disposed when the request ends, so the background work throws `ObjectDisposedException`. Opt-in.
+dotnet_diagnostic.SST2708.severity = error # A component subscribes to an event in a lifecycle method but never unsubscribes, so the event source keeps the component alive — a per-session leak on a Server circuit.
+dotnet_diagnostic.SST2709.severity = error # `StateHasChanged` is called while the component is being disposed, which the renderer no longer supports and throws.
+dotnet_diagnostic.SST2710.severity = error # `StateHasChanged` is called directly from a timer callback, off the renderer's dispatcher; marshal it with `InvokeAsync(StateHasChanged)`.
+dotnet_diagnostic.SST2711.severity = error # A synchronous component lifecycle method is overridden as `async void`, which the framework never awaits; override the `…Async` twin returning `Task`. Code fix rewrites the signature.
+dotnet_diagnostic.SST2712.severity = error # An `[Inject]`/`[CascadingParameter]` property has no setter, so the framework's reflection-based binding leaves it null. Code fix adds a setter.
+dotnet_diagnostic.SST2713.severity = error # A `DotNetObjectReference.Create(this)` is passed inline and never stored, so nothing can dispose it and it leaks on the JavaScript side.
+
###################
-# PerformanceSharp Analyzers (PSH) - severities staged ahead of package adoption;
-# inert until the PerformanceSharp.Analyzers package reference is enabled.
+# PerformanceSharp Analyzers (PSH)
###################
performancesharp.avoid_linq_on_hot_path = true
+# performancesharp.empty_string_style = pattern # PSH1204 (pattern | length | is_null_or_empty; the last two are only offered where the string is provably not null)
+# performancesharp.excluded_properties = Items, Keys # PSH1017 (comma-separated; properties allowed to copy on read)
+# performancesharp.include_public = false # PSH1411 (set true in an app to seal public types too; a break in a library)
dotnet_diagnostic.PSH1000.severity = error # Anonymous functions without captures should be static
dotnet_diagnostic.PSH1001.severity = error # Avoid allocating zero-length arrays (fix prefers [] on C# 12+, else Array.Empty())
dotnet_diagnostic.PSH1002.severity = error # Empty finalizers should be removed
@@ -1698,6 +1808,7 @@ dotnet_diagnostic.PSH1018.severity = error # A hand-written array is passed to a
dotnet_diagnostic.PSH1019.severity = error # The range indexer on an array allocates a copy; slice with AsSpan/AsMemory
dotnet_diagnostic.PSH1020.severity = error # Prefer a jagged array over a multidimensional one
dotnet_diagnostic.PSH1021.severity = error # An explicit GC.Collect or GC.WaitForPendingFinalizers forces collection the runtime tunes itself
+dotnet_diagnostic.PSH1022.severity = error # A parameterless `new EventArgs()` allocates where the shared `EventArgs.Empty` singleton would serve. Code fix uses the singleton.
dotnet_diagnostic.PSH1100.severity = error # Hot-path code should avoid System.Linq.Enumerable calls
dotnet_diagnostic.PSH1101.severity = none # LINQ terminal predicate simplification is reserved for test code; production code should avoid LINQ on hot paths
dotnet_diagnostic.PSH1102.severity = none # LINQ type-filter simplification is reserved for test code; production code should avoid LINQ on hot paths
@@ -1712,7 +1823,7 @@ dotnet_diagnostic.PSH1110.severity = error # Use the collection's own predicate
dotnet_diagnostic.PSH1111.severity = error # Use Contains for membership tests
dotnet_diagnostic.PSH1112.severity = error # Seed the collection through its constructor (fix honors performancesharp.prefer_collection_expressions)
dotnet_diagnostic.PSH1113.severity = error # Sort naturally instead of ordering by the element itself
-# dotnet_diagnostic.PSH1114.severity = error # Freeze static lookup collections (opt-in; freezing trades slower construction for faster reads)
+dotnet_diagnostic.PSH1114.severity = none # Freeze static lookup collections that are never mutated. Opt-in.
dotnet_diagnostic.PSH1115.severity = error # Insert-if-absent should probe the dictionary once
dotnet_diagnostic.PSH1116.severity = error # Probe string-keyed collections with a span through GetAlternateLookup
dotnet_diagnostic.PSH1117.severity = error # Ask the collection whether it is empty
@@ -1750,16 +1861,18 @@ dotnet_diagnostic.PSH1222.severity = error # Concatenate slices without material
dotnet_diagnostic.PSH1223.severity = error # A reused composite format string is re-parsed on every call
dotnet_diagnostic.PSH1224.severity = error # Convert bytes to hex in one call, not by building the string twice
dotnet_diagnostic.PSH1225.severity = error # Decode bytes to a string in one call, without a throwaway char[]
+dotnet_diagnostic.PSH1226.severity = error # A string's `ToCharArray()` result is only iterated, allocating a throwaway `char[]`; iterate the string directly. Code fix drops the copy.
+dotnet_diagnostic.PSH1227.severity = error # A cheaper equivalent exists — `string.CompareOrdinal` over `Compare(…, Ordinal)`, `Debug.Fail` over `Debug.Assert(false, …)`. Info. Code fix rewrites the call.
dotnet_diagnostic.PSH1300.severity = error # Use System.Threading.Lock for a dedicated lock object
dotnet_diagnostic.PSH1301.severity = error # Do not wrap a single task in WhenAll or WaitAll
dotnet_diagnostic.PSH1302.severity = error # TaskCompletionSource should run continuations asynchronously
dotnet_diagnostic.PSH1303.severity = error # Do not block an async method with Thread.Sleep
dotnet_diagnostic.PSH1304.severity = error # Use PeriodicTimer instead of pacing a loop with Task.Delay
dotnet_diagnostic.PSH1305.severity = error # Enumerate a ConcurrentDictionary directly, not its Keys/Values snapshots
-# dotnet_diagnostic.PSH1306.severity = error # Guard one-time execution with an interlocked latch (opt-in; thread-safety needs are contextual)
+dotnet_diagnostic.PSH1306.severity = none # Guard one-time execution with an interlocked latch. Opt-in.
dotnet_diagnostic.PSH1307.severity = error # Access interlocked fields with Volatile
dotnet_diagnostic.PSH1308.severity = error # Return the completed task instead of Task.FromResult
-# dotnet_diagnostic.PSH1309.severity = error # Register cancellation callbacks without flowing the execution context (opt-in; changes AsyncLocal visibility)
+dotnet_diagnostic.PSH1309.severity = none # Register cancellation callbacks without flowing the execution context. Opt-in.
dotnet_diagnostic.PSH1310.severity = error # Dispose IAsyncDisposable resources with await using in async code
dotnet_diagnostic.PSH1311.severity = error # Remove a pass-through async state machine and return the task directly
dotnet_diagnostic.PSH1312.severity = error # Return a completed task instead of null
@@ -1777,7 +1890,7 @@ dotnet_diagnostic.PSH1406.severity = error # Ask Regex for the answer directly
dotnet_diagnostic.PSH1407.severity = error # Query the dictionary, not its Keys view
dotnet_diagnostic.PSH1408.severity = error # Measure elapsed time with Stopwatch timestamps
dotnet_diagnostic.PSH1409.severity = error # Use the built-in throw helpers for argument guards
-# dotnet_diagnostic.PSH1410.severity = error # Mark trivial forwarders for aggressive inlining (opt-in; opinionated convention)
+dotnet_diagnostic.PSH1410.severity = none # Mark trivial forwarders for aggressive inlining. Opt-in.
dotnet_diagnostic.PSH1411.severity = error # Seal non-public types nothing derives from so the JIT can devirtualize
dotnet_diagnostic.PSH1412.severity = error # Use Random.Shared instead of allocating a Random
dotnet_diagnostic.PSH1413.severity = error # Read the Unix epoch from the framework, not a hand-built DateTime
@@ -1787,6 +1900,7 @@ dotnet_diagnostic.PSH1416.severity = error # Cache the serializer options instea
dotnet_diagnostic.PSH1417.severity = error # Do not compute an expensive argument for an assertion
dotnet_diagnostic.PSH1418.severity = error # An HttpClient is constructed on every call
dotnet_diagnostic.PSH1419.severity = error # A time-zone is resolved with a platform-specific id instead of the cross-platform API
+dotnet_diagnostic.PSH1420.severity = error # A shareable client held in an instance field of an Azure Functions worker class is rebuilt on every invocation, leaking sockets and connections; share a static/singleton client or inject `IHttpClientFactory`.
# ASP.NET Core - inert in this repo (no route handlers or middleware), enabled so the set stays complete
dotnet_diagnostic.PSH1500.severity = error # A minimal API handler returns Results instead of TypedResults, boxing the result
@@ -1794,6 +1908,13 @@ dotnet_diagnostic.PSH1501.severity = error # Middleware uses the legacy nested-d
dotnet_diagnostic.PSH1502.severity = error # A route handler returns a deferred sequence the serializer enumerates on the request thread
dotnet_diagnostic.PSH1503.severity = error # Response caching is used where server-side output caching applies
dotnet_diagnostic.PSH1505.severity = error # Exceptions are handled in an MVC exception filter instead of an IExceptionHandler
+dotnet_diagnostic.PSH1506.severity = error # The HTTP request or response body is read or written synchronously (`ReadToEnd`, `Body.Read`, `Body.Write`), which blocks a thread on Kestrel and buffers the whole payload; use the async overload. Code fix awaits it when the method is already async.
+
+# Blazor
+dotnet_diagnostic.PSH1600.severity = error # A delegate captured per iteration inside a component render loop reallocates on every render (measured ~128 B per row per render) and churns the diff; hoist it to a cached delegate or a precomputed per-item model.
+dotnet_diagnostic.PSH1601.severity = error # A JavaScript-interop call is issued once per loop iteration; on Interactive Server each is a separate SignalR round-trip. Batch into a single call over the collection.
+dotnet_diagnostic.PSH1602.severity = error # `StateHasChanged` is called unconditionally in `OnAfterRender`/`OnAfterRenderAsync`, scheduling another render every time — a runaway loop. Guard it with `firstRender` or a state flag.
+dotnet_diagnostic.PSH1603.severity = error # A non-delegate allocation is used as a component-parameter value inside a render loop, allocating per item and forcing the child to re-render each pass. Sibling of PSH1600.
###################
# SecuritySharp Analyzers (SES)
@@ -1835,10 +1956,10 @@ dotnet_diagnostic.SES1303.severity = error # Regular-expression pattern must not
dotnet_diagnostic.SES1304.severity = error # An archive entry name must not build a write path without a containment check
dotnet_diagnostic.SES1305.severity = error # Do not build a storage path from an uploaded file name
dotnet_diagnostic.SES1306.severity = error # Do not compile or execute non-constant C# via the scripting API
-dotnet_diagnostic.SES1310.severity = error # A directory bind is performed without authenticating
dotnet_diagnostic.SES1307.severity = error # Path.GetTempFileName creates a predictable, world-readable temporary file
dotnet_diagnostic.SES1308.severity = error # A file or directory is created group- or world-writable
dotnet_diagnostic.SES1309.severity = error # An XSLT stylesheet is loaded with embedded script enabled
+dotnet_diagnostic.SES1310.severity = error # A directory bind is performed without authenticating
# Serialization
dotnet_diagnostic.SES1401.severity = error # A type resolved from non-constant data must not be instantiated or deserialized
@@ -1873,20 +1994,7 @@ dotnet_diagnostic.SES1604.severity = error # Prompt-template input encoding must
dotnet_diagnostic.SES1605.severity = error # AI instrumentation must not enable sensitive-data capture
dotnet_diagnostic.SES1606.severity = error # Do not fetch model weights over cleartext HTTP
-# RoslynCommonAnalyzers rules added to reach 3.37.0 (on-by-default enforced; opt-in left off)
-dotnet_diagnostic.PSH1022.severity = error # A parameterless `new EventArgs()` allocates where the shared `EventArgs.Empty` singleton would serve. Code fix uses the singleton.
-dotnet_diagnostic.PSH1114.severity = none # Freeze static lookup collections that are never mutated. Opt-in.
-dotnet_diagnostic.PSH1226.severity = error # A string's `ToCharArray()` result is only iterated, allocating a throwaway `char[]`; iterate the string directly. Code fix drops the copy.
-dotnet_diagnostic.PSH1227.severity = error # A cheaper equivalent exists — `string.CompareOrdinal` over `Compare(…, Ordinal)`, `Debug.Fail` over `Debug.Assert(false, …)`. Info. Code fix rewrites the call.
-dotnet_diagnostic.PSH1306.severity = none # Guard one-time execution with an interlocked latch. Opt-in.
-dotnet_diagnostic.PSH1309.severity = none # Register cancellation callbacks without flowing the execution context. Opt-in.
-dotnet_diagnostic.PSH1410.severity = none # Mark trivial forwarders for aggressive inlining. Opt-in.
-dotnet_diagnostic.PSH1420.severity = error # A shareable client held in an instance field of an Azure Functions worker class is rebuilt on every invocation, leaking sockets and connections; share a static/singleton client or inject `IHttpClientFactory`.
-dotnet_diagnostic.PSH1506.severity = error # The HTTP request or response body is read or written synchronously (`ReadToEnd`, `Body.Read`, `Body.Write`), which blocks a thread on Kestrel and buffers the whole payload; use the async overload. Code fix awaits it when the method is already async.
-dotnet_diagnostic.PSH1600.severity = error # A delegate captured per iteration inside a component render loop reallocates on every render (measured ~128 B per row per render) and churns the diff; hoist it to a cached delegate or a precomputed per-item model.
-dotnet_diagnostic.PSH1601.severity = error # A JavaScript-interop call is issued once per loop iteration; on Interactive Server each is a separate SignalR round-trip. Batch into a single call over the collection.
-dotnet_diagnostic.PSH1602.severity = error # `StateHasChanged` is called unconditionally in `OnAfterRender`/`OnAfterRenderAsync`, scheduling another render every time — a runaway loop. Guard it with `firstRender` or a state flag.
-dotnet_diagnostic.PSH1603.severity = error # A non-delegate allocation is used as a component-parameter value inside a render loop, allocating per item and forcing the child to re-render each pass. Sibling of PSH1600.
+# Web UI trust boundaries
dotnet_diagnostic.SES1701.severity = error # Raw HTML is rendered from a non-constant value (`MarkupString`/`AddMarkupContent`), bypassing automatic encoding — an XSS risk. Sanitizer allow-list via `securitysharp.SES1701.sanitizers`.
dotnet_diagnostic.SES1702.severity = error # A JavaScript-interop call targets a script-evaluation primitive (`eval`, `Function`, `document.write`), turning interop into a script-injection channel.
dotnet_diagnostic.SES1703.severity = error # `[Authorize]` on a non-routable component enforces nothing — authorization runs as a routing concern. Exempt types via `securitysharp.SES1703.exempt_types`.
@@ -1897,164 +2005,20 @@ dotnet_diagnostic.SES1707.severity = error # A secret-shaped literal appears in
dotnet_diagnostic.SES1708.severity = error # `CircuitOptions.DetailedErrors` is enabled, shipping server exception detail to every connected client.
dotnet_diagnostic.SES1709.severity = error # `SerializeAllClaims` serializes every claim into client-readable WebAssembly authentication state, exposing internal ids, tokens, and PII.
dotnet_diagnostic.SES1710.severity = error # Antiforgery validation is disabled on a form (`[RequireAntiforgeryToken(required: false)]`), removing CSRF protection.
-dotnet_diagnostic.SST1101.severity = none # see docs/rules/SST1101.md
-dotnet_diagnostic.SST1220.severity = error # An all-named argument list is in a different order than the parameters. Code fix reorders it to declaration order. Info.
-dotnet_diagnostic.SST1221.severity = error # `where` constraint clauses are not ordered to match the type-parameter list. Code fix reorders them. Info.
-dotnet_diagnostic.SST1321.severity = none # Public APIs intentionally use Async to describe asynchronous observable behavior without returning an awaitable.
-dotnet_diagnostic.SST1434.severity = error # see docs/rules/SST1434.md
-dotnet_diagnostic.SST1525.severity = error # A multi-statement `switch` section has no braces; the braces-on policy extends to switch sections. Code fix wraps it.
-dotnet_diagnostic.SST1526.severity = none # A wrapped binary expression places the operator inconsistently. Configurable (`before`/`after`, default before). Opt-in.
-dotnet_diagnostic.SST1527.severity = none # The `=>` of an expression-bodied member wraps inconsistently. Configurable. Opt-in.
-dotnet_diagnostic.SST1528.severity = none # The `=` of a wrapped initializer wraps inconsistently. Configurable. Opt-in.
-dotnet_diagnostic.SST1529.severity = none # A wrapped `?.`/`.` call chain places the break inconsistently. Configurable. Opt-in.
-dotnet_diagnostic.SST1530.severity = none # A newline sits between a type declaration and its base list. Code fix pulls the base list onto the declaration line. Opt-in.
-dotnet_diagnostic.SST1531.severity = none # A short object initializer is split across lines. Code fix collapses it when it fits. Opt-in.
-dotnet_diagnostic.SST1532.severity = none # A file mixes line endings. Configurable (`lf`/`crlf`, default lf). Opt-in.
-dotnet_diagnostic.SST1533.severity = none # A source file contains no code. Opt-in.
-dotnet_diagnostic.SST1660.severity = error # The ` ` tags are not in parameter order. Code fix reorders them. Info.
-dotnet_diagnostic.SST1661.severity = error # A snippet uses ``/`` mismatched to single- vs multi-line content. Code fix swaps the tag. Info.
-dotnet_diagnostic.SST1662.severity = none # A thrown exception type has no `` documentation. Code fix adds the skeleton. Opt-in.
-dotnet_diagnostic.SST1663.severity = none # A `//` comment before a public member reads like a summary; use `///`. Code fix converts it. Opt-in.
-dotnet_diagnostic.SST1664.severity = none # A summary separates paragraphs with blank lines instead of ``. Code fix wraps them. Opt-in.
-dotnet_diagnostic.SST1708.severity = error # An extension method never uses its `this` receiver, so it need not be an extension.
-dotnet_diagnostic.SST1709.severity = none # A method in a `*Extensions` class whose first parameter lacks `this`. Code fix converts it to an extension block. Opt-in.
-dotnet_diagnostic.SST1804.severity = error # A positional record has an empty `{ }` body where `;` would do. Code fix rewrites it. Info.
-dotnet_diagnostic.SST1900.severity = error # see docs/rules/SST1900.md
-dotnet_diagnostic.SST2229.severity = error # see docs/rules/SST2229.md
-dotnet_diagnostic.SST2230.severity = error # see docs/rules/SST2230.md
-dotnet_diagnostic.SST2233.severity = none # see docs/rules/SST2233.md
-dotnet_diagnostic.SST2254.severity = none # A target-typed `new()` is written where an explicit type reads more clearly; the code fix restores `new TypeName(...)`. Opt-in — the counterpart to SST2202's target-typed direction, so a team enables at most one.
-dotnet_diagnostic.SST2255.severity = error # A hand-written null-or-empty string test. Code fix uses `string.IsNullOrEmpty`.
-dotnet_diagnostic.SST2256.severity = error # An extension method called in static form. Code fix rewrites to instance form. Info.
-dotnet_diagnostic.SST2257.severity = error # A lambda block body that is a single `return`. Code fix uses an expression body. Info.
-dotnet_diagnostic.SST2258.severity = error # A redundant explicit delegate wrapper (`new EventHandler(M)`). Code fix drops it. Info.
-dotnet_diagnostic.SST2259.severity = error # A stray `;` after a type declaration. Code fix removes it. Info.
-dotnet_diagnostic.SST2260.severity = error # An `as` cast to a type the operand already has. Code fix removes it. Info.
-dotnet_diagnostic.SST2261.severity = error # `(x && !y)
-dotnet_diagnostic.SST2262.severity = error # A raw string literal whose content needs no raw syntax. Code fix demotes it. Info.
-dotnet_diagnostic.SST2263.severity = error # An infinite loop whose body re-derives its stop condition. Code fix hoists the condition into the header. Info.
-dotnet_diagnostic.SST2264.severity = error # A numeric literal cast to an enum. Code fix names the member.
-dotnet_diagnostic.SST2265.severity = none # Consecutive fluent calls on one receiver can fold into a chain. Opt-in.
-dotnet_diagnostic.SST2266.severity = none # A local read exactly once can be inlined into that use. Opt-in.
-dotnet_diagnostic.SST2267.severity = none # Infinite loops written in mixed `while(true)`/`for(;;)` styles. Configurable. Opt-in.
-dotnet_diagnostic.SST2268.severity = none # Inconsistent `()` on object creation with an initializer. Configurable. Opt-in.
-dotnet_diagnostic.SST2269.severity = none # Inconsistent parentheses around a conditional's condition. Configurable. Opt-in.
-dotnet_diagnostic.SST2270.severity = none # Inconsistent explicit-vs-implicit array-creation type. Configurable. Opt-in.
-dotnet_diagnostic.SST2271.severity = none # `var`-vs-explicit local type per the configured preference. Configurable. Opt-in.
-dotnet_diagnostic.SST2272.severity = none # `[Flags]` member values written as mixed decimals and shifts. Configurable. Opt-in.
-dotnet_diagnostic.SST2273.severity = none # A function or loop body wraps its work in a trailing `if` that could be an early-exit guard clause. Code fix inverts it. Configurable threshold. Opt-in.
-dotnet_diagnostic.SST2274.severity = error # A value assigned with `as` and then null-checked is an `is` declaration pattern in one step. Code fix rewrites it.
-dotnet_diagnostic.SST2275.severity = error # A method whose block body is a single statement can use an expression body `=> expr`. Code fix rewrites it.
-dotnet_diagnostic.SST2276.severity = none # A constructor whose block body is a single statement can use an expression body. Code fix rewrites it. Opt-in.
-dotnet_diagnostic.SST2277.severity = none # An operator whose block body is a single `return` can use an expression body. Code fix rewrites it. Opt-in.
-dotnet_diagnostic.SST2278.severity = none # A conversion operator whose block body is a single `return` can use an expression body. Code fix rewrites it. Opt-in.
-dotnet_diagnostic.SST2279.severity = error # A get-only property whose getter is a single `return` can use a whole-member expression body. Code fix rewrites it.
-dotnet_diagnostic.SST2280.severity = error # A get-only indexer whose getter is a single `return` can use a whole-member expression body. Code fix rewrites it.
-dotnet_diagnostic.SST2281.severity = error # A local function whose block body is a single statement can use an expression body. Code fix rewrites it.
-dotnet_diagnostic.SST2282.severity = error # A reference-type `ReferenceEquals` check against `null` reads as an `is null` / `is not null` pattern. Code fix rewrites it.
-dotnet_diagnostic.SST2283.severity = error # A null guard that throws right before assigning the guarded value can fold into the assignment as `?? throw`. Code fix rewrites it.
-dotnet_diagnostic.SST2329.severity = error # A `[Flags]` enum declares no zero-valued member. Code fix adds `None = 0`.
-dotnet_diagnostic.SST2330.severity = error # A `[Flags]` member is a numeric literal equal to a combination of others (`All = 7`). Code fix writes `A
-dotnet_diagnostic.SST2331.severity = none # An enum leaves member values implicit, so their numbers depend on declaration order. Opt-in.
-dotnet_diagnostic.SST2332.severity = error # An auto-property's `private set` is only written during construction; make it get-only.
-dotnet_diagnostic.SST2333.severity = none # A generic comparison/equality contract is implemented without its non-generic counterpart. Opt-in.
-dotnet_diagnostic.SST2334.severity = none # A publicly visible type has no `[DebuggerDisplay]`. Opt-in.
-dotnet_diagnostic.SST2335.severity = none # Parts of a partial type disagree on the `static` modifier. Opt-in.
-dotnet_diagnostic.SST2491.severity = error # A non-`async` method returns an awaitable from inside `using`/`try-finally`/`lock`, so the resource is torn down before the task completes. Code fix makes it `async`.
-dotnet_diagnostic.SST2492.severity = error # A null-guard throws on a parameter the signature declares may be null.
-dotnet_diagnostic.SST2493.severity = error # `== null`/`!= null` on an unconstrained generic `T`. Code fix uses `is null`/`is not null`.
-dotnet_diagnostic.SST2494.severity = error # A `??` whose left operand is a constant null, so the right is always taken. Code fix folds it.
-dotnet_diagnostic.SST2495.severity = error # A `[Flags]` combination includes an operand whose bits another already covers. Code fix removes it.
-dotnet_diagnostic.SST2496.severity = error # An explicit `Dispose`/`Close` on a resource an enclosing `using` already disposes. Code fix removes it. Info.
-dotnet_diagnostic.SST2700.severity = error # An MVC route template contains a backslash; route segments are separated by `/`, so the route is unreachable. Code fix replaces `\` with `/`.
-dotnet_diagnostic.SST2701.severity = error # A `[JSInvokable]` method is not public, so JavaScript interop cannot call it. Code fix makes it public.
-dotnet_diagnostic.SST2702.severity = error # A `[SupplyParameterFromQuery]` property has a type the framework cannot bind from the query string, which throws at runtime.
-dotnet_diagnostic.SST2703.severity = error # A routable component's route constraint (`{id:int}`) disagrees with the matching `[Parameter]` CLR type, so the route silently fails to match.
-dotnet_diagnostic.SST2704.severity = error # A public action on an `[ApiController]` declares no HTTP-verb attribute, so it answers every verb and can make routing ambiguous.
-dotnet_diagnostic.SST2705.severity = none # A bound model member is a non-nullable value type with no required marker, so a request that omits it binds the default with no error. Opt-in.
-dotnet_diagnostic.SST2706.severity = error # A Windows Forms entry point carries neither `[STAThread]` nor `[MTAThread]`; without STA, clipboard, drag-and-drop, and common dialogs misbehave. Code fix adds `[STAThread]`.
-dotnet_diagnostic.SST2707.severity = none # A fire-and-forget `Task.Run` in a controller captures the request's `HttpContext`, which is disposed when the request ends, so the background work throws `ObjectDisposedException`. Opt-in.
-dotnet_diagnostic.SST2708.severity = error # A component subscribes to an event in a lifecycle method but never unsubscribes, so the event source keeps the component alive — a per-session leak on a Server circuit.
-dotnet_diagnostic.SST2709.severity = error # `StateHasChanged` is called while the component is being disposed, which the renderer no longer supports and throws.
-dotnet_diagnostic.SST2710.severity = error # `StateHasChanged` is called directly from a timer callback, off the renderer's dispatcher; marshal it with `InvokeAsync(StateHasChanged)`.
-dotnet_diagnostic.SST2711.severity = error # A synchronous component lifecycle method is overridden as `async void`, which the framework never awaits; override the `…Async` twin returning `Task`. Code fix rewrites the signature.
-dotnet_diagnostic.SST2712.severity = error # An `[Inject]`/`[CascadingParameter]` property has no setter, so the framework's reflection-based binding leaves it null. Code fix adds a setter.
-dotnet_diagnostic.SST2713.severity = error # A `DotNetObjectReference.Create(this)` is passed inline and never stored, so nothing can dispose it and it leaks on the JavaScript side.
-# In-box IDE code-style rules disabled where a StyleSharp rule covers the same shape (avoids double-reporting under EnforceCodeStyleInBuild)
-dotnet_diagnostic.IDE0001.severity = none # covered by SST1116
-dotnet_diagnostic.IDE0003.severity = none # covered by SST1117
-dotnet_diagnostic.IDE0005.severity = none # covered by SST1445
-dotnet_diagnostic.IDE0010.severity = none # covered by SST2205
-dotnet_diagnostic.IDE0011.severity = none # covered by SST1503
-dotnet_diagnostic.IDE0017.severity = none # covered by SST1193
-dotnet_diagnostic.IDE0018.severity = none # covered by SST2208
-dotnet_diagnostic.IDE0020.severity = none # covered by SST2007
-dotnet_diagnostic.IDE0027.severity = none # covered by SST2219
-dotnet_diagnostic.IDE0029.severity = none # covered by SST1195
-dotnet_diagnostic.IDE0030.severity = none # covered by SST1195
-dotnet_diagnostic.IDE0032.severity = none # covered by SST1420
-dotnet_diagnostic.IDE0033.severity = none # covered by SST1142
-dotnet_diagnostic.IDE0034.severity = none # covered by SST1188
-dotnet_diagnostic.IDE0036.severity = none # covered by SST1206
-dotnet_diagnostic.IDE0037.severity = none # covered by SST2216
-dotnet_diagnostic.IDE0039.severity = none # covered by SST2228
-dotnet_diagnostic.IDE0040.severity = none # covered by SST1400
-dotnet_diagnostic.IDE0045.severity = none # covered by SST1198
-dotnet_diagnostic.IDE0046.severity = none # covered by SST1197
-dotnet_diagnostic.IDE0051.severity = none # covered by SST1440
-dotnet_diagnostic.IDE0053.severity = none # covered by SST2257
-dotnet_diagnostic.IDE0054.severity = none # covered by SST1185
-dotnet_diagnostic.IDE0056.severity = none # covered by SST2203
-dotnet_diagnostic.IDE0062.severity = none # covered by SST2235
-dotnet_diagnostic.IDE0063.severity = none # covered by SST2236
-dotnet_diagnostic.IDE0065.severity = none # covered by SST1200
-dotnet_diagnostic.IDE0070.severity = none # covered by SST2217
-dotnet_diagnostic.IDE0071.severity = none # covered by SST2220
-dotnet_diagnostic.IDE0072.severity = none # covered by SST2206
-dotnet_diagnostic.IDE0073.severity = none # covered by SST1633
-dotnet_diagnostic.IDE0074.severity = none # covered by SST2223
-dotnet_diagnostic.IDE0076.severity = none # covered by SST1457
-dotnet_diagnostic.IDE0077.severity = none # covered by SST1458
-dotnet_diagnostic.IDE0080.severity = none # covered by SST2209
-dotnet_diagnostic.IDE0082.severity = none # covered by SST1199
-dotnet_diagnostic.IDE0083.severity = none # covered by SST2006
-dotnet_diagnostic.IDE0090.severity = none # covered by SST2202
-dotnet_diagnostic.IDE0100.severity = none # covered by SST1143
-dotnet_diagnostic.IDE0110.severity = none # covered by SST2213
-dotnet_diagnostic.IDE0150.severity = none # covered by SST2231
-dotnet_diagnostic.IDE0161.severity = none # covered by SST2237
-dotnet_diagnostic.IDE0170.severity = none # covered by SST2238
-dotnet_diagnostic.IDE0180.severity = none # covered by SST2215
-dotnet_diagnostic.IDE0200.severity = none # covered by SST2239
-dotnet_diagnostic.IDE0220.severity = none # covered by SST2225
-dotnet_diagnostic.IDE0230.severity = none # covered by SST2212
-dotnet_diagnostic.IDE0240.severity = none # covered by SST2210
-dotnet_diagnostic.IDE0241.severity = none # covered by SST2211
-dotnet_diagnostic.IDE0251.severity = none # covered by SST1460
-dotnet_diagnostic.IDE0270.severity = none # covered by SST1195
-dotnet_diagnostic.IDE0280.severity = none # covered by SST1463
-dotnet_diagnostic.IDE0290.severity = none # covered by SST2241
-dotnet_diagnostic.IDE0301.severity = none # covered by SST2100
-dotnet_diagnostic.IDE0302.severity = none # covered by SST2102
-dotnet_diagnostic.IDE0303.severity = none # covered by SST2103
-dotnet_diagnostic.IDE0304.severity = none # covered by SST2104
-dotnet_diagnostic.IDE0305.severity = none # covered by SST2105
-dotnet_diagnostic.IDE0340.severity = none # covered by SST2232
-dotnet_diagnostic.IDE0350.severity = none # covered by SST2218
-dotnet_diagnostic.IDE0380.severity = none # covered by SST1455
-dotnet_diagnostic.IDE1005.severity = none # covered by SST2240
-
-###################
-# PublicApiAnalyzers (RSxxxx) - public API surface tracking
+
###################
+# Microsoft.CodeAnalysis.PublicApiAnalyzers (RS)
+###################
+# Public API surface tracking
dotnet_diagnostic.RS0016.severity = error # public symbol missing from the PublicAPI baseline
dotnet_diagnostic.RS0017.severity = error # PublicAPI baseline entry no longer in source
###################
-# Trimming Analyzer Warnings (IL2001 - IL2123)
-# See: https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-warnings/
+# Microsoft.NET.ILLink.Analyzers (IL)
###################
+# Trimming
+# See: https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-warnings/
dotnet_diagnostic.IL2001.severity = error # Type in UnreferencedCode attribute doesn't have matching RequiresUnreferencedCode
dotnet_diagnostic.IL2002.severity = error # Method with RequiresUnreferencedCode called from code without that attribute
dotnet_diagnostic.IL2003.severity = error # RequiresUnreferencedCode attribute is only supported on methods
@@ -2170,10 +2134,8 @@ dotnet_diagnostic.IL2117.severity = error # Methods with DynamicallyAccessedMemb
dotnet_diagnostic.IL2122.severity = error # Reflection call to method with UnreferencedCode attribute cannot be statically analyzed
dotnet_diagnostic.IL2123.severity = error # DynamicallyAccessedMembers on method or parameter doesn't match overridden member
-###################
-# AOT Analyzer Warnings (IL3xxx)
+# Native AOT
# See: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/warnings/
-###################
dotnet_diagnostic.IL3050.severity = error # Using member annotated with RequiresDynamicCode
dotnet_diagnostic.IL3051.severity = error # RequiresDynamicCode attribute is only supported on methods and constructors
dotnet_diagnostic.IL3052.severity = error # RequiresDynamicCode attribute on type is not supported
@@ -2184,8 +2146,15 @@ dotnet_diagnostic.IL3056.severity = error # MakeGenericMethod on non-supported m
dotnet_diagnostic.IL3057.severity = error # Reflection access to generic parameter requires dynamic code
###################
-# SonarAnalyzer (Sxxxx) - Blocker Bug
+# SonarAnalyzer.CSharp (S)
###################
+# Repository suppressions
+dotnet_diagnostic.S1075.severity = none # Hardcoded URI — canonical SourceLink hosts are the point
+dotnet_diagnostic.S2436.severity = none # Too many generic parameters — needed for the projector overload
+dotnet_diagnostic.S4036.severity = none # PATH-relative process spawn — benchmark only, trusted env
+dotnet_diagnostic.S8969.severity = none # Nullability inference is inconsistent across the repository's target frameworks
+
+# Blocker bugs
dotnet_diagnostic.S1048.severity = none # Finalizers should not throw exceptions — covered by SST1485
dotnet_diagnostic.S2190.severity = none # Loops and recursions should not be infinite
dotnet_diagnostic.S2275.severity = none # Composite format strings should not lead to unexpected behavior at runtime - DUPLICATE CA2241
@@ -2197,9 +2166,7 @@ dotnet_diagnostic.S3869.severity = none # "SafeHandle.DangerousGetHandle" should
dotnet_diagnostic.S3889.severity = none # "Thread.Resume" and "Thread.Suspend" should not be used -> replaced by obsolete or compiler
dotnet_diagnostic.S4159.severity = none # Classes should implement their "ExportAttribute" interfaces — covered by SST2472
-###################
-# SonarAnalyzer (Sxxxx) - Critical Bug
-###################
+# Critical bugs
dotnet_diagnostic.S2551.severity = none # Shared resources should not be used for locking — covered by SST1902
dotnet_diagnostic.S2952.severity = none # Classes should "Dispose" of members from the classes' own "Dispose" methods -> replaced by SST2315
dotnet_diagnostic.S3449.severity = none # Right operands of shift operators should be integers -> replaced by SST1478
@@ -2210,9 +2177,7 @@ dotnet_diagnostic.S4586.severity = none # Non-async "Task/Task" methods shoul
dotnet_diagnostic.S5856.severity = none # Regular expressions should be syntactically valid — covered by SST2444
dotnet_diagnostic.S6674.severity = none # Log message template should be syntactically correct — covered by SST2441
-###################
-# SonarAnalyzer (Sxxxx) - Major Bug
-###################
+# Major bugs
dotnet_diagnostic.S1244.severity = none # Floating point numbers should not be tested for equality — covered by SST1473
dotnet_diagnostic.S1656.severity = none # Variables should not be self-assigned — covered by SST1189
dotnet_diagnostic.S1751.severity = none # Loops with at most one iteration should be refactored - covered by SST1444
@@ -2262,9 +2227,7 @@ dotnet_diagnostic.S6798.severity = none # [JSInvokable] attribute should only be
dotnet_diagnostic.S6800.severity = none # Component parameter type should match the route parameter type constraint -> replaced by SST2703
dotnet_diagnostic.S6930.severity = none # Backslash should be avoided in route templates -> replaced by SST2700
-###################
-# SonarAnalyzer (Sxxxx) - Minor Bug
-###################
+# Minor bugs
dotnet_diagnostic.S1206.severity = none # "Equals(Object)" and "GetHashCode()" should be overridden in pairs - DUPLICATE CA2218
dotnet_diagnostic.S1226.severity = none # Method parameters, caught exceptions and foreach variables' initial values should not be ignored
dotnet_diagnostic.S2183.severity = none # Integral numbers should not be shifted by zero or more than their number of bits-1 — covered by SST1478
@@ -2279,17 +2242,13 @@ dotnet_diagnostic.S3397.severity = none # "base.Equals" should not be used to ch
dotnet_diagnostic.S3456.severity = none # "string.ToCharArray()" and "ReadOnlySpan.ToArray()" should not be called redundantly — covered by PSH1217
dotnet_diagnostic.S3887.severity = none # Mutable, non-private fields should not be "readonly" — covered by SST2322
-###################
-# SonarAnalyzer (Sxxxx) - Blocker Vulnerability
-###################
+# Blocker vulnerabilities
dotnet_diagnostic.S2115.severity = none # A secure password should be used when connecting to a database -> replaced by SES1203
dotnet_diagnostic.S2755.severity = none # XML parsers should not be vulnerable to XXE attacks -> replaced by CA3075
dotnet_diagnostic.S3884.severity = none # "CoSetProxyBlanket" and "CoInitializeSecurity" should not be used -> replaced by obsolete (COM interop security)
dotnet_diagnostic.S6418.severity = none # Secrets should not be hard-coded — covered by SES1201
-###################
-# SonarAnalyzer (Sxxxx) - Critical Vulnerability
-###################
+# Critical vulnerabilities
dotnet_diagnostic.S4423.severity = none # Weak SSL/TLS protocols should not be used -> replaced by CA5397/CA5398
dotnet_diagnostic.S4426.severity = none # Cryptographic keys should be robust -> replaced by CA5385 (RSA) / CA5384 (DSA)
dotnet_diagnostic.S4433.severity = none # LDAP connections should be authenticated -> replaced by SES1310
@@ -2300,9 +2259,7 @@ dotnet_diagnostic.S5542.severity = none # Encryption algorithms should be used w
dotnet_diagnostic.S5547.severity = none # Cipher algorithms should be robust -> replaced by CA5351
dotnet_diagnostic.S5659.severity = none # JWT should be signed and verified with strong cipher algorithms -> replaced by SES1503
-###################
-# SonarAnalyzer (Sxxxx) - Major Vulnerability
-###################
+# Major vulnerabilities
dotnet_diagnostic.S2068.severity = none # Credentials should not be hard-coded -> replaced by SES1201
dotnet_diagnostic.S2612.severity = none # File permissions should not be set to world-accessible values -> replaced by SES1308
dotnet_diagnostic.S4211.severity = none # Members should not have conflicting transparency annotations -> replaced by obsolete (Code Access Security)
@@ -2310,9 +2267,7 @@ dotnet_diagnostic.S4212.severity = none # Serialization constructors should be s
dotnet_diagnostic.S6377.severity = none # XML signatures should be validated securely -> replaced by SES1008
dotnet_diagnostic.S7039.severity = none # Content Security Policies should be restrictive -> replaced by SES1515
-###################
-# SonarAnalyzer (Sxxxx) - Blocker Code Smell
-###################
+# Blocker code smells
dotnet_diagnostic.S1147.severity = none # Exit methods should not be called — covered by SST2321
dotnet_diagnostic.S1451.severity = none # Track lack of copyright and license headers
dotnet_diagnostic.S2178.severity = none # Short-circuit logic should be used in boolean contexts — covered by SST2415
@@ -2335,9 +2290,7 @@ dotnet_diagnostic.S4462.severity = none # Calls to "async" methods should not be
dotnet_diagnostic.S6422.severity = none # Calls to "async" methods should not be blocking in Azure Functions — covered by PSH1315
dotnet_diagnostic.S6424.severity = none # Interfaces for durable entities should satisfy the restrictions -> off: Durable Entity-specific; not used in this library
-###################
-# SonarAnalyzer (Sxxxx) - Critical Code Smell
-###################
+# Critical code smells
dotnet_diagnostic.S1006.severity = none # Method overrides should not change parameter defaults — covered by SST2424
dotnet_diagnostic.S1067.severity = none # Expressions should not be too complex
dotnet_diagnostic.S1163.severity = none # Exceptions should not be thrown in finally blocks -> replaced by CA2219
@@ -2400,9 +2353,7 @@ dotnet_diagnostic.S8380.severity = none # Return types named "partial" should be
dotnet_diagnostic.S8381.severity = none # "scoped" should be escaped when used as an identifier or type name in parenthesized lambda parameter lists -> replaced by compiler
dotnet_diagnostic.S927.severity = none # Parameter names should match base declaration and other partial definitions - DUPLICATE CA1725
-###################
-# SonarAnalyzer (Sxxxx) - Major Code Smell
-###################
+# Major code smells
dotnet_diagnostic.S103.severity = none # Lines should not be too long — covered by SST1521
dotnet_diagnostic.S104.severity = none # Files should not have too many lines of code — covered by SST1522
dotnet_diagnostic.S106.severity = none # Covered by SST1449 (canonical)
@@ -2527,9 +2478,7 @@ dotnet_diagnostic.S6968.severity = none # Actions that return a value should be
dotnet_diagnostic.S881.severity = none # Increment (++) and decrement (--) operators should not be used in a method call or mixed with other operators in an expression — covered by SST2015
dotnet_diagnostic.S907.severity = none # "goto" statement should not be used — covered by SST2014
-###################
-# SonarAnalyzer (Sxxxx) - Minor Code Smell
-###################
+# Minor code smells
dotnet_diagnostic.S100.severity = none # Methods and properties should be named in PascalCase — covered by SST1300
dotnet_diagnostic.S101.severity = none # Types should be named in PascalCase — covered by SST1300
dotnet_diagnostic.S105.severity = none # Tabulation characters should not be used — covered by SST1027
@@ -2657,16 +2606,12 @@ dotnet_diagnostic.S6675.severity = none # "Trace.WriteLineIf" should not be used
dotnet_diagnostic.S6678.severity = none # Use PascalCase for named placeholders -> replaced by CA1727
dotnet_diagnostic.S818.severity = none # Literal suffixes should be upper case — covered by SST2244
-###################
-# SonarAnalyzer (Sxxxx) - Info Code Smell
-###################
+# Informational code smells
dotnet_diagnostic.S1133.severity = none # Deprecated code should be removed — covered by SST2310
dotnet_diagnostic.S1135.severity = none # Track uses of "TODO" tags -> off: FIXME comment tracker; not enforced here
dotnet_diagnostic.S1309.severity = none # Track uses of in-source issue suppressions
-###################
-# SonarAnalyzer (Sxxxx) - Uncategorized
-###################
+# Uncategorized
dotnet_diagnostic.S9999-cpd.severity = error # Copy-paste token calculator
dotnet_diagnostic.S9999-log.severity = error # Log generator
dotnet_diagnostic.S9999-metadata.severity = error # File metadata generator
@@ -2677,9 +2622,7 @@ dotnet_diagnostic.S9999-testMethodDeclaration.severity = error # Test method dec
dotnet_diagnostic.S9999-token-type.severity = error # Token type calculator
dotnet_diagnostic.S9999-warning.severity = error # Analysis Warning generator
-###################
-# SonarAnalyzer (Sxxxx) - Critical Security Hotspot
-###################
+# Critical security hotspots
dotnet_diagnostic.S2245.severity = none # Using pseudorandom number generators (PRNGs) is security-sensitive - DUPLICATE CA5394
dotnet_diagnostic.S2257.severity = none # Using non-standard cryptographic algorithms is security-sensitive -> replaced by SES1007
dotnet_diagnostic.S4502.severity = none # Disabling CSRF protections is security-sensitive -> replaced by in-box ASP.NET antiforgery analyzer
@@ -2689,9 +2632,7 @@ dotnet_diagnostic.S5042.severity = none # Expanding archive files without contro
dotnet_diagnostic.S5332.severity = none # Using clear-text protocols is security-sensitive -> replaced by SES1106
dotnet_diagnostic.S5443.severity = none # Using publicly writable directories is security-sensitive -> replaced by SES1308
-###################
-# SonarAnalyzer (Sxxxx) - Major Security Hotspot
-###################
+# Major security hotspots
dotnet_diagnostic.S1313.severity = none # Using hardcoded IP addresses is security-sensitive -> off: hardcoded-IP heuristic; too noisy to enforce
dotnet_diagnostic.S2077.severity = none # Formatting SQL queries is security-sensitive -> replaced by CA2100
dotnet_diagnostic.S5693.severity = none # Allowing requests with excessive content length is security-sensitive -> replaced by SES1505
@@ -2700,9 +2641,7 @@ dotnet_diagnostic.S5766.severity = none # Creating Serializable objects without
dotnet_diagnostic.S6444.severity = none # Not specifying a timeout for regular expressions is security-sensitive -> replaced by SES1509
dotnet_diagnostic.S6640.severity = none # Using unsafe code blocks is security-sensitive -> off: unsafe-code audit; not enforced here
-###################
-# SonarAnalyzer (Sxxxx) - Minor Security Hotspot
-###################
+# Minor security hotspots
dotnet_diagnostic.S2092.severity = none # Creating cookies without the "secure" flag is security-sensitive -> replaced by CA5382
dotnet_diagnostic.S3330.severity = none # Creating cookies without the "HttpOnly" flag is security-sensitive -> replaced by CA5383
dotnet_diagnostic.S4507.severity = none # Delivering code in production with debug features activated is security-sensitive -> off: debug features in production; partly covered by SES1506, rest not enforced
diff --git a/src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs b/src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs
index db9a5ee..816e809 100644
--- a/src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs
+++ b/src/Primitives.Shared/Signals/SignalExtensions{FromTask}.cs
@@ -102,10 +102,9 @@ public async Task HandleCancellation(Action? action)
internal async Task<(TResult Value, bool IsCanceled)> WhenCancelled(CancellationToken cancellationToken)
{
TaskCompletionSource tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
- var registration = cancellationToken.Register(
- static state => ((TaskCompletionSource)state!).TrySetCanceled(),
- tcs,
- false);
+ var registration = cancellationToken.UnsafeRegister(
+ static (state, token) => ((TaskCompletionSource)state!).TrySetCanceled(token),
+ tcs);
var cancellationTask = tcs.Task;
try
From a43d8c56e08130ebbe484b0c9eeed1b87f63469e Mon Sep 17 00:00:00 2001
From: Glenn Watson <5834289+glennawatson@users.noreply.github.com>
Date: Sat, 25 Jul 2026 18:04:01 +1000
Subject: [PATCH 5/8] style: enable remaining layout analyzers
- Enforce SST1526 through SST1533 and update existing code.
- Exclude incompatible source files from .NET Framework builds.
---
.editorconfig | 16 +--
src/Polyfills/RequiredMemberAttribute.cs | 8 +-
src/Primitives.Async.Shared/AsyncContext.cs | 6 +-
.../Mixins/AsyncContextExtensions.cs | 4 +-
.../ParityHelpers.FilterFusions.Reactive.cs | 3 +-
.../Operators/RetryWithBackoffObservable.cs | 4 +-
.../ReactiveExtensions.Retry.cs | 4 +-
.../Advanced/ExpireSignal{T}.cs | 4 +-
.../Advanced/FromAsyncTaskObservation{T}.cs | 4 +-
.../Advanced/OnErrorResumeNextSignal{T}.cs | 4 +-
...SignalOperatorMixins.ChooseSwitchSelect.cs | 6 +-
.../SignalOperatorMixins.SchedulerSignals.cs | 4 +-
src/Primitives.Shared/SignalOperatorMixins.cs | 24 ++--
.../SignalOperatorParityMixins.RxNames.cs | 12 +-
.../SignalOperatorParityMixins.cs | 12 +-
.../Signals/Signal{Factories}.cs | 12 +-
.../Signals/Signal{RxAliases}.cs | 4 +-
...LatestEnumerableSignal{TSource,TResult}.cs | 4 +-
.../ConcurrentWitnessCallsException.cs | 4 +-
.../Disposables/DisposableAsync.cs | 3 +-
.../Observables/Defer.cs | 3 +-
.../Observables/Return.cs | 3 +-
.../Operators/AnyAllAsync.cs | 10 +-
.../Operators/Blend.cs | 21 ++-
.../Operators/ChainSignalSourcesSignal{T}.cs | 12 +-
.../Operators/ContainsAsync.cs | 20 +--
.../Operators/CountAsync.cs | 15 +-
.../Operators/Distinct.cs | 3 +-
.../Operators/Expire.cs | 6 +-
.../Operators/FirstAsync.cs | 11 +-
.../Operators/ForEachAsync.cs | 11 +-
.../Operators/GroupBy.cs | 3 +-
.../Operators/LastAsync.cs | 11 +-
.../Operators/LongCountAsync.cs | 15 +-
.../Operators/OnDispose.cs | 9 +-
.../ParityHelpers.OperatorFusions.cs | 3 +-
.../Operators/ParityHelpers.Partition.cs | 3 +-
.../Operators/RefCount.cs | 3 +-
.../Operators/Shift.cs | 6 +-
.../Operators/SingleAsync.cs | 16 +--
.../Operators/SkipWhile.cs | 3 +-
.../Operators/SwitchToSignal.cs | 20 +--
.../Operators/TakeUntil.PredicateSignals.cs | 6 +-
.../Operators/TakeUntil.cs | 6 +-
.../Operators/TakeWhile.cs | 3 +-
.../Operators/Throttle.cs | 6 +-
.../Operators/ToAsyncEnumerable.cs | 4 +-
.../Operators/ToDictionaryAsync.cs | 11 +-
.../Operators/ToListAsync.cs | 11 +-
.../Operators/Unique.cs | 3 +-
.../Operators/WaitCompletionAsync.cs | 3 +-
.../ConcurrentReplayLatestSignalAsync.cs | 3 +-
...currentStatelessReplayLatestSignalAsync.cs | 3 +-
.../Options/BehaviorSignalCreationOptions.cs | 6 +-
.../ReplayLatestSignalCreationOptions.cs | 6 +-
.../Signals/Options/SignalCreationOptions.cs | 6 +-
.../Signals/SerialReplayLatestSignalAsync.cs | 3 +-
.../SerialStatelessReplayLatestSignalAsync.cs | 3 +-
.../WitnessAsync.cs | 3 +-
.../Advanced/AggregateWitness.cs | 3 +-
.../Advanced/AllPredicateWitness.cs | 3 +-
.../Advanced/AnyPredicateWitness.cs | 3 +-
.../Advanced/AppendDelegateWitness.cs | 3 +-
.../Advanced/ContainsWitness.cs | 3 +-
.../Advanced/UseSignal{TResource,T}.cs | 4 +-
.../Advanced/Witness.cs | 3 +-
.../Core/EventPattern{TEventArgs}.cs | 4 +-
.../ReactiveUI.Primitives.Core.csproj | 6 +
.../Signals/KeepWithSignal{T,TState}.cs | 6 +-
.../Signals/MapSignal{TSource,TResult}.cs | 3 +-
...ProjectedReadOnlyState{TSource,TResult}.cs | 3 +-
.../Signals/Signal{T}.cs | 4 +-
.../Signals/TapWithSignal{T,TState}.cs | 3 +-
.../FirstAsTaskHelper.cs | 3 +-
.../Operators/BinaryMinMaxObservable.cs | 3 +-
.../Operators/SynchronizeAsyncObservable.cs | 3 +-
.../R3AsyncBridgeGenerator.cs | 8 +-
.../R3BridgeGenerator.cs | 10 +-
.../ReactiveUI.Primitives.Reactive.csproj | 5 +
.../SynchronizationContextSequencer.cs | 4 +-
.../ReactiveUI.Primitives.csproj | 5 +
.../SmokeParityValidator.cs | 18 +--
.../CombineLatestArityTests.Arity10.cs | 4 +-
.../CombineLatestArityTests.Arity11.cs | 6 +-
.../CombineLatestArityTests.Arity12.cs | 6 +-
.../CombineLatestArityTests.Arity13.cs | 6 +-
.../CombineLatestArityTests.Arity14.cs | 6 +-
.../CombineLatestArityTests.Arity15.cs | 8 +-
.../CombineLatestArityTests.Arity16.cs | 28 ++--
.../CombineLatestArityTests.Arity9.cs | 4 +-
.../CombiningOperatorTests.Multicast.cs | 72 ++--------
.../CombineLatestIndexedObserverTests.cs | 3 +-
.../SyncLatestCoordinatorBaseTests.cs | 3 +-
.../SignalTests.BehaviorAndReplay.cs | 132 +++---------------
.../SignalTests.CreationOptions.cs | 6 +-
.../TimeBasedOperatorTests.cs | 4 +-
.../UnhandledExceptionCapture.cs | 4 +-
.../ReactiveComponentBaseTests.cs | 5 +-
.../AotSafeAssertionExtensions.cs | 4 +-
.../DispatchWorkItemBaseTests.cs | 3 +-
.../ConcurencyTests.cs | 4 +-
.../DispatchSequencerBaseTests.cs | 3 +-
.../EverySignalTests.cs | 5 +-
.../FatalExceptionHelperTests.cs | 4 +-
.../OnErrorResumeNextSignalTests.cs | 3 +-
.../RxNamesTests.Helpers.cs | 52 +++----
.../RxNamesTests.cs | 16 +--
.../SwitchWitnessTests.cs | 5 +-
108 files changed, 366 insertions(+), 575 deletions(-)
diff --git a/.editorconfig b/.editorconfig
index 2057a87..01cccff 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1429,14 +1429,14 @@ dotnet_diagnostic.SST1522.severity = error # A file has more code lines than the
dotnet_diagnostic.SST1523.severity = error # A member has more code lines than the configured maximum (default 60)
dotnet_diagnostic.SST1524.severity = error # A switch section has more code lines than the configured maximum (default 20)
dotnet_diagnostic.SST1525.severity = error # A multi-statement `switch` section has no braces; the braces-on policy extends to switch sections. Code fix wraps it.
-dotnet_diagnostic.SST1526.severity = none # A wrapped binary expression places the operator inconsistently. Configurable (`before`/`after`, default before). Opt-in.
-dotnet_diagnostic.SST1527.severity = none # The `=>` of an expression-bodied member wraps inconsistently. Configurable. Opt-in.
-dotnet_diagnostic.SST1528.severity = none # The `=` of a wrapped initializer wraps inconsistently. Configurable. Opt-in.
-dotnet_diagnostic.SST1529.severity = none # A wrapped `?.`/`.` call chain places the break inconsistently. Configurable. Opt-in.
-dotnet_diagnostic.SST1530.severity = none # A newline sits between a type declaration and its base list. Code fix pulls the base list onto the declaration line. Opt-in.
-dotnet_diagnostic.SST1531.severity = none # A short object initializer is split across lines. Code fix collapses it when it fits. Opt-in.
-dotnet_diagnostic.SST1532.severity = none # A file mixes line endings. Configurable (`lf`/`crlf`, default lf). Opt-in.
-dotnet_diagnostic.SST1533.severity = none # A source file contains no code. Opt-in.
+dotnet_diagnostic.SST1526.severity = error # A wrapped binary expression places the operator inconsistently. Configurable (`before`/`after`, default before). Opt-in.
+dotnet_diagnostic.SST1527.severity = error # The `=>` of an expression-bodied member wraps inconsistently. Configurable. Opt-in.
+dotnet_diagnostic.SST1528.severity = error # The `=` of a wrapped initializer wraps inconsistently. Configurable. Opt-in.
+dotnet_diagnostic.SST1529.severity = error # A wrapped `?.`/`.` call chain places the break inconsistently. Configurable. Opt-in.
+dotnet_diagnostic.SST1530.severity = error # A newline sits between a type declaration and its base list. Code fix pulls the base list onto the declaration line. Opt-in.
+dotnet_diagnostic.SST1531.severity = error # A short object initializer is split across lines. Code fix collapses it when it fits. Opt-in.
+dotnet_diagnostic.SST1532.severity = error # A file mixes line endings. Configurable (`lf`/`crlf`, default lf). Opt-in.
+dotnet_diagnostic.SST1533.severity = error # A source file contains no code. Opt-in.
# Documentation
dotnet_diagnostic.SST1600.severity = error # Externally visible members should be documented
diff --git a/src/Polyfills/RequiredMemberAttribute.cs b/src/Polyfills/RequiredMemberAttribute.cs
index f0182fa..7f4cf26 100644
--- a/src/Polyfills/RequiredMemberAttribute.cs
+++ b/src/Polyfills/RequiredMemberAttribute.cs
@@ -14,10 +14,10 @@ namespace System.Runtime.CompilerServices;
[ExcludeFromCodeCoverage]
[DebuggerNonUserCode]
[AttributeUsage(
- AttributeTargets.Class |
- AttributeTargets.Struct |
- AttributeTargets.Field |
- AttributeTargets.Property,
+ AttributeTargets.Class
+ | AttributeTargets.Struct
+ | AttributeTargets.Field
+ | AttributeTargets.Property,
AllowMultiple = false,
Inherited = false)]
internal sealed class RequiredMemberAttribute : Attribute;
diff --git a/src/Primitives.Async.Shared/AsyncContext.cs b/src/Primitives.Async.Shared/AsyncContext.cs
index 284e45d..d66f2f0 100644
--- a/src/Primitives.Async.Shared/AsyncContext.cs
+++ b/src/Primitives.Async.Shared/AsyncContext.cs
@@ -49,9 +49,9 @@ private AsyncContext()
public ISequencer? Sequencer { get; init; }
/// Gets a value indicating whether the current context uses the default task scheduler and no synchronization context.
- internal bool UsesDefaultSequencer => SynchronizationContext is null &&
- Sequencer is null &&
- (TaskScheduler is null || TaskScheduler == TaskScheduler.Default);
+ internal bool UsesDefaultSequencer => SynchronizationContext is null
+ && Sequencer is null
+ && (TaskScheduler is null || TaskScheduler == TaskScheduler.Default);
/// Creates a new AsyncContext that uses the specified SynchronizationContext for asynchronous operations.
/// The returned AsyncContext will have its TaskScheduler property set to null. Use this method
diff --git a/src/Primitives.Async.Shared/Mixins/AsyncContextExtensions.cs b/src/Primitives.Async.Shared/Mixins/AsyncContextExtensions.cs
index 3cde902..6dac57e 100644
--- a/src/Primitives.Async.Shared/Mixins/AsyncContextExtensions.cs
+++ b/src/Primitives.Async.Shared/Mixins/AsyncContextExtensions.cs
@@ -32,8 +32,8 @@ public bool IsSameAsCurrentAsyncContext()
if (@this.Sequencer is not null)
{
- return TaskScheduler.Current is AsyncContext.SequencerTaskScheduler adapter &&
- ReferenceEquals(adapter.Sequencer, @this.Sequencer);
+ return TaskScheduler.Current is AsyncContext.SequencerTaskScheduler adapter
+ && ReferenceEquals(adapter.Sequencer, @this.Sequencer);
}
return @this.TaskScheduler is not null
diff --git a/src/Primitives.Async.Shared/Operators/ParityHelpers.FilterFusions.Reactive.cs b/src/Primitives.Async.Shared/Operators/ParityHelpers.FilterFusions.Reactive.cs
index 2c2f022..7727027 100644
--- a/src/Primitives.Async.Shared/Operators/ParityHelpers.FilterFusions.Reactive.cs
+++ b/src/Primitives.Async.Shared/Operators/ParityHelpers.FilterFusions.Reactive.cs
@@ -37,8 +37,7 @@ async ValueTask IObservableAsync.SubscribeAsync(
/// Forwards for every upstream emission.
/// The downstream observer.
/// The subscribe-time cancellation token.
- internal sealed class AsSignalWitness(IObserverAsync downstream, CancellationToken subscribeToken)
- : WitnessAsync(subscribeToken)
+ internal sealed class AsSignalWitness(IObserverAsync downstream, CancellationToken subscribeToken) : WitnessAsync(subscribeToken)
{
///
protected override ValueTask OnNextAsyncCore(T value, CancellationToken cancellationToken) =>
diff --git a/src/Primitives.Extensions.Shared/Operators/RetryWithBackoffObservable.cs b/src/Primitives.Extensions.Shared/Operators/RetryWithBackoffObservable.cs
index 38ed8a3..930e654 100644
--- a/src/Primitives.Extensions.Shared/Operators/RetryWithBackoffObservable.cs
+++ b/src/Primitives.Extensions.Shared/Operators/RetryWithBackoffObservable.cs
@@ -71,8 +71,8 @@ public void OnError(Exception error)
if (_retries < policy.MaxRetries)
{
- var delay = TimeSpan.FromTicks((long)(policy.InitialDelay.Ticks *
- Math.Pow(policy.BackoffFactor, _retries)));
+ var delay = TimeSpan.FromTicks((long)(policy.InitialDelay.Ticks
+ * Math.Pow(policy.BackoffFactor, _retries)));
if (policy.MaxDelay.HasValue && delay > policy.MaxDelay.Value)
{
delay = policy.MaxDelay.Value;
diff --git a/src/Primitives.Extensions.Shared/ReactiveExtensions.Retry.cs b/src/Primitives.Extensions.Shared/ReactiveExtensions.Retry.cs
index a43b782..42f777e 100644
--- a/src/Primitives.Extensions.Shared/ReactiveExtensions.Retry.cs
+++ b/src/Primitives.Extensions.Shared/ReactiveExtensions.Retry.cs
@@ -222,8 +222,8 @@ public IObservable RetryForeverWithDelay(TimeSpan delay) =>
/// The retry count.
/// The delay.
/// An IObservable of T.
- public IObservable RetryWithFixedDelay(int retryCount, TimeSpan delay)
- => new RetryWithBackoffObservable(
+ public IObservable RetryWithFixedDelay(int retryCount, TimeSpan delay) =>
+ new RetryWithBackoffObservable(
source,
new(
retryCount,
diff --git a/src/Primitives.Shared/Advanced/ExpireSignal{T}.cs b/src/Primitives.Shared/Advanced/ExpireSignal{T}.cs
index daf8462..c3856d6 100644
--- a/src/Primitives.Shared/Advanced/ExpireSignal{T}.cs
+++ b/src/Primitives.Shared/Advanced/ExpireSignal{T}.cs
@@ -38,8 +38,8 @@ public ExpireSignal(IObservable source, TimeSpan dueTime, ISequencer sequence
///
public bool IsRequiredSubscribeOnCurrentThread() =>
- _sequencer == Sequencer.CurrentThread ||
- (_source is IRequireCurrentThread currentThread && currentThread.IsRequiredSubscribeOnCurrentThread());
+ _sequencer == Sequencer.CurrentThread
+ || (_source is IRequireCurrentThread currentThread && currentThread.IsRequiredSubscribeOnCurrentThread());
///