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