diff --git a/internal/lsp/source/completion.go b/internal/lsp/source/completion.go index 1a8fc68f79..d9879f5558 100644 --- a/internal/lsp/source/completion.go +++ b/internal/lsp/source/completion.go @@ -239,6 +239,10 @@ func lexical(path []ast.Node, pos token.Pos, pkg *types.Package, info *types.Inf } scopes = append(scopes, pkg.Scope(), types.Universe) + // Track seen variables to avoid showing completions for shadowed variables. + // This works since we look at scopes from innermost to outermost. + seen := make(map[string]struct{}) + // Process scopes innermost first. for i, scope := range scopes { if scope == nil { @@ -272,7 +276,11 @@ func lexical(path []ast.Node, pos token.Pos, pkg *types.Package, info *types.Inf if scope == types.Universe { score *= 0.1 } - items = found(obj, score, items) + // If we haven't already added a candidate for an object with this name. + if _, ok := seen[obj.Name()]; !ok { + seen[obj.Name()] = struct{}{} + items = found(obj, score, items) + } } } return items diff --git a/internal/lsp/testdata/foo/foo.go b/internal/lsp/testdata/foo/foo.go index acd6cd1e39..ab588f1d56 100644 --- a/internal/lsp/testdata/foo/foo.go +++ b/internal/lsp/testdata/foo/foo.go @@ -19,4 +19,12 @@ func _() { } } +func _() { + shadowed := 123 + { + shadowed := "hi" //@item(shadowed, "shadowed", "string", "var") + sha //@complete("a", shadowed) + } +} + type IntFoo int //@item(IntFoo, "IntFoo", "int", "type"),complete("", Foo, IntFoo, StructFoo) diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go index 7948b4297c..73c30e99a4 100644 --- a/internal/lsp/tests/tests.go +++ b/internal/lsp/tests/tests.go @@ -27,7 +27,7 @@ import ( // We hardcode the expected number of test cases to ensure that all tests // are being executed. If a test is added, this number must be changed. const ( - ExpectedCompletionsCount = 84 + ExpectedCompletionsCount = 85 ExpectedDiagnosticsCount = 17 ExpectedFormatCount = 4 ExpectedDefinitionsCount = 21