Skip to content

Commit 2592a85

Browse files
committed
gopls/internal/lsp: simplify KnownPackages
This change simplifies the two functions called KnownPackages, and renames one of them. The first, source.KnownPackages, is a standalone function called in exactly one place: ListKnownPackages. It has been renamed KnownPackagePaths to distinguish from the other and to make clear that it returns only metadata. Its implementation could be greatly simplified in a follow-up, as noted. In the meantime, one obviously wrong use of ImportSpec.Path.Value (a quoted string literal!) as an package (not import!) path was fixed, and the package name was obtained directly, not via CompiledGoFiles. The second, Snapshot.KnownPackagePaths, is called from two places. This CL eliminates one of them: stubMethods used it apparently only to populate a field of missingInterface (pkg) that was unused. The other call (from 'implementations') is something that should eventually go away as we incrementalize; in any case it doesn't rely on the undocumented ordering invariant established by the implementation. This change removes the ordering invariant, documents the lack of order, and removes the ordering logic. Change-Id: Ia515a62c2d78276b3344f2880c22746b2c06ff64 Reviewed-on: https://go-review.googlesource.com/c/tools/+/451675 TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Alan Donovan <[email protected]> gopls-CI: kokoro <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent c7ed4b3 commit 2592a85

File tree

7 files changed

+35
-65
lines changed

7 files changed

+35
-65
lines changed

gopls/internal/lsp/cache/snapshot.go

+2-7
Original file line numberDiff line numberDiff line change
@@ -1150,19 +1150,14 @@ func (s *snapshot) KnownPackages(ctx context.Context) ([]source.Package, error)
11501150
return nil, err
11511151
}
11521152

1153-
// The WorkspaceSymbols implementation relies on this function returning
1154-
// workspace packages first.
1155-
ids := s.workspacePackageIDs()
1153+
ids := make([]source.PackageID, 0, len(s.meta.metadata))
11561154
s.mu.Lock()
11571155
for id := range s.meta.metadata {
1158-
if _, ok := s.workspacePackages[id]; ok {
1159-
continue
1160-
}
11611156
ids = append(ids, id)
11621157
}
11631158
s.mu.Unlock()
11641159

1165-
var pkgs []source.Package
1160+
pkgs := make([]source.Package, 0, len(ids))
11661161
for _, id := range ids {
11671162
pkg, err := s.checkedPackage(ctx, id, s.workspaceParseMode(id))
11681163
if err != nil {

gopls/internal/lsp/command.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ func (c *commandHandler) ListKnownPackages(ctx context.Context, args command.URI
735735
progress: "Listing packages",
736736
forURI: args.URI,
737737
}, func(ctx context.Context, deps commandDeps) error {
738-
pkgs, err := source.KnownPackages(ctx, deps.snapshot, deps.fh)
738+
pkgs, err := source.KnownPackagePaths(ctx, deps.snapshot, deps.fh)
739739
for _, pkg := range pkgs {
740740
result.Packages = append(result.Packages, string(pkg))
741741
}

gopls/internal/lsp/source/completion/completion.go

+3
Original file line numberDiff line numberDiff line change
@@ -1475,6 +1475,9 @@ func (c *completer) unimportedPackages(ctx context.Context, seen map[string]stru
14751475

14761476
count := 0
14771477

1478+
// TODO(adonovan): strength-reduce to a metadata query.
1479+
// All that's needed below is Package.{Name,Path}.
1480+
// Presumably that can be answered more thoroughly more quickly.
14781481
known, err := c.snapshot.CachedImportPaths(ctx)
14791482
if err != nil {
14801483
return err

gopls/internal/lsp/source/known_packages.go

+18-22
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,24 @@ import (
1616
"golang.org/x/tools/internal/imports"
1717
)
1818

19-
// KnownPackages returns a list of all known packages
20-
// in the package graph that could potentially be imported
21-
// by the given file.
22-
func KnownPackages(ctx context.Context, snapshot Snapshot, fh VersionedFileHandle) ([]PackagePath, error) {
19+
// KnownPackagePaths returns a new list of package paths of all known
20+
// packages in the package graph that could potentially be imported by
21+
// the given file. The list is ordered lexicographically, except that
22+
// all dot-free paths (standard packages) appear before dotful ones.
23+
func KnownPackagePaths(ctx context.Context, snapshot Snapshot, fh VersionedFileHandle) ([]PackagePath, error) {
24+
// TODO(adonovan): this whole algorithm could be more
25+
// simply expressed in terms of Metadata, not Packages.
26+
// All we need below is:
27+
// - for fh: Metadata.{DepsByPkgPath,Path,Name}
28+
// - for all cached packages: Metadata.{Path,Name,ForTest,DepsByPkgPath}.
2329
pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
2430
if err != nil {
2531
return nil, fmt.Errorf("GetParsedFile: %w", err)
2632
}
2733
alreadyImported := map[PackagePath]struct{}{}
28-
for _, imp := range pgf.File.Imports {
29-
// TODO(adonovan): the correct PackagePath might need a "vendor/" prefix.
30-
alreadyImported[PackagePath(imp.Path.Value)] = struct{}{}
34+
for _, imp := range pkg.Imports() {
35+
alreadyImported[imp.PkgPath()] = struct{}{}
3136
}
32-
// TODO(adonovan): this whole algorithm could be more
33-
// simply expressed in terms of Metadata, not Packages.
3437
pkgs, err := snapshot.CachedImportPaths(ctx)
3538
if err != nil {
3639
return nil, err
@@ -40,13 +43,8 @@ func KnownPackages(ctx context.Context, snapshot Snapshot, fh VersionedFileHandl
4043
paths []PackagePath
4144
)
4245
for path, knownPkg := range pkgs {
43-
gofiles := knownPkg.CompiledGoFiles()
44-
if len(gofiles) == 0 || gofiles[0].File.Name == nil {
45-
continue
46-
}
47-
pkgName := gofiles[0].File.Name.Name
4846
// package main cannot be imported
49-
if pkgName == "main" {
47+
if knownPkg.Name() == "main" {
5048
continue
5149
}
5250
// test packages cannot be imported
@@ -57,7 +55,7 @@ func KnownPackages(ctx context.Context, snapshot Snapshot, fh VersionedFileHandl
5755
if _, ok := alreadyImported[path]; ok {
5856
continue
5957
}
60-
// snapshot.KnownPackages could have multiple versions of a pkg
58+
// snapshot.CachedImportPaths could have multiple versions of a pkg
6159
if _, ok := seen[path]; ok {
6260
continue
6361
}
@@ -86,7 +84,8 @@ func KnownPackages(ctx context.Context, snapshot Snapshot, fh VersionedFileHandl
8684
return
8785
}
8886
paths = append(paths, path)
89-
}, "", pgf.URI.Filename(), pkg.GetTypes().Name(), o.Env)
87+
seen[path] = struct{}{}
88+
}, "", pgf.URI.Filename(), string(pkg.Name()), o.Env)
9089
})
9190
if err != nil {
9291
// if an error occurred, we still have a decent list we can
@@ -97,11 +96,8 @@ func KnownPackages(ctx context.Context, snapshot Snapshot, fh VersionedFileHandl
9796
importI, importJ := paths[i], paths[j]
9897
iHasDot := strings.Contains(string(importI), ".")
9998
jHasDot := strings.Contains(string(importJ), ".")
100-
if iHasDot && !jHasDot {
101-
return false
102-
}
103-
if jHasDot && !iHasDot {
104-
return true
99+
if iHasDot != jHasDot {
100+
return jHasDot // dot-free paths (standard packages) compare less
105101
}
106102
return importI < importJ
107103
})

gopls/internal/lsp/source/stub.go

+3-33
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,8 @@ func stubSuggestedFixFunc(ctx context.Context, snapshot Snapshot, fh VersionedFi
9898
// stubMethods returns the Go code of all methods
9999
// that implement the given interface
100100
func stubMethods(ctx context.Context, concreteFile *ast.File, si *stubmethods.StubInfo, snapshot Snapshot) ([]byte, []*stubImport, error) {
101-
ifacePkg, err := deducePkgFromTypes(ctx, snapshot, si.Interface)
102-
if err != nil {
103-
return nil, nil, err
104-
}
105-
si.Concrete.Obj().Type()
106101
concMS := types.NewMethodSet(types.NewPointer(si.Concrete.Obj().Type()))
107-
missing, err := missingMethods(ctx, snapshot, concMS, si.Concrete.Obj().Pkg(), si.Interface, ifacePkg, map[string]struct{}{})
102+
missing, err := missingMethods(ctx, snapshot, concMS, si.Concrete.Obj().Pkg(), si.Interface, map[string]struct{}{})
108103
if err != nil {
109104
return nil, nil, fmt.Errorf("missingMethods: %w", err)
110105
}
@@ -188,19 +183,6 @@ func printStubMethod(md methodData) []byte {
188183
return b.Bytes()
189184
}
190185

191-
func deducePkgFromTypes(ctx context.Context, snapshot Snapshot, ifaceObj types.Object) (Package, error) {
192-
pkgs, err := snapshot.KnownPackages(ctx)
193-
if err != nil {
194-
return nil, err
195-
}
196-
for _, p := range pkgs {
197-
if p.PkgPath() == PackagePath(ifaceObj.Pkg().Path()) {
198-
return p, nil
199-
}
200-
}
201-
return nil, fmt.Errorf("pkg %q not found", ifaceObj.Pkg().Path())
202-
}
203-
204186
func deduceIfaceName(concretePkg, ifacePkg *types.Package, ifaceObj types.Object) string {
205187
if concretePkg.Path() == ifacePkg.Path() {
206188
return ifaceObj.Name()
@@ -245,25 +227,15 @@ returns
245227
},
246228
}
247229
*/
248-
func missingMethods(ctx context.Context, snapshot Snapshot, concMS *types.MethodSet, concPkg *types.Package, ifaceObj types.Object, ifacePkg Package, visited map[string]struct{}) ([]*missingInterface, error) {
230+
func missingMethods(ctx context.Context, snapshot Snapshot, concMS *types.MethodSet, concPkg *types.Package, ifaceObj types.Object, visited map[string]struct{}) ([]*missingInterface, error) {
249231
iface, ok := ifaceObj.Type().Underlying().(*types.Interface)
250232
if !ok {
251233
return nil, fmt.Errorf("expected %v to be an interface but got %T", iface, ifaceObj.Type().Underlying())
252234
}
253235
missing := []*missingInterface{}
254236
for i := 0; i < iface.NumEmbeddeds(); i++ {
255237
eiface := iface.Embedded(i).Obj()
256-
depPkg := ifacePkg
257-
if path := PackagePath(eiface.Pkg().Path()); path != ifacePkg.PkgPath() {
258-
// TODO(adonovan): I'm not sure what this is trying to do, but it
259-
// looks wrong the in case of type aliases.
260-
var err error
261-
depPkg, err = ifacePkg.DirectDep(path)
262-
if err != nil {
263-
return nil, err
264-
}
265-
}
266-
em, err := missingMethods(ctx, snapshot, concMS, concPkg, eiface, depPkg, visited)
238+
em, err := missingMethods(ctx, snapshot, concMS, concPkg, eiface, visited)
267239
if err != nil {
268240
return nil, err
269241
}
@@ -274,7 +246,6 @@ func missingMethods(ctx context.Context, snapshot Snapshot, concMS *types.Method
274246
return nil, fmt.Errorf("error getting iface file: %w", err)
275247
}
276248
mi := &missingInterface{
277-
pkg: ifacePkg,
278249
iface: iface,
279250
file: parsedFile.File,
280251
}
@@ -322,7 +293,6 @@ func getStubFile(ctx context.Context, obj types.Object, snapshot Snapshot) (*Par
322293
type missingInterface struct {
323294
iface *types.Interface
324295
file *ast.File
325-
pkg Package
326296
missing []*types.Func
327297
}
328298

gopls/internal/lsp/source/view.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,11 @@ type Snapshot interface {
182182
// and checked in TypecheckWorkspace mode.
183183
CachedImportPaths(ctx context.Context) (map[PackagePath]Package, error)
184184

185-
// KnownPackages returns all the packages loaded in this snapshot, checked
186-
// in TypecheckWorkspace mode.
185+
// KnownPackages returns a new unordered list of all packages
186+
// loaded in this snapshot, checked in TypecheckWorkspace mode.
187+
//
188+
// TODO(adonovan): opt: rewrite 'implementations' to avoid the
189+
// need ever to "load everything at once" using this function.
187190
KnownPackages(ctx context.Context) ([]Package, error)
188191

189192
// ActivePackages returns the packages considered 'active' in the workspace.

internal/imports/fix.go

+3
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,9 @@ func candidateImportName(pkg *pkg) string {
697697

698698
// GetAllCandidates calls wrapped for each package whose name starts with
699699
// searchPrefix, and can be imported from filename with the package name filePkg.
700+
//
701+
// Beware that the wrapped function may be called multiple times concurrently.
702+
// TODO(adonovan): encapsulate the concurrency.
700703
func GetAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error {
701704
callback := &scanCallback{
702705
rootFound: func(gopathwalk.Root) bool {

0 commit comments

Comments
 (0)