Skip to content

MetadataFile.FindLocation(anchor, needle) points the diagnostic at the wrong entry when the needle's key comes before the anchor's key in the same JSON object #66

Open

Description

@matt-edmondson

What's wrong

FindLocation(string anchor, string needle) (SourceGeneratorToolkit/MetadataFile.cs:109-124) finds the anchor and then searches forward from it for the needle (IndexOfToken(needle, scope)). JSON objects have no key order, so the property being reported (for example base) can come before the entry's identifying key (for example name). In that case the needle in the anchor's own entry is never found, and the method returns either:

  • the needle in a later entry, or
  • if there is no later one, the unscoped first occurrence, which can be an earlier, different entry.

In both cases the result is a valid-looking location, so the generator's diagnostic squiggles the wrong line. The overload's remarks say it exists precisely so that a name "spelled correctly in dozens of places and only wrong in one of them" points at the right entry.

Reproduction

{"units":[
{"base":"Meter","name":"Foot"},
{"base":"Meter","name":"Yard"}
]}
  • file.FindLocation("Foot", "Meter") returns the location on line 2, the Yard entry. The expected result is line 1. This was checked with a probe test in a built copy of the repo.
  • Fallback variant: with entries Inch then Foot, both written base-first, FindLocation("Foot", "Meter") finds nothing after Foot and falls back to the first Meter, which is in the Inch entry.

The existing test ScopedFindLocationFallsBackWhenTheNeedleIsOnlyBeforeTheAnchor only asserts that the fallback equals the unscoped result. No test asserts that the anchor's own entry is chosen when the needle comes first in it.

Suggested fix

Scope the search to the JSON object that contains the anchor:

  1. Walk back from the anchor to the { that opens its enclosing object, skipping string contents and balanced nested {…}. A plain LastIndexOf('{') breaks when there is a nested object before the anchor.
  2. Search for the needle between that { and its matching }.
  3. Fall back to the current forward-from-anchor search, then to the unscoped search, only when the needle isn't inside that object.

Acceptance criteria

Activity

  1. matt-edmondson commented on Nov 4, 2026

    @matt-edmondson
    ContributorAuthor

    Triage

    Category: Bug
    Priority: Low

    Why: Generated code is unaffected. Only the location of a diagnostic is wrong: it squiggles a different entry when the needle's key comes before the anchor's key in a JSON object. That defeats the purpose of the scoped overload, but the diagnostic text still names the offending value. The fix is self-contained: scope the search to the object enclosing the anchor, skipping strings and nested braces.

    Suggested area / assignment: SourceGeneratorToolkit/MetadataFile.cs, in FindLocation(anchor, needle) and IndexOfToken.

    Duplicates / in progress: Not a duplicate. It follows on from #33 and PR #63 (the substring matching cases), which are closed. No open PR covers it.


    Generated by Claude Code

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

Metadata

Metadata

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