From 9f4956114fb8c2e71fc908e095140e5607e0e1e0 Mon Sep 17 00:00:00 2001 From: Rebecca Stambler Date: Wed, 11 Aug 2021 23:55:34 -0400 Subject: [PATCH] internal/lsp: allow for multiple ad-hoc packages in the workspace Add the scope to the command-line-arguments package ID and path so that multiple command-line-arguments packages can coexist in the workspace. Fixes golang/go#47584 Change-Id: Icbfe90d67627f384c54f352e46270ab2bf4240bd Reviewed-on: https://go-review.googlesource.com/c/tools/+/341611 Trust: Rebecca Stambler Run-TryBot: Rebecca Stambler gopls-CI: kokoro TryBot-Result: Go Bot Reviewed-by: Robert Findley --- .../regtest/misc/multiple_adhoc_test.go | 44 +++++++++++++++++++ internal/lsp/cache/load.go | 11 +++-- 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 gopls/internal/regtest/misc/multiple_adhoc_test.go diff --git a/gopls/internal/regtest/misc/multiple_adhoc_test.go b/gopls/internal/regtest/misc/multiple_adhoc_test.go new file mode 100644 index 0000000000..5f803e4e38 --- /dev/null +++ b/gopls/internal/regtest/misc/multiple_adhoc_test.go @@ -0,0 +1,44 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package misc + +import ( + "testing" + + . "golang.org/x/tools/internal/lsp/regtest" +) + +func TestMultipleAdHocPackages(t *testing.T) { + Run(t, ` +-- a/a.go -- +package main + +import "fmt" + +func main() { + fmt.Println("") +} +-- a/b.go -- +package main + +import "fmt" + +func main() () { + fmt.Println("") +} +`, func(t *testing.T, env *Env) { + env.OpenFile("a/a.go") + if list := env.Completion("a/a.go", env.RegexpSearch("a/a.go", "Println")); list == nil || len(list.Items) == 0 { + t.Fatal("expected completions, got none") + } + env.OpenFile("a/b.go") + if list := env.Completion("a/b.go", env.RegexpSearch("a/b.go", "Println")); list == nil || len(list.Items) == 0 { + t.Fatal("expected completions, got none") + } + if list := env.Completion("a/a.go", env.RegexpSearch("a/a.go", "Println")); list == nil || len(list.Items) == 0 { + t.Fatal("expected completions, got none") + } + }) +} diff --git a/internal/lsp/cache/load.go b/internal/lsp/cache/load.go index b13e4c0048..5c027e72df 100644 --- a/internal/lsp/cache/load.go +++ b/internal/lsp/cache/load.go @@ -205,7 +205,7 @@ func (s *snapshot) load(ctx context.Context, allowNetwork bool, scopes ...interf } // Set the metadata for this package. s.mu.Lock() - m, err := s.setMetadataLocked(ctx, packagePath(pkg.PkgPath), pkg, cfg, map[packageID]struct{}{}) + m, err := s.setMetadataLocked(ctx, packagePath(pkg.PkgPath), pkg, cfg, query, map[packageID]struct{}{}) s.mu.Unlock() if err != nil { return err @@ -403,8 +403,13 @@ func getWorkspaceDir(ctx context.Context, h *memoize.Handle, g *memoize.Generati // setMetadataLocked extracts metadata from pkg and records it in s. It // recurses through pkg.Imports to ensure that metadata exists for all // dependencies. -func (s *snapshot) setMetadataLocked(ctx context.Context, pkgPath packagePath, pkg *packages.Package, cfg *packages.Config, seen map[packageID]struct{}) (*metadata, error) { +func (s *snapshot) setMetadataLocked(ctx context.Context, pkgPath packagePath, pkg *packages.Package, cfg *packages.Config, query []string, seen map[packageID]struct{}) (*metadata, error) { id := packageID(pkg.ID) + if source.IsCommandLineArguments(pkg.ID) { + suffix := ":" + strings.Join(query, ",") + id = packageID(string(id) + suffix) + pkgPath = packagePath(string(pkgPath) + suffix) + } if _, ok := seen[id]; ok { return nil, errors.Errorf("import cycle detected: %q", id) } @@ -465,7 +470,7 @@ func (s *snapshot) setMetadataLocked(ctx context.Context, pkgPath packagePath, p continue } if s.noValidMetadataForIDLocked(importID) { - if _, err := s.setMetadataLocked(ctx, importPkgPath, importPkg, cfg, copied); err != nil { + if _, err := s.setMetadataLocked(ctx, importPkgPath, importPkg, cfg, query, copied); err != nil { event.Error(ctx, "error in dependency", err) } }