Skip to content

Match an unclosed glob bracket literally [patch] - #165

Open
matt-edmondson wants to merge 2 commits into
mainfrom
fix/159-unclosed-bracket-is-literal
Open

matt-edmondson wants to merge 2 commits into
mainfrom
fix/159-unclosed-bracket-is-literal

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #159

What was wrong

DotNet.Glob reads a [ that has no closing ] as a character class running to the end of the token. ExpandGlobClasses returned any token without a ] unchanged, so a literal bracket silently became a class:

Filter Before After
log[1 log1 log[1
a[b ab a[b
-log[1 hid log1, kept log[1 hides log[1, keeps log1
log[, a[[]b literal (unchanged) literal (unchanged)

Change

ExpandGlobClasses now writes an unclosed [ as the literal [[], the way fnmatch and bash treat it. This handles several brackets in one token and an unclosed bracket after a closed class ([ab]x[c → [ab]x[[]c).

The file[0- question: the issue asked for an explicit decision. I kept the documented #106/#110 behaviour: a class left open after a dash is a range still being typed, so it stays unparseable and is ignored. Two reasons:

The DoesMatchGlob remarks now describe both cases.

Tests

  • New GlobWithAnUnclosedBracketMatchesTheBracketLiterally uses the issue's repro items. It checks IsMatch("a[b", "a[b") is true and IsMatch("ab", "a[b") is false, that -log[1 excludes log[1 and keeps log1, and that the escaped form is unchanged. Each check runs case-sensitive and case-insensitive.
  • Four new ExpandGlobClassesRewritesOnlyClassesDotNetGlobMisreads rows, plus one pinning that a[[]b is unchanged.
  • With the source change reverted, 5 tests fail. With it, all 207 pass.
  • The existing half-typed-range tests (file[0-, [!a-, -file[0-, …) still pass unchanged.

Open PRs #162, #163 and #164 edit the same class rewriter, so whichever lands second may need a rebase.


Generated by Claude Code

DotNet.Glob reads a "[" with no closing "]" as a class running to the end of
the token, so "a[b" matched "ab" but not "a[b", and "-log[1" hid "log1" while
keeping "log[1". ExpandGlobClasses now writes such a bracket as the literal
"[[]", as fnmatch and bash treat it. A class left open after a dash
("file[0-") is still a range being typed, so it stays unparseable and is
ignored as DoesMatchGlob documents.

Fixes #159

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW5Cza8WxR4s8ByZ2GX
@sonarqubecloud

Copy link
Copy Markdown

matt-edmondson pushed a commit that referenced this pull request Nov 1, 2026
matt-edmondson added a commit that referenced this pull request Nov 4, 2026
* Match a literal ] straight after a glob class [patch]

DotNet.Glob read a "]" that directly follows a closed bracket class as
another member of that class, so "*[[][0-9]]" matched "items[3" and not
"items[3]", and the excluded form let through what it was written to hide.
ExpandGlobClasses now writes each such "]" as the one-member class "[]]",
which DotNet.Glob reads as the literal the pattern means.

Fixes #172

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW5LUHQ94WSDTYRpSJV

* Move the #172 tests away from the lines #158's and #165's tests add to

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW5LUHQ94WSDTYRpSJV

---------

Co-authored-by: Claude <noreply@anthropic.com>
Main added a row pinning the unclosed "x[^a" as unchanged. Under this
branch an unclosed "[" is a literal, so the row now expects "x[[]^a".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW3DwZv24u2tk7ZxTXk

Copy link
Copy Markdown
Contributor Author

ci / .NET / Test on * is red on 34f1bbe. The failure comes from main, not from this PR.

The failing test is ReadmeTests.EveryMethodInTheReadmeApiReferenceExistsWithItsDocumentedDefaults. It fails the same way on main at 5f420d9, on all three OSes. Two PRs that merged close together conflict:

No fix exists on main yet. This patch makes the test ignore the hidden compatibility overloads. With it, all 274 tests pass locally:

--- a/TextFilter.Test/ReadmeTests.cs
+++ b/TextFilter.Test/ReadmeTests.cs
@@ using System.Collections.Generic;
+using System.ComponentModel;
 using System.IO;
@@ public void EveryMethodInTheReadmeApiReferenceExistsWithItsDocumentedDefaults()
-			MethodInfo[] overloads = [.. methods.Where(m => m.Name == methodName)];
+			MethodInfo[] overloads = [.. methods.Where(m => m.Name == methodName && m.GetCustomAttribute<EditorBrowsableAttribute>()?.State != EditorBrowsableState.Never)];

I haven't added it to this PR, to keep this PR to #159. Once it lands on main, merging main in here should turn this PR green.


Generated by Claude Code

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.

Glob token with an unclosed [ reads the rest of the token as a character class: a[b matches "ab" but not "a[b"

2 participants