Do not report MA0173 when the value cannot be captured by a lambda - #1487
Merged
Merged
Conversation
The code fix moves the CompareExchange value into a lambda passed to LazyInitializer.EnsureInitialized, which does not compile when that value uses something a lambda cannot capture: a ref/out/in parameter (CS1628), a ref local or a variable of a ref struct type (CS8175), or the "this" reference of a struct (CS1673). The analyzer now walks the value operation and skips the diagnostic in those cases. The check is intentionally conservative: it scans all the descendants, including nested lambdas, so a few reportable cases are skipped instead of producing code that does not compile.
main added the MA0173 return-value exclusion (#1479), which touched the same regions of the analyzer and of the rule documentation. Both exclusions are kept: the diagnostic is skipped when the return value of CompareExchange is used and when the value cannot be captured by a lambda.
This was referenced Sep 17, 2026
Merged
Open
Open
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The MA0173 code fix rewrites
Interlocked.CompareExchange(ref field, value, null)intoLazyInitializer.EnsureInitialized(ref field, () => value). It wraps the value expression in a lambda without checking that the expression can legally live inside one, so it can turn compiling code into code that does not compile:The fixed code fails with CS1628, as a lambda cannot capture the
refparametervalue.Change
UseLazyInitializerEnsureInitializeAnalyzernow walks the value operation before reporting and skips the diagnostic when any descendant is something a lambda cannot capture:ref/out/in/ref readonlyparameter referencereflocal referenceref structtypethisof astructNotes for the reviewer
EnsureInitialized", so when the lambda form cannot exist there is nothing to report. The fixer is only reachable through this diagnostic, so it cannot produce the broken code any more, and no unfixable diagnostic is left behind.ref structand struct-thiscases were not in the original report, but they are the same defect (a value that is legal as an argument and illegal inside a lambda), so they are handled together.new Foo((ref int x) => ...)is skipped even though hoisting it would compile. That is a missed diagnostic, not a broken fix.docs/Rules/MA0173.mddocuments the exclusion.Tests
Added to
UseLazyInitializerEnsureInitializeAnalyzerTests: six no-diagnostic tests (RefParameter,OutParameter,InParameter,RefLocal,RefStructLocal,StructThis) and aParametertest that still reports and fixes, to guard against over-restricting the rule.All six new negative tests were confirmed to fail against the unmodified analyzer and to pass with the change.
Validation
dotnet buildsucceeds with no warnings.dotnet run --project src/DocumentationGeneratorexits 0 with no markdown changes, re-run after the documentation edit.