From 7a6ba209fdaf63d132cfb0211f1af85a1bfecbaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Ferr=C3=A0s?= Date: Sat, 20 Jan 2024 19:06:41 +0100 Subject: [PATCH] Fix bug in language.findSymbolDeclarationInDocPositionScope not finding elements in current scope. --- server/lsp/language/language.go | 7 +-- server/lsp/language/language_test.go | 65 ++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/server/lsp/language/language.go b/server/lsp/language/language.go index 5d12ed6a..9d197476 100644 --- a/server/lsp/language/language.go +++ b/server/lsp/language/language.go @@ -101,6 +101,7 @@ func (l *Language) findClosestSymbolDeclaration(word string, docId protocol.Docu // ----------- // Not found yet, let's try search the symbol defined as global in other files + // Note: Iterating a map is not guaranteed to be done always in the same order. for _, scope := range l.functionTreeByDocument { found, foundDepth := findDeepFirst(word, position, &scope, 0, AnyPosition) @@ -115,8 +116,8 @@ func (l *Language) findClosestSymbolDeclaration(word string, docId protocol.Docu // Search for symbol in docId func (l *Language) findSymbolDeclarationInDocPositionScope(identifier string, docId protocol.DocumentUri, position protocol.Position) (indexables.Indexable, error) { - scopedTree, ok := l.functionTreeByDocument[docId] - if !ok { + scopedTree, found := l.functionTreeByDocument[docId] + if !found { return nil, errors.New("Document is not indexed") } @@ -127,7 +128,7 @@ func (l *Language) findSymbolDeclarationInDocPositionScope(identifier string, do func findDeepFirst(identifier string, position protocol.Position, function *indexables.Function, depth uint, mode FindMode) (indexables.Indexable, uint) { if mode == InPosition && - !function.GetDeclarationRange().HasPosition(position) { + !function.GetDocumentRange().HasPosition(position) { return nil, depth } diff --git a/server/lsp/language/language_test.go b/server/lsp/language/language_test.go index 5a99075e..167957c9 100644 --- a/server/lsp/language/language_test.go +++ b/server/lsp/language/language_test.go @@ -16,6 +16,70 @@ func createParser() p.Parser { return p.NewParser(logger) } +func TestLanguage_findSymbolDeclarationInDocPositionScope_cursor_on_declaration_resolves_to_same_declaration(t *testing.T) { + language := NewLanguage() + + // Doc A + docA := "a" + moduleA := "modA" + fileA := idx.NewFunctionBuilder("main", "void", moduleA, docA). + WithDocumentRange(0, 0, 0, 20). + Build() + fileA.AddVariable(idx.NewVariableBuilder("out", "Out", moduleA, docA). + WithIdentifierRange(0, 0, 0, 10). + Build(), + ) + language.functionTreeByDocument[docA] = fileA + + resolvedSymbol, err := language.findSymbolDeclarationInDocPositionScope("out", docA, protocol.Position{0, 5}) + + assert.Equal(t, nil, err) + assert.Equal(t, + idx.NewVariableBuilder("out", "Out", moduleA, docA). + WithIdentifierRange(0, 0, 0, 10). + Build(), + resolvedSymbol, + ) +} + +func TestLanguage_findClosestSymbolDeclaration_cursor_on_declaration_resolves_to_same_declaration(t *testing.T) { + language := NewLanguage() + + // Doc A + docA := "a" + moduleA := "modA" + fileA := idx.NewFunctionBuilder("main", "void", moduleA, docA). + Build() + fileA.AddVariable(idx.NewVariableBuilder("out", "Out", moduleA, docA). + WithIdentifierRange(0, 0, 0, 10). + Build(), + ) + language.functionTreeByDocument[docA] = fileA + + // Doc B + docB := "b" + moduleB := "modB" + fileB := idx.NewFunctionBuilder("main", "void", moduleB, docB). + Build() + fileB.AddVariable(idx.NewVariableBuilder("out", "int", moduleB, docB). + WithIdentifierRange(0, 0, 0, 10). + Build(), + ) + language.functionTreeByDocument[docB] = fileB + // Add more docs to the map to increase possibility of iterating in random ways + language.functionTreeByDocument["3"] = idx.NewFunctionBuilder("aaa", "void", "aaa", "aaa").Build() + language.functionTreeByDocument["4"] = idx.NewFunctionBuilder("bbb", "void", "bbb", "bbb").Build() + + resolvedSymbol := language.findClosestSymbolDeclaration("out", docA, protocol.Position{0, 5}) + + assert.Equal(t, + idx.NewVariableBuilder("out", "Out", moduleA, docA). + WithIdentifierRange(0, 0, 0, 10). + Build(), + resolvedSymbol, + ) +} + func TestLanguage_FindHoverInformation(t *testing.T) { language := NewLanguage() parser := createParser() @@ -94,6 +158,7 @@ func newDeclarationParams(docId string, line protocol.UInteger, char protocol.UI WorkDoneProgressParams: protocol.WorkDoneProgressParams{}, } } + func TestLanguage_FindSymbolDeclarationInWorkspace_symbol_same_scope(t *testing.T) { module := "mod" cases := []struct {