Fix SYSLIB1045 code fixer generating duplicate MyRegex names across partial class declarations#124698
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes issue #77409 where the SYSLIB1045 code fixer (which converts Regex constructor calls to GeneratedRegex) generates duplicate property names when applied to multiple partial class declarations via batch fixing. The root cause is that concurrent batch fixers all see the original compilation state before any fixes are applied, causing them to independently conclude that the same name (e.g., "MyRegex") is available.
The PR also includes two unrelated changes: a performance optimization using SetSearchValues for the regex interpreter, and a regression test for character class encoding validation.
Changes:
- Adds
CountPrecedingRegexCallSiteshelper to deterministically order all Regex call sites across partial declarations by file path and position, allowing each concurrent fixer to offset its name generation - Implements
SetSearchValuesoptimization in the regex interpreter for vectorized character class matching - Adds validation for character class encoding before calling
GetSetCharsto prevent IndexOutOfRangeException on malformed input
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs | Adds CountPrecedingRegexCallSites helper and name offset logic to prevent duplicate names in batch fixing |
| src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs | Adds test validating unique name generation across partial class declarations |
| src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreterCode.cs | Adds SetSearchValues precomputation and character class encoding validation (unrelated optimization) |
| src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreter.cs | Uses SetSearchValues for vectorized Set opcode matching (unrelated optimization) |
| src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Match.Tests.cs | Adds regression test for Multi literal resembling character class encoding (unrelated) |
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs
Show resolved
Hide resolved
...System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs
Show resolved
Hide resolved
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs
Outdated
Show resolved
Hide resolved
...es/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreterCode.cs
Outdated
Show resolved
Hide resolved
259abc1 to
3e46fc1
Compare
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs
Outdated
Show resolved
Hide resolved
...System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs
Show resolved
Hide resolved
ec91456 to
ca22fda
Compare
ca22fda to
ed09d48
Compare
ed09d48 to
b83f949
Compare
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs
Outdated
Show resolved
Hide resolved
...System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs
Show resolved
Hide resolved
…artial class declarations When the BatchFixer applies multiple fixes concurrently, each fix sees the original compilation and independently picks the same first-available name. This causes CS0756 when two partial declarations of the same class both contain Regex calls that need fixing. The fix scans all partial declarations of the containing type for Regex call sites that would generate new property names, orders them deterministically (by file path, then position), and offsets the generated name by the current node's index in that list. Fixes dotnet#77409 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
b83f949 to
832199b
Compare
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs
Outdated
Show resolved
Hide resolved
Extract fixable method names into shared FixableMethodNames set on the analyzer, referenced by both the analyzer and the fixer. Add test verifying Regex.Escape calls don't inflate the generated name offset. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
8af55cd to
c9e46b8
Compare
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexAnalyzer.cs
Show resolved
Hide resolved
|
Feedback addressed. |
|
/ba-g unrelated infra issues |
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs
Outdated
Show resolved
Hide resolved
Field and property initializer call sites are fixed via ConvertFieldToGeneratedRegexProperty / ConvertPropertyToGeneratedRegexProperty, which keep the original member name and don't compete for MyRegex* names. Counting them inflated the name offset for method-body fixes (e.g., producing MyRegex1 when MyRegex was available). Updated AnayzerSupportsMultipleDiagnostics test to include a field initializer between two method-body calls to cover this scenario. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@eiriktsarpalis I reviewed yours to the regex source gen. Do you want to do this one? It's much simpler. |
|
/ba-g unrelated |
|
@stephentoub you looked at this a while back -- could you sign off? |
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexAnalyzer.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs
Outdated
Show resolved
Hide resolved
- Rename FixableMethodNames to s_fixableMethodNames (naming convention) - Simplify name generation loop to avoid throwaway strings - Extract shared IsFixableRegexOperation to eliminate duplication between analyzer and fixer - Refactor analyzer to use IsFixableRegexOperation, removing AnalyzeInvocation/AnalyzeObjectCreation/GetMethodSymbolHash Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…pleDiagnostics Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes a SYSLIB1045 code-fix naming collision that can occur when Roslyn’s BatchFixer applies fixes concurrently across multiple partial declarations of the same type, leading to duplicate generated member names (e.g., multiple MyRegex properties).
Changes:
- Update the code fixer’s generated-member naming logic to derive a deterministic per-callsite suffix across all partial declarations of the containing type.
- Refactor analyzer/fixer shared “fixable Regex call” logic into
UpgradeToGeneratedRegexAnalyzer.IsFixableRegexOperation(and makeValidateParametersreusable). - Add/extend functional tests to validate unique naming across partial declarations (same file and separate files) and relevant edge cases.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs | Adds/updates tests validating unique generated names across partial declarations and related naming edge cases. |
| src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs | Implements deterministic unique naming via CountPrecedingRegexCallSites and adjusts member insertion formatting. |
| src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexAnalyzer.cs | Centralizes “fixable Regex operation” logic for reuse by the code fixer and analyzer. |
Copilot's findings
- Files reviewed: 3/3 changed files
- Comments generated: 0 new
|
/ba-g unrelated wasm |
Fixes #77409
Problem
When the SYSLIB1045
BatchFixerapplies multiple code fixes concurrently to separate partial class declarations, each fix independently checks existing members via the semantic model. Since all fixers see the original compilation (before any fix is applied), they all concludeMyRegexis available and generate duplicate property names, causing CS0756.Fix
In
UpgradeToGeneratedRegexCodeFixer.CreateGeneratedRegexProperty, after finding the first available name via the semantic model, the newCountPrecedingRegexCallSiteshelper scans allDeclaringSyntaxReferencesof the containing type for Regex constructor/static-method call sites that would also generate new property names. These are sorted deterministically (by file path, then span position). The current node's index in that sorted list determines how many names to skip, giving each concurrent fixer a unique name.Test
Added
CodeFixerGeneratesUniqueNamesAcrossPartialClassDeclarations— twonew Regex(...)calls in separate partial class declarations of the same type, verifyingMyRegexandMyRegex1are generated. Verified the test fails without the fix (both declarations produceMyRegex).