Skip to content

Commit bbfb162

Browse files
authored
Use invariant culture when formatting transfer capture in regex source generator (#113081) (#113151)
A balancing group can result in TransferCapture being emitted with a negative "capnum". If the compiler is running under a culture that uses something other than '-' as the negative sign, the resulting generated code will fail to compile.
1 parent 316eab8 commit bbfb162

File tree

2 files changed

+24
-7
lines changed

2 files changed

+24
-7
lines changed

src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2419,7 +2419,7 @@ void EmitCapture(RegexNode node, RegexNode? subsequent = null)
24192419
}
24202420
else
24212421
{
2422-
writer.WriteLine($"base.TransferCapture({capnum}, {uncapnum}, {startingPos}, pos);");
2422+
writer.WriteLine($"base.TransferCapture({capnum.ToString(CultureInfo.InvariantCulture)}, {uncapnum}, {startingPos}, pos);");
24232423
}
24242424

24252425
if (isAtomic || !childBacktracks)

src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorHelper.netcoreapp.cs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ internal static async Task<Regex> SourceGenRegexAsync(
134134
return results[0];
135135
}
136136

137+
private static readonly CultureInfo s_cultureWithMinusNegativeSign = new CultureInfo("")
138+
{
139+
// To validate that generation still succeeds even when something other than '-' is used.
140+
NumberFormat = new NumberFormatInfo() { NegativeSign = $"{(char)0x2212}" }
141+
};
142+
137143
internal static async Task<Regex[]> SourceGenRegexAsync(
138144
(string pattern, CultureInfo? culture, RegexOptions? options, TimeSpan? matchTimeout)[] regexes, CancellationToken cancellationToken = default)
139145
{
@@ -212,13 +218,24 @@ internal static async Task<Regex[]> SourceGenRegexAsync(
212218
comp = comp.ReplaceSyntaxTree(comp.SyntaxTrees.First(), CSharpSyntaxTree.ParseText(SourceText.From(code.ToString(), Encoding.UTF8), s_previewParseOptions));
213219

214220
// Run the generator
215-
GeneratorDriverRunResult generatorResults = s_generatorDriver.RunGenerators(comp!, cancellationToken).GetRunResult();
216-
ImmutableArray<Diagnostic> generatorDiagnostics = generatorResults.Diagnostics.RemoveAll(d => d.Severity <= DiagnosticSeverity.Hidden);
217-
if (generatorDiagnostics.Length != 0)
221+
CultureInfo origCulture = CultureInfo.CurrentCulture;
222+
CultureInfo.CurrentCulture = s_cultureWithMinusNegativeSign;
223+
GeneratorDriverRunResult generatorResults;
224+
ImmutableArray<Diagnostic> generatorDiagnostics;
225+
try
218226
{
219-
throw new ArgumentException(
220-
string.Join(Environment.NewLine, generatorResults.GeneratedTrees.Select(t => NumberLines(t.ToString()))) + Environment.NewLine +
221-
string.Join(Environment.NewLine, generatorDiagnostics));
227+
generatorResults = s_generatorDriver.RunGenerators(comp!, cancellationToken).GetRunResult();
228+
generatorDiagnostics = generatorResults.Diagnostics.RemoveAll(d => d.Severity <= DiagnosticSeverity.Hidden);
229+
if (generatorDiagnostics.Length != 0)
230+
{
231+
throw new ArgumentException(
232+
string.Join(Environment.NewLine, generatorResults.GeneratedTrees.Select(t => NumberLines(t.ToString()))) + Environment.NewLine +
233+
string.Join(Environment.NewLine, generatorDiagnostics));
234+
}
235+
}
236+
finally
237+
{
238+
CultureInfo.CurrentCulture = origCulture;
222239
}
223240

224241
// Compile the assembly to a stream

0 commit comments

Comments
 (0)