Add new NumberStyles option to stop parsing on invalid character (#13… · dotnet/runtime@4dbc74d · GitHub
Skip to content

Commit 4dbc74d

Browse files
tannergoodingCopilotCopilotCopilot
authored andcommitted
Add new NumberStyles option to stop parsing on invalid character (#130210)
This is a continuation of #123944, now that I had a chance to finish getting copilot to respond to the feedback, which was namely just tests. The original commit (product code) is still the original which was done by hand. This resolves #87171 --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 12b1218 commit 4dbc74d

58 files changed

Lines changed: 2826 additions & 393 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎src/libraries/Common/src/System/Number.Parsing.Common.cs‎

Lines changed: 36 additions & 23 deletions

‎src/libraries/System.Private.CoreLib/src/Resources/Strings.resx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@
440440
<value>Invalid handle.</value>
441441
</data>
442442
<data name="Arg_InvalidHexBinaryStyle" xml:space="preserve">
443-
<value>With the AllowHexSpecifier or AllowBinarySpecifier bit set in the enum bit field, the only other valid bits that can be combined into the enum value must be AllowLeadingWhite and AllowTrailingWhite.</value>
443+
<value>With the AllowHexSpecifier or AllowBinarySpecifier bit set in the enum bit field, the only other valid bits that can be combined into the enum value must be AllowLeadingWhite, AllowTrailingWhite, and AllowTrailingInvalidCharacters.</value>
444444
</data>
445445
<data name="Arg_InvalidNeutralResourcesLanguage_Asm_Culture" xml:space="preserve">
446446
<value>The NeutralResourcesLanguageAttribute on the assembly "{0}" specifies an invalid culture name: "{1}".</value>
@@ -4501,4 +4501,4 @@
45014501
<data name="InvalidOperation_NoElements" xml:space="preserve">
45024502
<value>Sequence contains no elements.</value>
45034503
</data>
4504-
</root>
4504+
</root>

‎src/libraries/System.Private.CoreLib/src/System/Byte.cs‎

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,19 +124,13 @@ public static byte Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyles
124124
public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out byte result)
125125
{
126126
NumberFormatInfo.ValidateParseStyleInteger(style);
127-
128-
if (s is null)
129-
{
130-
result = 0;
131-
return false;
132-
}
133-
return Number.TryParseBinaryInteger(s.AsSpan(), style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK;
127+
return Number.TryParseBinaryInteger(s.AsSpan(), style, NumberFormatInfo.GetInstance(provider), out result, out _) == Number.ParsingStatus.OK;
134128
}
135129

136130
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out byte result)
137131
{
138132
NumberFormatInfo.ValidateParseStyleInteger(style);
139-
return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK;
133+
return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result, out _) == Number.ParsingStatus.OK;
140134
}
141135

142136
public override string ToString()
@@ -1104,6 +1098,27 @@ static bool INumberBase<byte>.TryConvertToTruncating<TOther>(byte value, [MaybeN
11041098
}
11051099
}
11061100

1101+
/// <inheritdoc cref="INumberBase{TSelf}.TryParse(string, NumberStyles, IFormatProvider?, out TSelf, out int)" />
1102+
public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out byte result, out int charsConsumed)
1103+
{
1104+
NumberFormatInfo.ValidateParseStyleInteger(style);
1105+
return Number.TryParseBinaryInteger(s.AsSpan(), style, NumberFormatInfo.GetInstance(provider), out result, out charsConsumed) == Number.ParsingStatus.OK;
1106+
}
1107+
1108+
/// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{char}, NumberStyles, IFormatProvider?, out TSelf, out int)" />
1109+
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out byte result, out int charsConsumed)
1110+
{
1111+
NumberFormatInfo.ValidateParseStyleInteger(style);
1112+
return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result, out charsConsumed) == Number.ParsingStatus.OK;
1113+
}
1114+
1115+
/// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?, out TSelf, out int)" />
1116+
public static bool TryParse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out byte result, out int bytesConsumed)
1117+
{
1118+
NumberFormatInfo.ValidateParseStyleInteger(style);
1119+
return Number.TryParseBinaryInteger(utf8Text, style, NumberFormatInfo.GetInstance(provider), out result, out bytesConsumed) == Number.ParsingStatus.OK;
1120+
}
1121+
11071122
//
11081123
// IParsable
11091124
//
@@ -1176,7 +1191,7 @@ public static byte Parse(ReadOnlySpan<byte> utf8Text, NumberStyles style = Numbe
11761191
public static bool TryParse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out byte result)
11771192
{
11781193
NumberFormatInfo.ValidateParseStyleInteger(style);
1179-
return Number.TryParseBinaryInteger(utf8Text, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK;
1194+
return Number.TryParseBinaryInteger(utf8Text, style, NumberFormatInfo.GetInstance(provider), out result, out _) == Number.ParsingStatus.OK;
11801195
}
11811196

11821197
/// <inheritdoc cref="IUtf8SpanParsable{TSelf}.Parse(ReadOnlySpan{byte}, IFormatProvider?)" />

‎src/libraries/System.Private.CoreLib/src/System/Char.cs‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,45 @@ static bool INumberBase<char>.TryConvertToTruncating<TOther>(char value, [MaybeN
19591959

19601960
static bool INumberBase<char>.TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out char result) => TryParse(s, out result);
19611961

1962+
static bool INumberBase<char>.TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out char result, out int charsConsumed)
1963+
{
1964+
if (TryParse(s, out result))
1965+
{
1966+
charsConsumed = 1;
1967+
return true;
1968+
}
1969+
1970+
charsConsumed = 0;
1971+
return false;
1972+
}
1973+
1974+
static bool INumberBase<char>.TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out char result, out int charsConsumed)
1975+
{
1976+
if (TryParse(s, out result))
1977+
{
1978+
charsConsumed = 1;
1979+
return true;
1980+
}
1981+
1982+
charsConsumed = 0;
1983+
return false;
1984+
}
1985+
1986+
static bool INumberBase<char>.TryParse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out char result, out int bytesConsumed)
1987+
{
1988+
if (Rune.DecodeFromUtf8(utf8Text, out Rune rune, out bytesConsumed) != Buffers.OperationStatus.Done ||
1989+
bytesConsumed != utf8Text.Length ||
1990+
!rune.IsBmp)
1991+
{
1992+
result = '\0';
1993+
bytesConsumed = 0;
1994+
return false;
1995+
}
1996+
1997+
result = (char)rune.Value;
1998+
return true;
1999+
}
2000+
19622001
//
19632002
// IParsable
19642003
//

‎src/libraries/System.Private.CoreLib/src/System/Decimal.cs‎

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -551,19 +551,13 @@ public static decimal Parse(ReadOnlySpan<char> s, NumberStyles style = NumberSty
551551
public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out decimal result)
552552
{
553553
NumberFormatInfo.ValidateParseStyleDecimal(style);
554-
555-
if (s == null)
556-
{
557-
result = 0;
558-
return false;
559-
}
560-
return Number.TryParseDecimal(s.AsSpan(), style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK;
554+
return Number.TryParseDecimal(s.AsSpan(), style, NumberFormatInfo.GetInstance(provider), out result, out _) == Number.ParsingStatus.OK;
561555
}
562556

563557
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out decimal result)
564558
{
565559
NumberFormatInfo.ValidateParseStyleDecimal(style);
566-
return Number.TryParseDecimal(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK;
560+
return Number.TryParseDecimal(s, style, NumberFormatInfo.GetInstance(provider), out result, out _) == Number.ParsingStatus.OK;
567561
}
568562

569563
// Returns a binary representation of a Decimal. The return value is an
@@ -1781,6 +1775,27 @@ private static bool TryConvertTo<TOther>(decimal value, [MaybeNullWhen(false)] o
17811775
}
17821776
}
17831777

1778+
/// <inheritdoc cref="INumberBase{TSelf}.TryParse(string, NumberStyles, IFormatProvider?, out TSelf, out int)" />
1779+
public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out decimal result, out int charsConsumed)
1780+
{
1781+
NumberFormatInfo.ValidateParseStyleDecimal(style);
1782+
return Number.TryParseDecimal(s.AsSpan(), style, NumberFormatInfo.GetInstance(provider), out result, out charsConsumed) == Number.ParsingStatus.OK;
1783+
}
1784+
1785+
/// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{char}, NumberStyles, IFormatProvider?, out TSelf, out int)" />
1786+
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out decimal result, out int charsConsumed)
1787+
{
1788+
NumberFormatInfo.ValidateParseStyleDecimal(style);
1789+
return Number.TryParseDecimal(s, style, NumberFormatInfo.GetInstance(provider), out result, out charsConsumed) == Number.ParsingStatus.OK;
1790+
}
1791+
1792+
/// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?, out TSelf, out int)" />
1793+
public static bool TryParse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out decimal result, out int bytesConsumed)
1794+
{
1795+
NumberFormatInfo.ValidateParseStyleDecimal(style);
1796+
return Number.TryParseDecimal(utf8Text, style, NumberFormatInfo.GetInstance(provider), out result, out bytesConsumed) == Number.ParsingStatus.OK;
1797+
}
1798+
17841799
//
17851800
// IParsable
17861801
//
@@ -1820,7 +1835,7 @@ public static decimal Parse(ReadOnlySpan<byte> utf8Text, NumberStyles style = Nu
18201835
public static bool TryParse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out decimal result)
18211836
{
18221837
NumberFormatInfo.ValidateParseStyleDecimal(style);
1823-
return Number.TryParseDecimal(utf8Text, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK;
1838+
return Number.TryParseDecimal(utf8Text, style, NumberFormatInfo.GetInstance(provider), out result, out _) == Number.ParsingStatus.OK;
18241839
}
18251840

18261841
/// <inheritdoc cref="IUtf8SpanParsable{TSelf}.Parse(ReadOnlySpan{byte}, IFormatProvider?)" />

‎src/libraries/System.Private.CoreLib/src/System/Double.cs‎

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -427,19 +427,13 @@ public static double Parse(ReadOnlySpan<char> s, NumberStyles style = NumberStyl
427427
public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out double result)
428428
{
429429
NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
430-
431-
if (s == null)
432-
{
433-
result = 0;
434-
return false;
435-
}
436-
return Number.TryParseFloat(s.AsSpan(), style, NumberFormatInfo.GetInstance(provider), out result);
430+
return Number.TryParseFloat(s.AsSpan(), style, NumberFormatInfo.GetInstance(provider), out result, out _);
437431
}
438432

439433
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out double result)
440434
{
441435
NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
442-
return Number.TryParseFloat(s, style, NumberFormatInfo.GetInstance(provider), out result);
436+
return Number.TryParseFloat(s, style, NumberFormatInfo.GetInstance(provider), out result, out _);
443437
}
444438

445439
//
@@ -1487,6 +1481,27 @@ private static bool TryConvertTo<TOther>(double value, [MaybeNullWhen(false)] ou
14871481
}
14881482
}
14891483

1484+
/// <inheritdoc cref="INumberBase{TSelf}.TryParse(string, NumberStyles, IFormatProvider?, out TSelf, out int)" />
1485+
public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out double result, out int charsConsumed)
1486+
{
1487+
NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
1488+
return Number.TryParseFloat(s.AsSpan(), style, NumberFormatInfo.GetInstance(provider), out result, out charsConsumed);
1489+
}
1490+
1491+
/// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{char}, NumberStyles, IFormatProvider?, out TSelf, out int)" />
1492+
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out double result, out int charsConsumed)
1493+
{
1494+
NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
1495+
return Number.TryParseFloat(s, style, NumberFormatInfo.GetInstance(provider), out result, out charsConsumed);
1496+
}
1497+
1498+
/// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?, out TSelf, out int)" />
1499+
public static bool TryParse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out double result, out int bytesConsumed)
1500+
{
1501+
NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
1502+
return Number.TryParseFloat(utf8Text, style, NumberFormatInfo.GetInstance(provider), out result, out bytesConsumed);
1503+
}
1504+
14901505
//
14911506
// IParsable
14921507
//
@@ -2292,7 +2307,7 @@ public static double Parse(ReadOnlySpan<byte> utf8Text, NumberStyles style = Num
22922307
public static bool TryParse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out double result)
22932308
{
22942309
NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
2295-
return Number.TryParseFloat(utf8Text, style, NumberFormatInfo.GetInstance(provider), out result);
2310+
return Number.TryParseFloat(utf8Text, style, NumberFormatInfo.GetInstance(provider), out result, out _);
22962311
}
22972312

22982313
/// <inheritdoc cref="IUtf8SpanParsable{TSelf}.Parse(ReadOnlySpan{byte}, IFormatProvider?)" />

‎src/libraries/System.Private.CoreLib/src/System/Enum.cs‎

Lines changed: 1 addition & 1 deletion

0 commit comments

Comments
 (0)