diff --git a/internal/lsp/source/completion.go b/internal/lsp/source/completion.go index 79787bec16..8ece709bd5 100644 --- a/internal/lsp/source/completion.go +++ b/internal/lsp/source/completion.go @@ -603,6 +603,8 @@ func (c *completer) lexical() error { } scopes = append(scopes, c.pkg.GetTypes().Scope(), types.Universe) + builtinIota := types.Universe.Lookup("iota") + // 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{}) @@ -635,6 +637,11 @@ func (c *completer) lexical() error { } } + // Don't suggest "iota" outside of const decls. + if obj == builtinIota && !c.inConstDecl() { + continue + } + // If we haven't already added a candidate for an object with this name. if _, ok := seen[obj.Name()]; !ok { seen[obj.Name()] = struct{}{} @@ -665,6 +672,15 @@ func (c *completer) lexical() error { return nil } +func (c *completer) inConstDecl() bool { + for _, n := range c.path { + if decl, ok := n.(*ast.GenDecl); ok && decl.Tok == token.CONST { + return true + } + } + return false +} + // structLiteralFieldName finds completions for struct field names inside a struct literal. func (c *completer) structLiteralFieldName() error { clInfo := c.enclosingCompositeLiteral diff --git a/internal/lsp/testdata/builtins/builtins.go b/internal/lsp/testdata/builtins/builtins.go index 14fd14417c..d9d384313b 100644 --- a/internal/lsp/testdata/builtins/builtins.go +++ b/internal/lsp/testdata/builtins/builtins.go @@ -1,7 +1,7 @@ package builtins func _() { - //@complete("", append, bool, byte, cap, close, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, iota, len, make, new, _nil, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr) + //@complete("", append, bool, byte, cap, close, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, _nil, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr) } /* Create markers for builtin types. Only for use by this test. diff --git a/internal/lsp/testdata/builtins/iota.go b/internal/lsp/testdata/builtins/iota.go new file mode 100644 index 0000000000..4442724596 --- /dev/null +++ b/internal/lsp/testdata/builtins/iota.go @@ -0,0 +1,13 @@ +package builtins + +func _() { + const ( + foo = iota //@complete(" //", iota) + ) + + iota //@complete(" //") + + var iota int //@item(iotaVar, "iota", "int", "var") + + iota //@complete(" //", iotaVar) +} diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go index 67f155a29d..ffa49007de 100644 --- a/internal/lsp/tests/tests.go +++ b/internal/lsp/tests/tests.go @@ -29,7 +29,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 = 160 + ExpectedCompletionsCount = 163 ExpectedCompletionSnippetCount = 16 ExpectedDiagnosticsCount = 21 ExpectedFormatCount = 6