mirror of https://github.com/golang/go.git
internal/lsp/cache: use gopls.mod for the workspace module if it exists
When building the workspace module, prefer a gopls.mod file located at the root of the view if it exists. Also do some minor documenting/cleanup along the way. For golang/go#32394 Change-Id: If87729a766d37e6c834fefe40cfb47b67a36a60c Reviewed-on: https://go-review.googlesource.com/c/tools/+/256582 Run-TryBot: Robert Findley <rfindley@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com> Trust: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
50ab9675f5
commit
19e0367891
|
|
@ -358,3 +358,73 @@ func Hello() int {
|
|||
)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUseGoplsMod(t *testing.T) {
|
||||
const multiModule = `
|
||||
-- moda/a/go.mod --
|
||||
module a.com
|
||||
|
||||
require b.com v1.2.3
|
||||
|
||||
-- moda/a/a.go --
|
||||
package a
|
||||
|
||||
import (
|
||||
"b.com/b"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var x int
|
||||
_ = b.Hello()
|
||||
}
|
||||
-- modb/go.mod --
|
||||
module b.com
|
||||
|
||||
-- modb/b/b.go --
|
||||
package b
|
||||
|
||||
func Hello() int {
|
||||
var x int
|
||||
}
|
||||
-- gopls.mod --
|
||||
module gopls-workspace
|
||||
|
||||
require (
|
||||
a.com v0.0.0-goplsworkspace
|
||||
b.com v1.2.3
|
||||
)
|
||||
|
||||
replace a.com => $SANDBOX_WORKDIR/moda/a
|
||||
`
|
||||
withOptions(
|
||||
WithProxyFiles(workspaceModuleProxy),
|
||||
).run(t, multiModule, func(t *testing.T, env *Env) {
|
||||
env.Await(InitialWorkspaceLoad)
|
||||
env.OpenFile("moda/a/a.go")
|
||||
original, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
|
||||
if want := "b.com@v1.2.3/b/b.go"; !strings.HasSuffix(original, want) {
|
||||
t.Errorf("expected %s, got %v", want, original)
|
||||
}
|
||||
workdir := env.Sandbox.Workdir.RootURI().SpanURI().Filename()
|
||||
env.WriteWorkspaceFile("gopls.mod", fmt.Sprintf(`module gopls-workspace
|
||||
|
||||
require (
|
||||
a.com v0.0.0-goplsworkspace
|
||||
b.com v0.0.0-goplsworkspace
|
||||
)
|
||||
|
||||
replace a.com => %s/moda/a
|
||||
replace b.com => %s/modb
|
||||
`, workdir, workdir))
|
||||
env.Await(
|
||||
OnceMet(
|
||||
CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), 1),
|
||||
env.DiagnosticAtRegexp("modb/b/b.go", "x"),
|
||||
),
|
||||
)
|
||||
newLocation, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
|
||||
if want := "modb/b/b.go"; !strings.HasSuffix(newLocation, want) {
|
||||
t.Errorf("expected %s, got %v", want, newLocation)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
errors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// metadata holds package metadata extracted from a call to packages.Load.
|
||||
type metadata struct {
|
||||
id packageID
|
||||
pkgPath packagePath
|
||||
|
|
@ -40,6 +41,8 @@ type metadata struct {
|
|||
config *packages.Config
|
||||
}
|
||||
|
||||
// load calls packages.Load for the given scopes, updating package metadata,
|
||||
// import graph, and mapped files with the result.
|
||||
func (s *snapshot) load(ctx context.Context, scopes ...interface{}) error {
|
||||
var query []string
|
||||
var containsDir bool // for logging
|
||||
|
|
@ -234,6 +237,9 @@ func (s *snapshot) tempWorkspaceModule(ctx context.Context) (_ span.URI, cleanup
|
|||
return span.URIFromPath(filepath.Dir(filename)), cleanup, nil
|
||||
}
|
||||
|
||||
// setMetadata 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) setMetadata(ctx context.Context, pkgPath packagePath, pkg *packages.Package, cfg *packages.Config, seen map[packageID]struct{}) (*metadata, error) {
|
||||
id := packageID(pkg.ID)
|
||||
if _, ok := seen[id]; ok {
|
||||
|
|
@ -262,6 +268,7 @@ func (s *snapshot) setMetadata(ctx context.Context, pkgPath packagePath, pkg *pa
|
|||
s.addID(uri, m.id)
|
||||
}
|
||||
|
||||
// TODO(rstambler): is this still necessary?
|
||||
copied := map[packageID]struct{}{
|
||||
id: {},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -733,8 +733,11 @@ func (s *snapshot) FindFile(uri span.URI) source.VersionedFileHandle {
|
|||
return s.files[f.URI()]
|
||||
}
|
||||
|
||||
// GetFile returns a File for the given URI. It will always succeed because it
|
||||
// adds the file to the managed set if needed.
|
||||
// GetFile returns a File for the given URI. If the file is unknown it is added
|
||||
// to the managed set.
|
||||
//
|
||||
// GetFile succeeds even if the file does not exist. A non-nil error return
|
||||
// indicates some type of internal error, for example if ctx is cancelled.
|
||||
func (s *snapshot) GetFile(ctx context.Context, uri span.URI) (source.VersionedFileHandle, error) {
|
||||
f, err := s.view.getFile(uri)
|
||||
if err != nil {
|
||||
|
|
@ -1426,6 +1429,25 @@ func (s *snapshot) getWorkspaceModuleHandle(ctx context.Context) (*workspaceModu
|
|||
}
|
||||
fhs = append(fhs, fh)
|
||||
}
|
||||
goplsModURI := span.URIFromPath(filepath.Join(s.view.Folder().Filename(), "gopls.mod"))
|
||||
goplsModFH, err := s.GetFile(ctx, goplsModURI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = goplsModFH.Read()
|
||||
switch {
|
||||
case err == nil:
|
||||
// We have a gopls.mod. Our handle only depends on it.
|
||||
fhs = []source.FileHandle{goplsModFH}
|
||||
case os.IsNotExist(err):
|
||||
// No gopls.mod, so we must build the workspace mod file automatically.
|
||||
// Defensively ensure that the goplsModFH is nil as this controls automatic
|
||||
// building of the workspace mod file.
|
||||
goplsModFH = nil
|
||||
default:
|
||||
return nil, errors.Errorf("error getting gopls.mod: %w", err)
|
||||
}
|
||||
|
||||
sort.Slice(fhs, func(i, j int) bool {
|
||||
return fhs[i].URI() < fhs[j].URI()
|
||||
})
|
||||
|
|
@ -1435,6 +1457,13 @@ func (s *snapshot) getWorkspaceModuleHandle(ctx context.Context) (*workspaceModu
|
|||
}
|
||||
key := workspaceModuleKey(hashContents([]byte(k)))
|
||||
h := s.generation.Bind(key, func(ctx context.Context, arg memoize.Arg) interface{} {
|
||||
if goplsModFH != nil {
|
||||
parsed, err := s.ParseMod(ctx, goplsModFH)
|
||||
if err != nil {
|
||||
return &workspaceModuleData{err: err}
|
||||
}
|
||||
return &workspaceModuleData{file: parsed.File}
|
||||
}
|
||||
s := arg.(*snapshot)
|
||||
data := &workspaceModuleData{}
|
||||
data.file, data.err = s.BuildWorkspaceModFile(ctx)
|
||||
|
|
@ -1450,7 +1479,7 @@ func (s *snapshot) getWorkspaceModuleHandle(ctx context.Context) (*workspaceModu
|
|||
}
|
||||
|
||||
// BuildWorkspaceModFile generates a workspace module given the modules in the
|
||||
// the workspace.
|
||||
// the workspace. It does not read gopls.mod.
|
||||
func (s *snapshot) BuildWorkspaceModFile(ctx context.Context) (*modfile.File, error) {
|
||||
file := &modfile.File{}
|
||||
file.AddModuleStmt("gopls-workspace")
|
||||
|
|
|
|||
|
|
@ -314,11 +314,8 @@ func minorOptionsChange(a, b *source.Options) bool {
|
|||
copy(bBuildFlags, b.BuildFlags)
|
||||
sort.Strings(aBuildFlags)
|
||||
sort.Strings(bBuildFlags)
|
||||
if !reflect.DeepEqual(aBuildFlags, bBuildFlags) {
|
||||
return false
|
||||
}
|
||||
// the rest of the options are benign
|
||||
return true
|
||||
return reflect.DeepEqual(aBuildFlags, bBuildFlags)
|
||||
}
|
||||
|
||||
func (v *View) SetOptions(ctx context.Context, options *source.Options) (source.View, error) {
|
||||
|
|
|
|||
|
|
@ -407,9 +407,8 @@ type FileHandle interface {
|
|||
URI() span.URI
|
||||
Kind() FileKind
|
||||
|
||||
// Identity returns a FileIdentity for the file, even if there was an error
|
||||
// reading it.
|
||||
// It is a fatal error to call Identity on a file that has not yet been read.
|
||||
// FileIdentity returns a FileIdentity for the file, even if there was an
|
||||
// error reading it.
|
||||
FileIdentity() FileIdentity
|
||||
// Read reads the contents of a file.
|
||||
// If the file is not available, returns a nil slice and an error.
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ func (s *Server) didModifyFiles(ctx context.Context, modifications []source.File
|
|||
for _, s := range snapshots {
|
||||
if s.View() == view {
|
||||
if snapshot != nil {
|
||||
return errors.Errorf("duplicate snapshots for the same view")
|
||||
return errors.New("duplicate snapshots for the same view")
|
||||
}
|
||||
snapshot = s
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue