Skip to content

Commit 6d6ca0f

Browse files
Update regex parsing to latest .Net core parsing (and diagnostic messages). (#76269)
2 parents 0fef6d5 + 0ebd4e3 commit 6d6ca0f

30 files changed

+733
-772
lines changed

src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ private static string RemoveMessagesInNonSupportedLanguage(string value)
9292

9393
var diagnosticsElement = XElement.Parse(value);
9494
foreach (var diagnosticElement in diagnosticsElement.Elements("Diagnostic"))
95-
diagnosticElement.Attribute("Message").Remove();
95+
diagnosticElement.Attribute("Message")!.Remove();
9696

9797
return diagnosticsElement.ToString();
9898
}

src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/CSharpRegexParserTests.cs

Lines changed: 22 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -40,46 +40,26 @@ private static SyntaxToken GetStringToken(string text)
4040
return token;
4141
}
4242

43-
private void Test(string stringText, string expected, RegexOptions options,
44-
bool runSubTreeTests = true,
45-
bool allowIndexOutOfRange = false,
46-
bool allowNullReference = false,
47-
bool allowOutOfMemory = false,
48-
bool allowDiagnosticsMismatch = false)
43+
private void Test(
44+
string stringText, string expected, RegexOptions options)
4945
{
50-
var (tree, sourceText) = TryParseTree(stringText, options, conversionFailureOk: false,
51-
allowIndexOutOfRange, allowNullReference, allowOutOfMemory, allowDiagnosticsMismatch);
46+
var (tree, sourceText) = TryParseTree(stringText, options, conversionFailureOk: false);
5247

53-
// Tests are allowed to not run the subtree tests. This is because some
54-
// subtrees can cause the native regex parser to exhibit very bad behavior
55-
// (like not ever actually finishing compiling).
56-
if (runSubTreeTests)
57-
{
58-
TryParseSubTrees(stringText, options,
59-
allowIndexOutOfRange, allowNullReference, allowOutOfMemory, allowDiagnosticsMismatch);
60-
}
48+
TryParseSubTrees(stringText, options);
6149

62-
const string DoubleQuoteEscaping = "\"\"";
6350
var actual = TreeToText(sourceText, tree)
64-
.Replace("\"", DoubleQuoteEscaping)
65-
.Replace(""", DoubleQuoteEscaping);
66-
AssertEx.Equal(expected.Replace("\"", DoubleQuoteEscaping), actual);
51+
.Replace(""", "\"");
52+
AssertEx.Equal(expected, actual);
6753
}
6854

69-
private void TryParseSubTrees(
70-
string stringText, RegexOptions options,
71-
bool allowIndexOutOfRange,
72-
bool allowNullReference,
73-
bool allowOutOfMemory,
74-
bool allowDiagnosticsMismatch)
55+
private void TryParseSubTrees(string stringText, RegexOptions options)
7556
{
7657
// Trim the input from the right and make sure tree invariants hold
7758
var current = stringText;
7859
while (current is not "@\"\"" and not "\"\"")
7960
{
8061
current = current[..^2] + "\"";
81-
TryParseTree(current, options, conversionFailureOk: true,
82-
allowIndexOutOfRange, allowNullReference, allowOutOfMemory, allowDiagnosticsMismatch);
62+
TryParseTree(current, options, conversionFailureOk: true);
8363
}
8464

8565
// Trim the input from the left and make sure tree invariants hold
@@ -95,17 +75,16 @@ private void TryParseSubTrees(
9575
current = "\"" + current[2..];
9676
}
9777

98-
TryParseTree(current, options, conversionFailureOk: true,
99-
allowIndexOutOfRange, allowNullReference, allowOutOfMemory, allowDiagnosticsMismatch);
78+
TryParseTree(current, options, conversionFailureOk: true);
10079
}
10180

10281
for (var start = stringText[0] == '@' ? 2 : 1; start < stringText.Length - 1; start++)
10382
{
10483
TryParseTree(
10584
stringText[..start] +
10685
stringText[(start + 1)..],
107-
options, conversionFailureOk: true,
108-
allowIndexOutOfRange, allowNullReference, allowOutOfMemory, allowDiagnosticsMismatch);
86+
options,
87+
conversionFailureOk: true);
10988
}
11089
}
11190

@@ -125,12 +104,7 @@ private void TryParseSubTrees(
125104
}
126105

127106
private (RegexTree, SourceText) TryParseTree(
128-
string stringText, RegexOptions options,
129-
bool conversionFailureOk,
130-
bool allowIndexOutOfRange,
131-
bool allowNullReference,
132-
bool allowOutOfMemory,
133-
bool allowDiagnosticsMismatch = false)
107+
string stringText, RegexOptions options, bool conversionFailureOk)
134108
{
135109
var (token, tree, allChars) = JustParseTree(stringText, options, conversionFailureOk);
136110
if (tree == null)
@@ -148,42 +122,24 @@ private void TryParseSubTrees(
148122
{
149123
regex = new Regex(token.ValueText, options);
150124
}
151-
catch (IndexOutOfRangeException) when (allowIndexOutOfRange)
152-
{
153-
// bug with .NET regex parser. Can happen with patterns like: (?<-0
154-
Assert.NotEmpty(tree.Diagnostics);
155-
return treeAndText;
156-
}
157-
catch (NullReferenceException) when (allowNullReference)
158-
{
159-
// bug with .NET regex parser. can happen with patterns like: (?(?S))
160-
return treeAndText;
161-
}
162-
catch (OutOfMemoryException) when (allowOutOfMemory)
163-
{
164-
// bug with .NET regex parser. can happen with patterns like: a{2147483647,}
165-
return treeAndText;
166-
}
167125
catch (ArgumentException ex)
168126
{
169-
if (!allowDiagnosticsMismatch)
127+
Assert.NotEmpty(tree.Diagnostics);
128+
129+
// Ensure the diagnostic we emit is the same as the .NET one. Note: we can only
130+
// do this in en-US as that's the only culture where we control the text exactly
131+
// and can ensure it exactly matches Regex. We depend on localization to do a
132+
// good enough job here for other languages.
133+
if (Thread.CurrentThread.CurrentCulture.Name == "en-US")
170134
{
171-
Assert.NotEmpty(tree.Diagnostics);
172-
173-
// Ensure the diagnostic we emit is the same as the .NET one. Note: we can only
174-
// do this in en-US as that's the only culture where we control the text exactly
175-
// and can ensure it exactly matches Regex. We depend on localization to do a
176-
// good enough job here for other languages.
177-
if (Thread.CurrentThread.CurrentCulture.Name == "en-US")
178-
{
179-
Assert.True(tree.Diagnostics.Any(d => ex.Message.Contains(d.Message)));
180-
}
135+
var result = tree.Diagnostics.Any(d => ex.Message.Contains(d.Message));
136+
Assert.True(result);
181137
}
182138

183139
return treeAndText;
184140
}
185141

186-
if (!tree.Diagnostics.IsEmpty && !allowDiagnosticsMismatch)
142+
if (!tree.Diagnostics.IsEmpty)
187143
{
188144
var expectedDiagnostics = CreateDiagnosticsElement(sourceText, tree);
189145
Assert.False(true, "Expected diagnostics: \r\n" + expectedDiagnostics.ToString().Replace(@"""", @""""""));

0 commit comments

Comments
 (0)