Skip to content

A glob class whose only range is reversed (file[%-!]) matches every item, while the letter/digit equivalent (file[9-0]) matches none #173

Open

Description

@matt-edmondson

What's wrong

When a glob class contains only reversed ranges, or expands past MaxGlobClassMembers (4096), ToGlobCharacterList (TextFilter/TextFilter.cs) returns null:

  • the reversed-range case: the for (member = first; member <= last; …) loop adds nothing, so members.Count == 0 returns null (around line 600)
  • the over-cap case: around line 587

ResolveGlob caches that null, and DoesMatchGlob then treats the token as unparseable, half-typed input:

  • around line 378, unparseable optional tokens are dropped
  • with none left, around line 382, no optional constraint applies, so every item passes

Letter and digit ranges take a different path: IsNativeGlobRange (around line 559) sends them to DotNet.Glob, where a reversed range correctly matches nothing. So whether the same mistake hides everything or shows everything depends on which characters the range uses.

Failure scenario

  • Filter(["alpha.cs", "beta.txt", "gamma.md"], "file[%-!]") returns all three items. Expected: none, because the class is empty.
  • Filter(..., "file[9-0]") correctly returns none.
  • IsMatch("hello", "x[?-!]") returns true, as does IsMatch("hello", "x[\u0001-�]y") (over the cap). Both should be false.

The pattern is complete and well-formed, so this isn't the "user is still typing" case that the drop-unparseable rule exists for. It is the same symptom that #110 and #130 fixed for half-typed ranges: a filter that should narrow the list instead shows everything.

Suggested fix / acceptance criteria

  • Keep the "unparseable → drop" path for genuinely incomplete input only, such as [a- or an unclosed [.
  • For a complete class that has no members, produce a token that never matches. A reversed range then behaves the same for punctuation as it does for letters and digits.
  • For a class that expands past the cap, either keep it as a native range when DotNet.Glob can express it, raise the cap, or treat it as never-matching. It must not match everything.
  • Add tests:
    • file[%-!] and x[?-!] match nothing, under both Filter and IsMatch, in both case-sensitivity modes
    • an over-cap class doesn't match unrelated text

Related: #110 and #130 (closed; half-typed ranges), #167 (notes that a native reversed range matches nothing).

Activity

  1. matt-edmondson commented on Oct 31, 2026

    @matt-edmondson
    ContributorAuthor

    Triage


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions