Fix SYSLIB1045 code fixer generating duplicate MyRegex names across partial class declarations#124698
Fix SYSLIB1045 code fixer generating duplicate MyRegex names across partial class declarations#124698danmoseley wants to merge 2 commits intodotnet:mainfrom
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
Show resolved
Hide resolved
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs
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 <[email protected]>
b83f949 to
832199b
Compare
src/libraries/System.Text.RegularExpressions/gen/UpgradeToGeneratedRegexCodeFixer.cs
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 <[email protected]>
8af55cd to
c9e46b8
Compare
| // Creates a HashSet of all of the method Symbols containing the static methods to analyze. | ||
| static HashSet<IMethodSymbol> GetMethodSymbolHash(INamedTypeSymbol regexTypeSymbol, HashSet<string> methodNames) | ||
| { | ||
| // This warning is due to a false positive bug https://github.com/dotnet/roslyn-analyzers/issues/5804 |
There was a problem hiding this comment.
noticed comment was dead, should have been removed with the pragma
...System.Text.RegularExpressions/tests/FunctionalTests/UpgradeToGeneratedRegexAnalyzerTests.cs
Show resolved
Hide resolved
|
ready for review |
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).