Skip to content

Find metadata values the file writes with JSON escapes [patch] - #76

Open
matt-edmondson wants to merge 1 commit into
mainfrom
fix/find-escaped-values-68
Open

matt-edmondson wants to merge 1 commit into
mainfrom
fix/find-escaped-values-68

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #68

What was wrong

MetadataFile.IndexOfToken searched the raw file text for "<value>", then for <value>. A generator passes a value it got back from Deserialize<T>, which is unescaped, while the file holds the escaped JSON form. So FindLocation(@"C:\temp"), FindLocation("say \"hi\"") and FindLocation("Café") (written Caf\u00e9) all returned Location.None. When the anchor was the escaped value, the scoped overload fell back to the first unscoped match, which is the wrong entry.

Change

  • IndexOfToken now walks the file's string literals and decodes each one: \", \\, \/, \b, \f, \n, \r, \t, and \uXXXX in either hex case. It returns the first literal in range whose decoded value equals the needle. The location covers the literal's escaped contents between the quotes, so IndexOfToken now also reports the match length.
  • A literal with an escape JSON doesn't allow decodes to nothing and never matches.
  • Literals are found by a forward scan, as TryGetEnclosingObject already does. The scan skips // and /* */ comments, which DefaultSerializerOptions accepts, so a quote inside a comment no longer opens a string. The list is built once per file, on first use.
  • The raw substring search stays as the fallback for text that isn't a whole string, such as a number or an already quoted anchor like "\"b\"".
  • The range rules haven't changed: the opening quote must be at or after the start, and the closing quote before the end.

Tests

New in MetadataFileTests:

  • Unscoped: a backslash path, an embedded quote, lowercase \u00e9, and mixed-case \u03A9\u00B7m\u00b2. Each asserts the line and that the span is the escaped text.
  • Scoped: an escaped needle anchored on another entry's name, and a plain needle after an escaped anchor.
  • A // the "old" name comment no longer captures the search for old.

With the SourceGeneratorToolkit/ change reverted, all 7 new tests fail.

Full suite: 105/105 passed on Linux / .NET 10.

The local Sonar build (.sonarlint/sonar-local.props) reports nothing in the new code. The one remaining finding in this file is S3776 on the unchanged TryGetEnclosingObject.


Generated by Claude Code

FindLocation searched the raw file text for the value a generator passes,
which it got back from Deserialize<T> and is therefore unescaped. A value
the file writes with an escape, such as "C:\\temp", "say \"hi\"" or the
"\u03A9" System.Text.Json writes for non-ASCII, was never found, and the
scoped overload fell back to the wrong entry.

Each string literal is now decoded and compared with the value, and the
location covers the literal's escaped contents. Quotes inside // and /* */
comments no longer open a string. The raw search stays as the fallback
for text that isn't a whole string, such as a number.

Fixes #68

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

Copy link
Copy Markdown

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

Labels

None yet

Projects

None yet

2 participants