From 56463cc14b28e21d0aaf562409cbc8b8b0d4af89 Mon Sep 17 00:00:00 2001 From: Rohan Challa Date: Wed, 11 Dec 2019 13:44:39 -0500 Subject: [PATCH] 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 TryBot-Result: Gobot Gobot Reviewed-by: Rebecca Stambler --- go.mod | 3 +- go.sum | 9 +++- gopls/go.sum | 5 +++ internal/lsp/cache/load.go | 1 + internal/lsp/cache/parse.go | 8 ++-- internal/lsp/cache/parse_mod.go | 76 +++++++++++++++++++++++++++++++++ internal/lsp/source/view.go | 14 ++++++ 7 files changed, 109 insertions(+), 7 deletions(-) create mode 100644 internal/lsp/cache/parse_mod.go diff --git a/go.mod b/go.mod index 026a263884..dd91ce1529 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,8 @@ module golang.org/x/tools 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 da662da593..3d48818185 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 4a74beec89..c076cc271f 100644 --- a/gopls/go.sum +++ b/gopls/go.sum @@ -19,7 +19,10 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy 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/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w 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 6d8a9ef1d2..2b5c16bf0f 100644 --- a/internal/lsp/cache/load.go +++ b/internal/lsp/cache/load.go @@ -80,6 +80,7 @@ func (c *cache) shouldLoad(ctx context.Context, s *snapshot, originalFH, current 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 2cee62e776..a556124a99 100644 --- a/internal/lsp/cache/parse.go +++ b/internal/lsp/cache/parse.go @@ -47,10 +47,6 @@ type parseGoData struct { 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 (c *cache) ParseGoHandle(fh source.FileHandle, mode source.ParseMode) sourc } } +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 0000000000..b08f752abf --- /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 f4cb971d1d..bcd1ec7d1b 100644 --- a/internal/lsp/source/view.go +++ b/internal/lsp/source/view.go @@ -11,6 +11,7 @@ import ( "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 @@ type Cache interface { // 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 @@ type ParseGoHandle interface { 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