Skip to content

Return null from StartsWithValueConverter on empty input - #196

Merged
TylerBrinks merged 1 commit into
TylerBrinks:masterfrom
jhaygood86:bugfix/starts-with-converter-empty-input
Jul 23, 2026
Merged

Return null from StartsWithValueConverter on empty input#196
TylerBrinks merged 1 commit into
TylerBrinks:masterfrom
jhaygood86:bugfix/starts-with-converter-empty-input

Conversation

@jhaygood86

Copy link
Copy Markdown
Contributor

Problem

StartsWithValueConverter.Transform skips leading whitespace and then reads Current without checking whether the enumerator was exhausted:

while (enumerator.MoveNext() && enumerator.Current.Type == TokenType.Whitespace)
{
    //Empty on purpose.
}

if (enumerator.Current.Type != _type || ...) return null;   // <-- enumerator may be finished

When the sequence is empty or whitespace-only, the loop exits because MoveNext() returned false, and Current is then either null or throws depending on the enumerator implementation:

Converters.IntegerConverter.StartsWithDelimiter().ConvertDefault();
// System.NullReferenceException

converter.Convert(new[] { Token.Whitespace });
// System.InvalidOperationException: Enumeration already finished.

Empty input isn't an exotic case here: ConvertDefault() passes Enumerable.Empty<Token>() by definition, and VaryStart falls back to ConvertDefault() once its token list is exhausted. Every other converter treats empty input as "no match" — DictionaryValueConverter, for instance, gets null back from ToIdentifier() and returns null.

Fix

Capture the MoveNext() result and return null when the sequence was exhausted.

This also unblocks composing StartsWithValueConverter into converters that get probed with empty input — for example a font-style: oblique <angle> converter, which is where I hit it.

Tests

5 tests in Property.cs:

  • ConvertDefault() on a StartsWithDelimiter converter returns null (currently NullReferenceException)
  • whitespace-only input returns null (currently InvalidOperationException)
  • 3 guards over RatioConverter — the one composition that puts StartsWithDelimiter behind an ordered converter — parsing incomplete aspect-ratio media features

The first 2 fail on master; the 3 guards pass either way and are there to keep the real-world path covered. The full suite (1263 existing tests) stays green, and all seven target frameworks build with no new warnings.

Transform advances past leading whitespace with

  while (enumerator.MoveNext() && enumerator.Current.Type == ...)

and then reads enumerator.Current without checking whether MoveNext had
actually returned false. On an empty or whitespace-only sequence the
enumerator is already exhausted, so Current either is null or throws:

  Converters.IntegerConverter.StartsWithDelimiter().ConvertDefault();
  // NullReferenceException

  converter.Convert(new[] { Token.Whitespace });
  // InvalidOperationException: Enumeration already finished.

Empty input is not exotic here - ConvertDefault() passes
Enumerable.Empty<Token>() by definition, and VaryStart falls back to it
once the token list is exhausted. Every other converter answers "no
match" for it. Capture the MoveNext result and do the same.
@jhaygood86
jhaygood86 marked this pull request as ready for review July 22, 2026 21:30
@jhaygood86
jhaygood86 marked this pull request as draft July 22, 2026 21:40
@jhaygood86
jhaygood86 marked this pull request as ready for review July 22, 2026 21:44
@TylerBrinks
TylerBrinks merged commit 2806c4e into TylerBrinks:master Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants