[release/10.0.3xx] Use suppressors when applying code fixes#54595
Merged
JoeRobich merged 3 commits intoJun 6, 2026
Conversation
Member
|
/tactics |
This was referenced Jun 4, 2026
Open
JoeRobich
approved these changes
Jun 5, 2026
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.
Backport of #53268 to release/10.0.3xx
#48512 fixed suppressors during analysis, but they aren't run when applying code fixes, which can cause fixes to be applied for diagnostics that should have been suppressed.
This only happens when there's a mix of suppressed and unsuppressed diagnostics, because if all diagnostics of a certain type are suppressed, it will bail out earlier.
Tactics
Summary
dotnet formatincorrectly applied code fixes to diagnostics that should have been suppressed byDiagnosticSuppressoranalyzers. PR #48512 previously added suppressor support to the analysis phase, but the code-fix path inAnalyzerFormatter.FixDiagnosticsAsyncselected analyzers solely by matchingSupportedDiagnosticsagainst the diagnostic ID — it never includedDiagnosticSuppressorinstances, which only exposeSupportedSuppressions. The fix adds a single OR clause to the LINQWherepredicate to also select anyDiagnosticSuppressorthat suppresses the target diagnostic ID, ensuring suppressors participate when fixes are applied. The change is surgical and self-contained, making it well-suited for a servicing release.Customer Impact
Users of
dotnet formatwhose projects includeDiagnosticSuppressor-based analyzers experience incorrect file modifications: suppressed diagnostics are "fixed" when they should be left alone. The most common real-world scenario involves Unity projects usingMicrosoft.Unity.Analyzers, where the suppressor prevents IDE0044 ("Make field readonly") from being applied to[SerializeField]-marked fields — without this fix,dotnet format --fix-stylesilently corrupts those fields. The issue affects all SDK releases that include PR #48512. The bug only manifests when the same diagnostic ID has a mix of suppressed and unsuppressed instances in the same project; fully-suppressed diagnostics bail out earlier and are unaffected. No simple per-project workaround exists short of disabling the diagnostic entirely in.editorconfig.Regression?
Not a traditional regression — this is a pre-existing deficiency in the code-fix path that predates PR #48512. When #48512 landed it wired up suppressors for the analysis phase but did not update the fix-application path, leaving a gap. The bug was not easily observable until suppressors were respected during analysis (post-#48512), at which point the mismatch became apparent. No single PR introduced a behavioral change that used to work correctly.
Testing
A new MSBuild-fact unit test
SuppressedDiagnosticsAreNotFixedwas added totest/dotnet-format.UnitTests/CodeFormatterTests.cs. It runsdotnet format --fix-styleagainst a new test project (suppressor_fix_project) that contains two source files:Program.cs(a UnityMonoBehavioursubclass with a[SerializeField]-marked field, suppressed byMicrosoft.Unity.Analyzers) andProgram2.cs(a plain class with the same unsuppressed field). The test asserts that onlyProgram2.csis modified. CI ran on the originating PR (#53268) againstmainbefore it was merged and then backported here.Risk
Low. The production change is a 5-line modification (4 added, 1 deleted) confined entirely to a single LINQ
Wherepredicate inAnalyzerFormatter.FixDiagnosticsAsync. The added condition is gated by a type-check (is DiagnosticSuppressor), so all existing behavior for non-suppressor analyzers is completely unchanged. The fix only expands the set of analyzers passed toRunCodeAnalysisAsyncfor the fix phase — it does not alter fix selection or application logic. A dedicated regression test covers the exact scenario being fixed.