From e64f1efd13a8804051845ed947233c94d39e6b39 Mon Sep 17 00:00:00 2001 From: Sergei Efremov Date: Sat, 5 Sep 2026 17:55:39 +0300 Subject: [PATCH] gopls/internal/golang/completion: report types in unimported completion pkgIDmatches handled only the Function, Variable, Struct and Constant symbol kinds, so an interface or a named non-struct type from a workspace package was dropped, and a struct type was reported as "var". Report every type as "type (from ...)", as the other two search paths already do. All three paths gave a type VariableCompletion, so editors drew a variable icon beside an item whose detail read "type". Use InterfaceCompletion for an interface and ClassCompletion otherwise. The standard library and module cache indexes do not record whether a type is an interface, so those two paths always use ClassCompletion. Fixes golang/go#81369 --- .../internal/golang/completion/unimported.go | 12 ++++++++--- .../marker/testdata/completion/unimported.txt | 20 ++++++++++++++++++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/gopls/internal/golang/completion/unimported.go b/gopls/internal/golang/completion/unimported.go index 79ec3d77771..2fcc6cf86a7 100644 --- a/gopls/internal/golang/completion/unimported.go +++ b/gopls/internal/golang/completion/unimported.go @@ -233,9 +233,15 @@ func (c *completer) pkgIDmatches(ctx context.Context, ids []metadata.PackageID, } kind = protocol.FunctionCompletion detail = fmt.Sprintf("func (from %q)", pkg.PkgPath) - case protocol.Variable, protocol.Struct: + case protocol.Variable: kind = protocol.VariableCompletion detail = fmt.Sprintf("var (from %q)", pkg.PkgPath) + case protocol.Interface: + kind = protocol.InterfaceCompletion + detail = fmt.Sprintf("type (from %q)", pkg.PkgPath) + case protocol.Struct, protocol.Class: + kind = protocol.ClassCompletion + detail = fmt.Sprintf("type (from %q)", pkg.PkgPath) case protocol.Constant: kind = protocol.ConstantCompletion detail = fmt.Sprintf("const (from %q)", pkg.PkgPath) @@ -284,7 +290,7 @@ func (c *completer) stdlibMatches(pkgs []metadata.PackagePath, pkg metadata.Pack kind = protocol.VariableCompletion detail = fmt.Sprintf("var (from %q)", candpkg) case stdlib.Type: - kind = protocol.VariableCompletion + kind = protocol.ClassCompletion detail = fmt.Sprintf("type (from %q)", candpkg) default: continue @@ -331,7 +337,7 @@ func (c *completer) modcacheMatches(pkg metadata.PackageName, prefix string) ([] kind = protocol.ConstantCompletion detail = fmt.Sprintf("const (from %s)", cand.ImportPath) case modindex.Type: // might be a type alias - kind = protocol.VariableCompletion + kind = protocol.ClassCompletion detail = fmt.Sprintf("type (from %s)", cand.ImportPath) default: continue diff --git a/gopls/internal/test/marker/testdata/completion/unimported.txt b/gopls/internal/test/marker/testdata/completion/unimported.txt index be10595d738..7835266b3e8 100644 --- a/gopls/internal/test/marker/testdata/completion/unimported.txt +++ b/gopls/internal/test/marker/testdata/completion/unimported.txt @@ -21,6 +21,13 @@ func Foo() {} package foo type StructFoo struct{ F int } +type ArrayFoo [16]byte +type InterfaceFoo interface{} +type FuncFoo func(int) + +const ConstFoo = 1 + +var VarFoo = 2 -- baz/baz.go -- package baz @@ -41,6 +48,10 @@ func _() { signature.Foo //@complete(re"()Foo", signaturefoo) context.Bac //@complete(re"() \\/\\/", contextBackground) + + // Every kind of exported declaration of a workspace package that is not + // imported yet. + foo. //@complete(re"foo.() \\/\\/", fooArray, fooConst, fooFunc, fooInterface, fooStruct, fooVar) } // Create markers for unimported std lib packages. Only for use by this test. @@ -49,7 +60,14 @@ func _() { /* httptrace */ //@item(httptrace, "httptrace", "\"net/http/httptrace\"", "package") /* httputil */ //@item(httputil, "httputil", "\"net/http/httputil\"", "package") -/* ring.Ring */ //@item(ringring, "Ring", "type (from \"container/ring\")", "var") +/* ring.Ring */ //@item(ringring, "Ring", "type (from \"container/ring\")", "type") + +/* foo.ArrayFoo */ //@item(fooArray, "ArrayFoo", "type (from \"unimported.test/foo\")", "type") +/* foo.ConstFoo */ //@item(fooConst, "ConstFoo", "const (from \"unimported.test/foo\")", "const") +/* foo.FuncFoo */ //@item(fooFunc, "FuncFoo", "func (from \"unimported.test/foo\")", "func") +/* foo.InterfaceFoo */ //@item(fooInterface, "InterfaceFoo", "type (from \"unimported.test/foo\")", "interface") +/* foo.StructFoo */ //@item(fooStruct, "StructFoo", "type (from \"unimported.test/foo\")", "type") +/* foo.VarFoo */ //@item(fooVar, "VarFoo", "var (from \"unimported.test/foo\")", "var") /* signature.Foo */ //@item(signaturefoo, "Foo", "func (from \"unimported.test/signature\")", "func")