Skip to content

Add new NumberStyles option to stop parsing on invalid characte#130210

Open
tannergooding wants to merge 4 commits into
dotnet:mainfrom
tannergooding:fix-87171
Open

Add new NumberStyles option to stop parsing on invalid characte#130210
tannergooding wants to merge 4 commits into
dotnet:mainfrom
tannergooding:fix-87171

Conversation

@tannergooding

Copy link
Copy Markdown
Member

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

tannergooding and others added 3 commits July 4, 2026 14:54
)

## Description

Added comprehensive test coverage for the
`NumberStyles.AllowTrailingInvalidCharacters` mode across all numeric
types. This style allows Parse/TryParse APIs to parse up to the first
invalid character and return the number of characters consumed, similar
to Utf8Parser behavior.

## Changes

**Test Coverage Added:**
- All integer types: Int32, Int64, Int16, SByte, UInt32, UInt64, UInt16,
Byte
- All floating point types: Double, Single, Half, Decimal
- Arbitrary precision: BigInteger

**Test Scenarios:**
- Basic parsing with trailing invalid characters (e.g., `"123abc"` →
value: 123, consumed: 3)
- Combined with NumberStyles: Integer, HexNumber, BinaryNumber,
Currency, Float
- Edge cases: max/min values, empty strings, overflow, special values
(Infinity, NaN)
- All API surface: string, ReadOnlySpan\<char\>, ReadOnlySpan\<byte\>
overloads
- Both success and failure paths with proper validation of
characters/bytes consumed

Tests follow existing patterns in System.Runtime.Tests and mirror the
ValidateParser approach used in System.Memory Utf8Parser tests.

## Testing

Tests build successfully. Full baseline build required for test
execution would exceed time constraints.

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
- Reset elementsConsumed to 0 on the integer and decimal overflow paths so a
  failed parse never reports a nonzero consumed count.
- Restrict floating-point special-value (Infinity/NaN) matching to the non-hex
  path and honor AllowTrailingInvalidCharacters via prefix matching, reporting
  leading whitespace plus the matched symbol as consumed.
- Apply the same special-value consistency fix to the IEEE-754 decimal path
  (Decimal32/64/128) and share the matching logic via a helper.
- Add AllowTrailingInvalidCharacters to the hex and binary allowed styles.
- Remove redundant string null guards from TryParse overloads and rely on
  ReadOnlySpan null-tolerance; relax internal asserts to tolerate empty spans.
- Restore the UTF-8 BOM inadvertently stripped from Double/Single and the
  IEEE-754 decimal source files.
- Add and correct AllowTrailingInvalidCharacters tests, using
  CultureInfo.InvariantCulture for culture-dependent special values.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for parsing numeric prefixes (stopping at the first invalid character) via a new NumberStyles.AllowTrailingInvalidCharacters flag, and introduces TryParse overloads that report how many UTF-16 chars / UTF-8 bytes were consumed. The change updates the CoreLib parsing pipelines and extends coverage across built-in numeric types plus BigInteger and Complex, with broad new tests.

Changes:

  • Add NumberStyles.AllowTrailingInvalidCharacters and plumb “consumed count” (charsConsumed / bytesConsumed) through numeric parsing implementations.
  • Add/override new TryParse(..., out int consumed) APIs across numeric types (CoreLib, Numerics) and update ref assemblies accordingly.
  • Add extensive tests validating consumed counts and behavior for trailing invalid characters (including UTF-8 overloads in many cases).
Show a summary per file
File Description
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.cs Adds tests for AllowTrailingInvalidCharacters including consumed-count validation.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.cs Adds tests for AllowTrailingInvalidCharacters including consumed-count validation.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.cs Adds tests for AllowTrailingInvalidCharacters including UTF-8 cases.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs Adds tests for float parsing with trailing invalid characters and consumed counts.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.cs Adds tests for sbyte parsing with trailing invalid characters and consumed counts.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.cs Adds tests for long parsing with trailing invalid characters and consumed counts.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.cs Adds broad tests for int parsing behavior/consumption across styles/cultures.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.cs Adds tests for short parsing with trailing invalid characters and consumed counts.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/HalfTests.cs Adds tests for Half parsing with trailing invalid characters and consumed counts.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs Adds tests for double parsing with trailing invalid characters and consumed counts.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DecimalTests.cs Adds tests for decimal parsing with trailing invalid characters and consumed counts.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Decimal64Tests.cs Adds tests for Decimal64 parsing with trailing invalid characters and consumed counts.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Decimal32Tests.cs Adds tests for Decimal32 parsing with trailing invalid characters and consumed counts.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Decimal128Tests.cs Adds tests for Decimal128 parsing with trailing invalid characters and consumed counts.
src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.cs Adds tests for byte parsing with trailing invalid characters and consumed counts.
src/libraries/System.Runtime/ref/System.Runtime.cs Updates public surface: new NumberStyles flag + new TryParse(..., out int consumed) APIs (including on primitives and INumberBase<TSelf>).
src/libraries/System.Runtime.Numerics/tests/ComplexTests.cs Adds tests validating Complex.TryParse consumed-count behavior under the new flag.
src/libraries/System.Runtime.Numerics/tests/BigInteger/parse.cs Adds tests validating BigInteger.TryParse consumed-count behavior under the new flag.
src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs Extends Complex.TryParse to support consumed counts and trailing invalid characters after the closing bracket.
src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs Adds consumed-count TryParse overloads; wires into updated Number.TryParseBigInteger parsing entry points.
src/libraries/System.Runtime.Numerics/src/System/Number.Polyfill.cs Changes whitespace helper to report how many elements were consumed (for generic UTF parsing).
src/libraries/System.Runtime.Numerics/src/System/Number.BigInteger.cs Adds AllowTrailingInvalidCharacters support to BigInteger parsing (including hex/binary) and tracks consumed counts.
src/libraries/System.Runtime.Numerics/src/Resources/Strings.resx Updates error string for invalid hex/binary style combinations to include the new flag.
src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs Updates Numerics ref surface for BigInteger/Complex new TryParse(..., out int consumed) overloads.
src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs Updates ref surface for NFloat new TryParse(..., out int consumed) overloads.
src/libraries/System.Private.CoreLib/src/System/Version.cs Updates to new TryParseBinaryIntegerStyle(..., out int consumed) signature.
src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs Adds TryParse(..., out int consumed) overloads for nuint.
src/libraries/System.Private.CoreLib/src/System/UInt64.cs Adds TryParse(..., out int consumed) overloads and threads through new parsing entry points.
src/libraries/System.Private.CoreLib/src/System/UInt32.cs Adds TryParse(..., out int consumed) overloads and threads through new parsing entry points.
src/libraries/System.Private.CoreLib/src/System/UInt16.cs Adds TryParse(..., out int consumed) overloads and threads through new parsing entry points.
src/libraries/System.Private.CoreLib/src/System/UInt128.cs Adds TryParse(..., out int consumed) overloads and threads through new parsing entry points.
src/libraries/System.Private.CoreLib/src/System/Single.cs Adds TryParse(..., out int consumed) overloads; updates float parser callsites to new signature.
src/libraries/System.Private.CoreLib/src/System/SByte.cs Adds TryParse(..., out int consumed) overloads and threads through new parsing entry points.
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs Adds TryParse(..., out int consumed) overloads for NFloat.
src/libraries/System.Private.CoreLib/src/System/Numerics/INumberBase.cs Adds DIM overloads TryParse(..., out int consumed) for string/span/utf8.
src/libraries/System.Private.CoreLib/src/System/Numerics/Decimal64.cs Adds TryParse(..., out int consumed) overloads; updates decimal IEEE754 parser calls.
src/libraries/System.Private.CoreLib/src/System/Numerics/Decimal32.cs Adds TryParse(..., out int consumed) overloads; updates decimal IEEE754 parser calls.
src/libraries/System.Private.CoreLib/src/System/Numerics/Decimal128.cs Adds TryParse(..., out int consumed) overloads; updates decimal IEEE754 parser calls.
src/libraries/System.Private.CoreLib/src/System/Numerics/BFloat16.cs Adds TryParse(..., out int consumed) overloads; updates float parser calls.
src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs Core parsing changes: plumb elementsConsumed through integer/float/decimal parsing and implement stop-on-invalid behavior.
src/libraries/System.Private.CoreLib/src/System/IntPtr.cs Adds TryParse(..., out int consumed) overloads for nint.
src/libraries/System.Private.CoreLib/src/System/Int64.cs Adds TryParse(..., out int consumed) overloads and threads through new parsing entry points.
src/libraries/System.Private.CoreLib/src/System/Int32.cs Adds TryParse(..., out int consumed) overloads and threads through new parsing entry points.
src/libraries/System.Private.CoreLib/src/System/Int16.cs Adds TryParse(..., out int consumed) overloads and threads through new parsing entry points.
src/libraries/System.Private.CoreLib/src/System/Int128.cs Adds TryParse(..., out int consumed) overloads and threads through new parsing entry points.
src/libraries/System.Private.CoreLib/src/System/Half.cs Adds TryParse(..., out int consumed) overloads; updates float parser calls.
src/libraries/System.Private.CoreLib/src/System/Guid.cs Updates GUID parsing helper callsite for new hex/binary parse entry point signature.
src/libraries/System.Private.CoreLib/src/System/Globalization/NumberStyles.cs Adds AllowTrailingInvalidCharacters flag to NumberStyles.
src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs Updates style validation to allow AllowTrailingInvalidCharacters in hex/binary style combinations.
src/libraries/System.Private.CoreLib/src/System/Enum.cs Updates enum parsing numeric path to new TryParseBinaryIntegerStyle(..., out int consumed) signature.
src/libraries/System.Private.CoreLib/src/System/Double.cs Adds TryParse(..., out int consumed) overloads; updates float parser calls.
src/libraries/System.Private.CoreLib/src/System/Decimal.cs Adds TryParse(..., out int consumed) overloads for decimal (and wires into new parsing entry points).
src/libraries/System.Private.CoreLib/src/System/Char.cs Adds explicit INumberBase<char>.TryParse(..., out int consumed) implementations.
src/libraries/System.Private.CoreLib/src/System/Byte.cs Adds TryParse(..., out int consumed) overloads and threads through new parsing entry points.
src/libraries/System.Private.CoreLib/src/Resources/Strings.resx Updates invalid-hex/binary style error text to include the new flag.
src/libraries/Common/src/System/Number.Parsing.Common.cs Common parsing changes: return elementsConsumed from TryStringToNumber / core scanner and support early-stop behavior.

Copilot's findings

  • Files reviewed: 56/56 changed files
  • Comments generated: 5

Comment thread src/libraries/System.Private.CoreLib/src/System/Decimal.cs
Comment thread src/libraries/System.Runtime/ref/System.Runtime.cs
Comment thread src/libraries/System.Runtime/ref/System.Runtime.cs
…acters

- Decimal.cs: the new consumed-count TryParse overloads now use ValidateParseStyleDecimal instead of ValidateParseStyleFloatingPoint, matching the rest of decimal parsing (which rejects hex/binary specifiers).

- INumberBase.cs: the default consumed-count TryParse implementations no longer strip NumberStyles.AllowTrailingInvalidCharacters before delegating. Per the approved design, the style is passed through unmodified so a type that does not understand the flag throws as expected, rather than silently succeeding with a masked style.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Comment on lines +281 to +282
// including trailing nulls (zeros). Otherwise, for compatibility we still need to
// process any trailing nulls that exist and report them as having been consumed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment seems wrong here. Trailing nulls aren't incrementing index/elementsConsumed so they aren't being counted as consumed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide a new NumberStyles option to stop parsing after the first invalid character

4 participants