internal/lsp: create parseModHandle for storing go.mod data
Created an analogous data structure for go.mod files when we parse them
using the golang.org/x/mod package. Gopls can now access the data
within a go.mod file using a parseModHandle and the corresponding
parseModData object. This will help down the road when it is time
to implement the lsp functions for go.mod files.
Updates golang/go#31999
Change-Id: Ibd4d64569bbe3df61b203490b63399d479e7d794
Reviewed-on: https://go-review.googlesource.com/c/tools/+/211303
Run-TryBot: Rohan Challa <rohan@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/go.mod b/go.mod
index 026a263..dd91ce1 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,8 @@
go 1.11
require (
+ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee
golang.org/x/net v0.0.0-20190620200207-3b0461eec859
golang.org/x/sync v0.0.0-20190423024810-112230192c58
- golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
+ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898
)
diff --git a/go.sum b/go.sum
index da662da..3d48818 100644
--- a/go.sum
+++ b/go.sum
@@ -1,10 +1,15 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/gopls/go.sum b/gopls/go.sum
index 4a74bee..c076cc2 100644
--- a/gopls/go.sum
+++ b/gopls/go.sum
@@ -19,7 +19,10 @@
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
@@ -29,6 +32,8 @@
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/internal/lsp/cache/load.go b/internal/lsp/cache/load.go
index 6d8a9ef..2b5c16b 100644
--- a/internal/lsp/cache/load.go
+++ b/internal/lsp/cache/load.go
@@ -80,6 +80,7 @@
if originalFH == nil {
return true
}
+ // If the file is a mod file, we should always load.
if originalFH.Identity().Kind == currentFH.Identity().Kind && currentFH.Identity().Kind == source.Mod {
return true
}
diff --git a/internal/lsp/cache/parse.go b/internal/lsp/cache/parse.go
index 2cee62e..a556124 100644
--- a/internal/lsp/cache/parse.go
+++ b/internal/lsp/cache/parse.go
@@ -47,10 +47,6 @@
err error
}
-func (pgh *parseGoHandle) String() string {
- return pgh.File().Identity().URI.Filename()
-}
-
func (c *cache) ParseGoHandle(fh source.FileHandle, mode source.ParseMode) source.ParseGoHandle {
key := parseKey{
file: fh.Identity(),
@@ -69,6 +65,10 @@
}
}
+func (pgh *parseGoHandle) String() string {
+ return pgh.File().Identity().URI.Filename()
+}
+
func (pgh *parseGoHandle) File() source.FileHandle {
return pgh.file
}
diff --git a/internal/lsp/cache/parse_mod.go b/internal/lsp/cache/parse_mod.go
new file mode 100644
index 0000000..b08f752
--- /dev/null
+++ b/internal/lsp/cache/parse_mod.go
@@ -0,0 +1,76 @@
+// Copyright 2019 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 cache
+
+import (
+ "context"
+
+ "golang.org/x/mod/modfile"
+ "golang.org/x/tools/internal/lsp/source"
+ "golang.org/x/tools/internal/lsp/telemetry"
+ "golang.org/x/tools/internal/memoize"
+ "golang.org/x/tools/internal/telemetry/trace"
+ errors "golang.org/x/xerrors"
+)
+
+type parseModHandle struct {
+ handle *memoize.Handle
+ file source.FileHandle
+}
+
+type parseModData struct {
+ memoize.NoCopy
+
+ modfile *modfile.File
+ err error
+}
+
+func (c *cache) ParseModHandle(fh source.FileHandle) source.ParseModHandle {
+ key := parseKey{
+ file: fh.Identity(),
+ mode: source.ParseFull,
+ }
+ h := c.store.Bind(key, func(ctx context.Context) interface{} {
+ data := &parseModData{}
+ data.modfile, data.err = parseMod(ctx, fh)
+ return data
+ })
+ return &parseModHandle{
+ handle: h,
+ file: fh,
+ }
+}
+
+func parseMod(ctx context.Context, fh source.FileHandle) (modifle *modfile.File, err error) {
+ ctx, done := trace.StartSpan(ctx, "cache.parseMod", telemetry.File.Of(fh.Identity().URI.Filename()))
+ defer done()
+
+ buf, _, err := fh.Read(ctx)
+ if err != nil {
+ return nil, err
+ }
+ f, err := modfile.Parse(fh.Identity().URI.Filename(), buf, nil)
+ if err != nil {
+ return nil, err
+ }
+ return f, nil
+}
+
+func (pgh *parseModHandle) String() string {
+ return pgh.File().Identity().URI.Filename()
+}
+
+func (pgh *parseModHandle) File() source.FileHandle {
+ return pgh.file
+}
+
+func (pgh *parseModHandle) Parse(ctx context.Context) (*modfile.File, error) {
+ v := pgh.handle.Get(ctx)
+ if v == nil {
+ return nil, errors.Errorf("no parsed file for %s", pgh.File().Identity().URI)
+ }
+ data := v.(*parseModData)
+ return data.modfile, data.err
+}
diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go
index f4cb971..bcd1ec7 100644
--- a/internal/lsp/source/view.go
+++ b/internal/lsp/source/view.go
@@ -11,6 +11,7 @@
"go/token"
"go/types"
+ "golang.org/x/mod/modfile"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/imports"
@@ -224,6 +225,9 @@
// FileSet returns the shared fileset used by all files in the system.
FileSet() *token.FileSet
+ // ParseGoHandle returns a go.mod ParseGoHandle for the given file handle.
+ ParseModHandle(fh FileHandle) ParseModHandle
+
// ParseGoHandle returns a ParseGoHandle for the given file handle.
ParseGoHandle(fh FileHandle, mode ParseMode) ParseGoHandle
}
@@ -250,6 +254,16 @@
Cached() (*ast.File, *protocol.ColumnMapper, error, error)
}
+// ParseModHandle represents a handle to the modfile for a go.mod.
+type ParseModHandle interface {
+ // File returns a file handle for which to get the modfile.
+ File() FileHandle
+
+ // Parse returns the parsed modifle for the go.mod file.
+ // If the file is not available, returns nil and an error.
+ Parse(ctx context.Context) (*modfile.File, error)
+}
+
// ParseMode controls the content of the AST produced when parsing a source file.
type ParseMode int