lsp: project-wide find-references + revive the LSP test suite

find-references only searched documents the editor had open, so asking
for references to a field from a file whose users were all closed
returned just the definition. Load every .sx under the workspace root
before matching so uses in unopened files are found too.

The LSP server's own tests were dormant: nested under the `lsp` struct in
root.zig, refAllDecls never reached them, and they had bit-rotted (stale
DocumentStore.init arity, an unaligned dummy io, fake /test/ paths that
no longer resolve). Reference the lsp files directly so their tests run,
give the doc-store tests a real Threaded io with bare paths, and fix the
stale extractIdentAtOffset expectation.

Extract referencesPayload from the transport so it is unit-testable, and
add tests covering cross-document field references, includeDeclaration,
the for-loop capture inlay hint, and workspace file loading.
This commit is contained in:
agra
2026-05-31 13:36:20 +03:00
parent 8b4006a68d
commit 292fd937c6
4 changed files with 221 additions and 29 deletions

View File

@@ -2099,6 +2099,26 @@ test "sema: for-loop captures resolve element, by-ref pointer, and range cursor"
// range cursor is s64.
try std.testing.expect(i_ty != null and i_ty.? == .signed);
try std.testing.expect(i_ty.?.signed == 64);
// The typed capture lets `m.flag` / `p.flag` resolve their owner to `Move`
// (an untyped capture would leave the owner blank — a wildcard that quietly
// over-matches in find-references).
var value_owner_ok = false;
var ref_owner_ok = false;
for (res.member_refs) |mr| {
if (mr.is_def or !std.mem.eql(u8, mr.name, "flag")) continue;
if (!std.mem.eql(u8, mr.owner, "Move")) continue;
if (offsetIn(source, mr.span, "m.flag")) value_owner_ok = true;
if (offsetIn(source, mr.span, "p.flag")) ref_owner_ok = true;
}
try std.testing.expect(value_owner_ok);
try std.testing.expect(ref_owner_ok);
}
/// True when `span` falls inside the first occurrence of `needle` in `source`.
fn offsetIn(source: []const u8, span: ast.Span, needle: []const u8) bool {
const at = std.mem.indexOf(u8, source, needle) orelse return false;
return span.start >= at and span.start < at + needle.len;
}
test "sema: member references record fields, methods, and enum variants" {