feat(lsp): resolve definition and references across open documents

This commit is contained in:
2026-09-14 18:50:55 +02:00
parent edc20ffa97
commit 89fa6ea15e
2 changed files with 152 additions and 52 deletions
+61
View File
@@ -691,3 +691,64 @@ func TestCodeActionsTargetsFlaggedFunctionOnly(t *testing.T) {
t.Errorf("edit does not insert RET at the end of second:\n%s", actions[0].Edit.Changes["file:///f_amd64.s"][0].NewText)
}
}
// TestCrossFileDefinitionAndReferences opens two documents: docA calls
// ·helper(SB), docB defines it. Definition must jump to docB and references
// must collect the call site in docA plus the definition in docB.
func TestCrossFileDefinitionAndReferences(t *testing.T) {
docA := "TEXT \u00b7caller(SB), NOSPLIT, $0\n" +
"\tCALL \u00b7helper(SB)\n" +
"\tRET\n"
docB := "TEXT \u00b7helper(SB), NOSPLIT, $0\n" +
"\tRET\n"
in := frame(1, "initialize", map[string]any{}) +
frame(nil, "initialized", map[string]any{}) +
frame(nil, "textDocument/didOpen", map[string]any{
"textDocument": map[string]any{"uri": "file:///a_amd64.s", "languageId": "gasm", "version": 1, "text": docA},
}) +
frame(nil, "textDocument/didOpen", map[string]any{
"textDocument": map[string]any{"uri": "file:///b_amd64.s", "languageId": "gasm", "version": 1, "text": docB},
}) +
frame(2, "textDocument/definition", map[string]any{
"textDocument": map[string]any{"uri": "file:///a_amd64.s"},
"position": map[string]any{"line": 1, "character": 8}, // on helper in CALL ·helper(SB)
}) +
frame(3, "textDocument/references", map[string]any{
"textDocument": map[string]any{"uri": "file:///b_amd64.s"},
"position": map[string]any{"line": 0, "character": 7}, // on helper in TEXT ·helper(SB)
"context": map[string]any{"includeDeclaration": true},
}) +
frame(nil, "exit", nil)
msgs := run(t, in)
dresp := findByID(msgs, 2)
if dresp == nil {
t.Fatal("no definition response")
}
var locs []Location
if err := json.Unmarshal(mustResult(t, dresp), &locs); err != nil {
t.Fatal(err)
}
if len(locs) != 1 || locs[0].URI != "file:///b_amd64.s" || locs[0].Range.Start.Line != 0 {
t.Fatalf("definition = %+v, want the TEXT in b_amd64.s line 0", locs)
}
rresp := findByID(msgs, 3)
if rresp == nil {
t.Fatal("no references response")
}
locs = nil
if err := json.Unmarshal(mustResult(t, rresp), &locs); err != nil {
t.Fatal(err)
}
if len(locs) != 2 {
t.Fatalf("references = %+v, want the definition in b_amd64.s and the call in a_amd64.s", locs)
}
byURI := map[string]int{}
for _, l := range locs {
byURI[l.URI]++
}
if byURI["file:///a_amd64.s"] != 1 || byURI["file:///b_amd64.s"] != 1 {
t.Errorf("references by uri = %v, want one in each file", byURI)
}
}