[gopls-release-branch.0.6] all: merge master into gopls-release-branch.0.6
9a6582cd gopls/internal/regtest: avoid flake in TestGoModInvalidesOnSave
f618651c internal/lsp/cache: compare file size when invalidating file cache
7646fae9 internal/lsp/fake: use hash rather than mtime to identify workdir files
45115c1c internal/lsp/source: rename uses of embedded fields
1e6ecd4b go/packages: don't crash if given an invalid overlay
88ba5d0b internal/imports: handle un-downloaded modules
d33bae44 copyright: test that all files in the repo have copyright notices
1b1bb645 gopls/doc/emacs.md: describe configuration for eglot
7905ceac internal/lsp/cmd: add licenses command
9c811dba gopls/internal/hooks: create included licenses text
1462c254 gopls/internal/regtest: fix TestUnimportedCompletions
e1c06e46 gopls: use standard command doc comment format
21398c4d Revert "go/analysis/passes/structtag: recognize multiple keys per tag"
5bd8423e internal/lsp/cache: fix panic in GOPATH mode
6f6e4b65 internal/lsp/cache: fix module paths in nested module error messages
7de0487e gopls/internal/regtest: skip regtests on android-amd64-emu
92778473 all: add copyright notices to files that are missing them
5d655790 go/packages: remove -mod, -modfile flags from build flags for go version
b8e0803c internal/lsp/source: return all field funcs from outgoing callhierarchy
6c3993fd gopls: update link to nvim-lspconfig gopls configuration
66568f37 gopls/doc: add additional information on CI in contributing.md
961d08dc gopls: bump gofumpt to v0.1.0
2e889ff4 gopls/internal/regtest: support multiple workspace folders
eb9b40eb cmd/goyacc: double ACTSIZE, NSTATE and TEMPSTATE
2993f551 internal/lsp: avoid panic during interface assertion
c4dccaf3 go/analysis/passes/fieldalignment: add command
9ca8607e internal/lsp: save all possible keys for analyses, codelenses
d2d86cca internal/lsp: restructure user options (CL 278433 continued)
Change-Id: I9ee4b4ad55369caa697e0527bfc61c553e40bbe4
diff --git a/blog/atom/atom.go b/blog/atom/atom.go
index 542c50e..efea650 100644
--- a/blog/atom/atom.go
+++ b/blog/atom/atom.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2009 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.
diff --git a/blog/blog.go b/blog/blog.go
index a87401c..947c60e 100644
--- a/blog/blog.go
+++ b/blog/blog.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
diff --git a/cmd/benchcmp/benchcmp_test.go b/cmd/benchcmp/benchcmp_test.go
index b79bfaa..298dcba 100644
--- a/cmd/benchcmp/benchcmp_test.go
+++ b/cmd/benchcmp/benchcmp_test.go
@@ -1,3 +1,7 @@
+// Copyright 2014 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 main
import (
diff --git a/cmd/compilebench/main.go b/cmd/compilebench/main.go
index 094a56c..afce218 100644
--- a/cmd/compilebench/main.go
+++ b/cmd/compilebench/main.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// Copyright 2015 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.
diff --git a/cmd/cover/cover_test.go b/cmd/cover/cover_test.go
index 54c4512..54d3465 100644
--- a/cmd/cover/cover_test.go
+++ b/cmd/cover/cover_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
diff --git a/cmd/eg/eg.go b/cmd/eg/eg.go
index 18b0f09..9199f42 100644
--- a/cmd/eg/eg.go
+++ b/cmd/eg/eg.go
@@ -1,3 +1,7 @@
+// Copyright 2014 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.
+
// The eg command performs example-based refactoring.
// For documentation, run the command, or see Help in
// golang.org/x/tools/refactor/eg.
diff --git a/cmd/godoc/godoc_test.go b/cmd/godoc/godoc_test.go
index e61432f..ac6bacd 100644
--- a/cmd/godoc/godoc_test.go
+++ b/cmd/godoc/godoc_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
diff --git a/cmd/goimports/doc.go b/cmd/goimports/doc.go
index 7033e4d..f344d80 100644
--- a/cmd/goimports/doc.go
+++ b/cmd/goimports/doc.go
@@ -1,3 +1,7 @@
+// Copyright 2013 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.
+
/*
Command goimports updates your Go import lines,
diff --git a/cmd/gomvpkg/main.go b/cmd/gomvpkg/main.go
index 043b061..20f6111 100644
--- a/cmd/gomvpkg/main.go
+++ b/cmd/gomvpkg/main.go
@@ -1,6 +1,6 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
-// licence that can be found in the LICENSE file.
+// license that can be found in the LICENSE file.
// The gomvpkg command moves go packages, updating import declarations.
// See the -help message or Usage constant for details.
diff --git a/cmd/gorename/main.go b/cmd/gorename/main.go
index b1b895c..03e9958 100644
--- a/cmd/gorename/main.go
+++ b/cmd/gorename/main.go
@@ -1,3 +1,7 @@
+// Copyright 2014 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.
+
// The gorename command performs precise type-safe renaming of
// identifiers in Go source code.
//
diff --git a/cmd/goyacc/yacc.go b/cmd/goyacc/yacc.go
index fdd44c1..848717e 100644
--- a/cmd/goyacc/yacc.go
+++ b/cmd/goyacc/yacc.go
@@ -60,9 +60,9 @@
// the following are adjustable
// according to memory size
const (
- ACTSIZE = 120000
- NSTATES = 8000
- TEMPSIZE = 8000
+ ACTSIZE = 240000
+ NSTATES = 16000
+ TEMPSIZE = 16000
SYMINC = 50 // increase for non-term or term
RULEINC = 50 // increase for max rule length prodptr[i]
diff --git a/cmd/html2article/conv.go b/cmd/html2article/conv.go
index 4ef4f6c..604bb1f 100644
--- a/cmd/html2article/conv.go
+++ b/cmd/html2article/conv.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
diff --git a/cmd/present/main.go b/cmd/present/main.go
index cc04c46..b89e11f 100644
--- a/cmd/present/main.go
+++ b/cmd/present/main.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
diff --git a/cmd/present/play.go b/cmd/present/play.go
index 6650b94..80627f2 100644
--- a/cmd/present/play.go
+++ b/cmd/present/play.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 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.
diff --git a/cmd/toolstash/cmp.go b/cmd/toolstash/cmp.go
index f5974e1..a789d79 100644
--- a/cmd/toolstash/cmp.go
+++ b/cmd/toolstash/cmp.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// Copyright 2015 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.
diff --git a/cmd/toolstash/main.go b/cmd/toolstash/main.go
index 6baf42e..b462b50 100644
--- a/cmd/toolstash/main.go
+++ b/cmd/toolstash/main.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// Copyright 2015 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.
diff --git a/container/intsets/popcnt_gccgo.go b/container/intsets/popcnt_gccgo.go
index 82a8875..3fc5e85 100644
--- a/container/intsets/popcnt_gccgo.go
+++ b/container/intsets/popcnt_gccgo.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// Copyright 2015 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.
diff --git a/copyright/copyright.go b/copyright/copyright.go
new file mode 100644
index 0000000..a20d623
--- /dev/null
+++ b/copyright/copyright.go
@@ -0,0 +1,107 @@
+// Copyright 2020 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 copyright checks that files have the correct copyright notices.
+package copyright
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+)
+
+func checkCopyright(dir string) ([]string, error) {
+ var files []string
+ err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if info.IsDir() {
+ // Skip directories like ".git".
+ if strings.HasPrefix(info.Name(), ".") {
+ return filepath.SkipDir
+ }
+ return nil
+ }
+ needsCopyright, err := checkFile(dir, path)
+ if err != nil {
+ return err
+ }
+ if needsCopyright {
+ files = append(files, path)
+ }
+ return nil
+ })
+ return files, err
+}
+
+var copyrightRe = regexp.MustCompile(`Copyright \d{4} 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.`)
+
+func checkFile(toolsDir, filename string) (bool, error) {
+ // Only check Go files.
+ if !strings.HasSuffix(filename, "go") {
+ return false, nil
+ }
+ // Don't check testdata files.
+ normalized := strings.TrimPrefix(filepath.ToSlash(filename), filepath.ToSlash(toolsDir))
+ if strings.Contains(normalized, "/testdata/") {
+ return false, nil
+ }
+ // goyacc is the only file with a different copyright header.
+ if strings.HasSuffix(normalized, "cmd/goyacc/yacc.go") {
+ return false, nil
+ }
+ content, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return false, err
+ }
+ fset := token.NewFileSet()
+ parsed, err := parser.ParseFile(fset, filename, content, parser.ParseComments)
+ if err != nil {
+ return false, err
+ }
+ // Don't require headers on generated files.
+ if isGenerated(fset, parsed) {
+ return false, nil
+ }
+ shouldAddCopyright := true
+ for _, c := range parsed.Comments {
+ // The copyright should appear before the package declaration.
+ if c.Pos() > parsed.Package {
+ break
+ }
+ if copyrightRe.MatchString(c.Text()) {
+ shouldAddCopyright = false
+ break
+ }
+ }
+ return shouldAddCopyright, nil
+}
+
+// Copied from golang.org/x/tools/internal/lsp/source/util.go.
+// Matches cgo generated comment as well as the proposed standard:
+// https://golang.org/s/generatedcode
+var generatedRx = regexp.MustCompile(`// .*DO NOT EDIT\.?`)
+
+func isGenerated(fset *token.FileSet, file *ast.File) bool {
+ for _, commentGroup := range file.Comments {
+ for _, comment := range commentGroup.List {
+ if matched := generatedRx.MatchString(comment.Text); !matched {
+ continue
+ }
+ // Check if comment is at the beginning of the line in source.
+ if pos := fset.Position(comment.Slash); pos.Column == 1 {
+ return true
+ }
+ }
+ }
+ return false
+}
diff --git a/copyright/copyright_test.go b/copyright/copyright_test.go
new file mode 100644
index 0000000..bfab43c
--- /dev/null
+++ b/copyright/copyright_test.go
@@ -0,0 +1,30 @@
+// Copyright 2020 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 copyright
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+func TestToolsCopyright(t *testing.T) {
+ cwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+ tools := filepath.Dir(cwd)
+ if !strings.HasSuffix(filepath.Base(tools), "tools") {
+ t.Fatalf("current working directory is %s, expected tools", tools)
+ }
+ files, err := checkCopyright(tools)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(files) > 0 {
+ t.Errorf("The following files are missing copyright notices:\n%s", strings.Join(files, "\n"))
+ }
+}
diff --git a/go/analysis/analysis.go b/go/analysis/analysis.go
index 8c3c2e7..d11505a 100644
--- a/go/analysis/analysis.go
+++ b/go/analysis/analysis.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 analysis
import (
diff --git a/go/analysis/analysistest/analysistest.go b/go/analysis/analysistest/analysistest.go
index 8b752be..5e99afe 100644
--- a/go/analysis/analysistest/analysistest.go
+++ b/go/analysis/analysistest/analysistest.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 analysistest provides utilities for testing analyzers.
package analysistest
diff --git a/go/analysis/analysistest/analysistest_test.go b/go/analysis/analysistest/analysistest_test.go
index e1ce857..cb9bdd2 100644
--- a/go/analysis/analysistest/analysistest_test.go
+++ b/go/analysis/analysistest/analysistest_test.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 analysistest_test
import (
diff --git a/go/analysis/diagnostic.go b/go/analysis/diagnostic.go
index 57eaf6f..cd462a0 100644
--- a/go/analysis/diagnostic.go
+++ b/go/analysis/diagnostic.go
@@ -1,3 +1,7 @@
+// 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 analysis
import "go/token"
diff --git a/go/analysis/doc.go b/go/analysis/doc.go
index 9fa3302..94a3bd5 100644
--- a/go/analysis/doc.go
+++ b/go/analysis/doc.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 analysis defines the interface between a modular static
diff --git a/go/analysis/internal/analysisflags/help.go b/go/analysis/internal/analysisflags/help.go
index c5a70f3..ce92892 100644
--- a/go/analysis/internal/analysisflags/help.go
+++ b/go/analysis/internal/analysisflags/help.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 analysisflags
import (
diff --git a/go/analysis/internal/checker/checker_test.go b/go/analysis/internal/checker/checker_test.go
index 7c0d0a9..50c51a1 100644
--- a/go/analysis/internal/checker/checker_test.go
+++ b/go/analysis/internal/checker/checker_test.go
@@ -1,3 +1,7 @@
+// 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 checker_test
import (
diff --git a/go/analysis/multichecker/multichecker_test.go b/go/analysis/multichecker/multichecker_test.go
index ca3dab5..c7a2c46 100644
--- a/go/analysis/multichecker/multichecker_test.go
+++ b/go/analysis/multichecker/multichecker_test.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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.
+
// +build go1.12
package multichecker_test
diff --git a/go/analysis/passes/fieldalignment/cmd/fieldalignment/main.go b/go/analysis/passes/fieldalignment/cmd/fieldalignment/main.go
new file mode 100644
index 0000000..47d383d
--- /dev/null
+++ b/go/analysis/passes/fieldalignment/cmd/fieldalignment/main.go
@@ -0,0 +1,11 @@
+// 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 main
+
+import (
+ "golang.org/x/tools/go/analysis/passes/fieldalignment"
+ "golang.org/x/tools/go/analysis/singlechecker"
+)
+
+func main() { singlechecker.Main(fieldalignment.Analyzer) }
diff --git a/go/analysis/passes/fieldalignment/fieldalignment_test.go b/go/analysis/passes/fieldalignment/fieldalignment_test.go
index 97cbfc1..e445088 100644
--- a/go/analysis/passes/fieldalignment/fieldalignment_test.go
+++ b/go/analysis/passes/fieldalignment/fieldalignment_test.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 fieldalignment_test
import (
diff --git a/go/analysis/passes/findcall/cmd/findcall/main.go b/go/analysis/passes/findcall/cmd/findcall/main.go
index c933b24..e0ce913 100644
--- a/go/analysis/passes/findcall/cmd/findcall/main.go
+++ b/go/analysis/passes/findcall/cmd/findcall/main.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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.
+
// The findcall command runs the findcall analyzer.
package main
diff --git a/go/analysis/passes/internal/analysisutil/util.go b/go/analysis/passes/internal/analysisutil/util.go
index 80c9476..ac37e47 100644
--- a/go/analysis/passes/internal/analysisutil/util.go
+++ b/go/analysis/passes/internal/analysisutil/util.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 analysisutil defines various helper functions
// used by two or more packages beneath go/analysis.
package analysisutil
diff --git a/go/analysis/passes/lostcancel/cmd/lostcancel/main.go b/go/analysis/passes/lostcancel/cmd/lostcancel/main.go
index d48c290..0bba846 100644
--- a/go/analysis/passes/lostcancel/cmd/lostcancel/main.go
+++ b/go/analysis/passes/lostcancel/cmd/lostcancel/main.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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.
+
// The lostcancel command applies the golang.org/x/tools/go/analysis/passes/lostcancel
// analysis to the specified packages of Go source code.
package main
diff --git a/go/analysis/passes/nilness/cmd/nilness/main.go b/go/analysis/passes/nilness/cmd/nilness/main.go
index bac26bd..136ac25 100644
--- a/go/analysis/passes/nilness/cmd/nilness/main.go
+++ b/go/analysis/passes/nilness/cmd/nilness/main.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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.
+
// The nilness command applies the golang.org/x/tools/go/analysis/passes/nilness
// analysis to the specified packages of Go source code.
package main
diff --git a/go/analysis/passes/printf/printf_test.go b/go/analysis/passes/printf/printf_test.go
index 6845326..fd22cf6 100644
--- a/go/analysis/passes/printf/printf_test.go
+++ b/go/analysis/passes/printf/printf_test.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 printf_test
import (
diff --git a/go/analysis/passes/printf/types.go b/go/analysis/passes/printf/types.go
index bd8a594..6a5fae4 100644
--- a/go/analysis/passes/printf/types.go
+++ b/go/analysis/passes/printf/types.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 printf
import (
diff --git a/go/analysis/passes/shadow/cmd/shadow/main.go b/go/analysis/passes/shadow/cmd/shadow/main.go
index ccf7b5c..f9e36ec 100644
--- a/go/analysis/passes/shadow/cmd/shadow/main.go
+++ b/go/analysis/passes/shadow/cmd/shadow/main.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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.
+
// The shadow command runs the shadow analyzer.
package main
diff --git a/go/analysis/passes/shadow/shadow_test.go b/go/analysis/passes/shadow/shadow_test.go
index c4d200a..4fcdc92 100644
--- a/go/analysis/passes/shadow/shadow_test.go
+++ b/go/analysis/passes/shadow/shadow_test.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 shadow_test
import (
diff --git a/go/analysis/passes/sortslice/analyzer_test.go b/go/analysis/passes/sortslice/analyzer_test.go
index 9f81fe1..a14d689 100644
--- a/go/analysis/passes/sortslice/analyzer_test.go
+++ b/go/analysis/passes/sortslice/analyzer_test.go
@@ -1,3 +1,7 @@
+// 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 sortslice_test
import (
diff --git a/go/analysis/passes/structtag/structtag.go b/go/analysis/passes/structtag/structtag.go
index 0255564..f0b1505 100644
--- a/go/analysis/passes/structtag/structtag.go
+++ b/go/analysis/passes/structtag/structtag.go
@@ -207,12 +207,12 @@
)
// validateStructTag parses the struct tag and returns an error if it is not
-// in the canonical format, as defined by reflect.StructTag.
+// in the canonical format, which is a space-separated list of key:"value"
+// settings. The value may contain spaces.
func validateStructTag(tag string) error {
// This code is based on the StructTag.Get code in package reflect.
n := 0
- var keys []string
for ; tag != ""; n++ {
if n > 0 && tag != "" && tag[0] != ' ' {
// More restrictive than reflect, but catches likely mistakes
@@ -240,27 +240,14 @@
if i == 0 {
return errTagKeySyntax
}
- if i+1 >= len(tag) || tag[i] < ' ' || tag[i] == 0x7f {
+ if i+1 >= len(tag) || tag[i] != ':' {
return errTagSyntax
}
- key := tag[:i]
- keys = append(keys, key)
- tag = tag[i:]
-
- // If we found a space char here - assume that we have a tag with
- // multiple keys.
- if tag[0] == ' ' {
- continue
- }
-
- // Spaces were filtered above so we assume that here we have
- // only valid tag value started with `:"`.
- if tag[0] != ':' || tag[1] != '"' {
+ if tag[i+1] != '"' {
return errTagValueSyntax
}
-
- // Remove the colon leaving tag at the start of the quoted string.
- tag = tag[1:]
+ key := tag[:i]
+ tag = tag[i+1:]
// Scan quoted string to find value.
i = 1
@@ -276,56 +263,51 @@
qvalue := tag[:i+1]
tag = tag[i+1:]
- wholeValue, err := strconv.Unquote(qvalue)
+ value, err := strconv.Unquote(qvalue)
if err != nil {
return errTagValueSyntax
}
- for _, key := range keys {
- if !checkTagSpaces[key] {
+ if !checkTagSpaces[key] {
+ continue
+ }
+
+ switch key {
+ case "xml":
+ // If the first or last character in the XML tag is a space, it is
+ // suspicious.
+ if strings.Trim(value, " ") != value {
+ return errTagValueSpace
+ }
+
+ // If there are multiple spaces, they are suspicious.
+ if strings.Count(value, " ") > 1 {
+ return errTagValueSpace
+ }
+
+ // If there is no comma, skip the rest of the checks.
+ comma := strings.IndexRune(value, ',')
+ if comma < 0 {
continue
}
- value := wholeValue
- switch key {
- case "xml":
- // If the first or last character in the XML tag is a space, it is
- // suspicious.
- if strings.Trim(value, " ") != value {
- return errTagValueSpace
- }
-
- // If there are multiple spaces, they are suspicious.
- if strings.Count(value, " ") > 1 {
- return errTagValueSpace
- }
-
- // If there is no comma, skip the rest of the checks.
- comma := strings.IndexRune(value, ',')
- if comma < 0 {
- continue
- }
-
- // If the character before a comma is a space, this is suspicious.
- if comma > 0 && value[comma-1] == ' ' {
- return errTagValueSpace
- }
- value = value[comma+1:]
- case "json":
- // JSON allows using spaces in the name, so skip it.
- comma := strings.IndexRune(value, ',')
- if comma < 0 {
- continue
- }
- value = value[comma+1:]
- }
-
- if strings.IndexByte(value, ' ') >= 0 {
+ // If the character before a comma is a space, this is suspicious.
+ if comma > 0 && value[comma-1] == ' ' {
return errTagValueSpace
}
+ value = value[comma+1:]
+ case "json":
+ // JSON allows using spaces in the name, so skip it.
+ comma := strings.IndexRune(value, ',')
+ if comma < 0 {
+ continue
+ }
+ value = value[comma+1:]
}
- keys = keys[:0]
+ if strings.IndexByte(value, ' ') >= 0 {
+ return errTagValueSpace
+ }
}
return nil
}
diff --git a/go/analysis/passes/structtag/structtag_go16_test.go b/go/analysis/passes/structtag/structtag_go16_test.go
deleted file mode 100644
index 2b0867f..0000000
--- a/go/analysis/passes/structtag/structtag_go16_test.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2020 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.
-
-// +build go1.16
-
-package structtag_test
-
-import (
- "testing"
-
- "golang.org/x/tools/go/analysis/analysistest"
- "golang.org/x/tools/go/analysis/passes/structtag"
-)
-
-// Test the multiple key format added in Go 1.16.
-
-func TestGo16(t *testing.T) {
- testdata := analysistest.TestData()
- analysistest.Run(t, testdata, structtag.Analyzer, "go16")
-}
diff --git a/go/analysis/passes/structtag/testdata/src/go16/go16.go b/go/analysis/passes/structtag/testdata/src/go16/go16.go
deleted file mode 100644
index 895d55a..0000000
--- a/go/analysis/passes/structtag/testdata/src/go16/go16.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2020 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.
-
-// Tests for the new multiple-key struct tag format supported in 1.16.
-
-package go16
-
-type Go16StructTagTest struct {
- OK int `multiple keys can:"share a value"`
- OK2 int `json bson xml form:"field_1,omitempty" other:"value"`
-}
-
-type Go16UnexportedEncodingTagTest struct {
- F int `json xml:"ff"`
-
- // We currently always check json first, and return after an error.
- f1 int `json xml:"f1"` // want "struct field f1 has json tag but is not exported"
- f2 int `xml json:"f2"` // want "struct field f2 has json tag but is not exported"
- f3 int `xml bson:"f3"` // want "struct field f3 has xml tag but is not exported"
- f4 int `bson xml:"f4"` // want "struct field f4 has xml tag but is not exported"
-}
-
-type Go16DuplicateFields struct {
- JSONXML int `json xml:"c"`
- DuplicateJSONXML int `json xml:"c"` // want "struct field DuplicateJSONXML repeats json tag .c. also at go16.go:25" "struct field DuplicateJSONXML repeats xml tag .c. also at go16.go:25"
-}
diff --git a/go/analysis/passes/unmarshal/cmd/unmarshal/main.go b/go/analysis/passes/unmarshal/cmd/unmarshal/main.go
index 993bf74..1a17cd6 100644
--- a/go/analysis/passes/unmarshal/cmd/unmarshal/main.go
+++ b/go/analysis/passes/unmarshal/cmd/unmarshal/main.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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.
+
// The unmarshal command runs the unmarshal analyzer.
package main
diff --git a/go/analysis/unitchecker/main.go b/go/analysis/unitchecker/main.go
index a1fe3d3..7fa7c85 100644
--- a/go/analysis/unitchecker/main.go
+++ b/go/analysis/unitchecker/main.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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.
+
// +build ignore
// This file provides an example command for static checkers
diff --git a/go/analysis/unitchecker/unitchecker112.go b/go/analysis/unitchecker/unitchecker112.go
index 683b7e9..9051456 100644
--- a/go/analysis/unitchecker/unitchecker112.go
+++ b/go/analysis/unitchecker/unitchecker112.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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.
+
// +build go1.12
package unitchecker
diff --git a/go/analysis/validate.go b/go/analysis/validate.go
index ad0e727..23e57bf 100644
--- a/go/analysis/validate.go
+++ b/go/analysis/validate.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 analysis
import (
diff --git a/go/ast/astutil/util.go b/go/ast/astutil/util.go
index 7630629..919d530 100644
--- a/go/ast/astutil/util.go
+++ b/go/ast/astutil/util.go
@@ -1,3 +1,7 @@
+// Copyright 2015 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 astutil
import "go/ast"
diff --git a/go/ast/inspector/inspector_test.go b/go/ast/inspector/inspector_test.go
index 9b31e89..3e9d3ba 100644
--- a/go/ast/inspector/inspector_test.go
+++ b/go/ast/inspector/inspector_test.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 inspector_test
import (
diff --git a/go/ast/inspector/typeof.go b/go/ast/inspector/typeof.go
index d61301b..b6b00cf 100644
--- a/go/ast/inspector/typeof.go
+++ b/go/ast/inspector/typeof.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 inspector
// This file defines func typeOf(ast.Node) uint64.
diff --git a/go/buildutil/fakecontext.go b/go/buildutil/fakecontext.go
index 8b7f066..5fc672f 100644
--- a/go/buildutil/fakecontext.go
+++ b/go/buildutil/fakecontext.go
@@ -1,3 +1,7 @@
+// Copyright 2015 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 buildutil
import (
diff --git a/go/buildutil/overlay_test.go b/go/buildutil/overlay_test.go
index 92e2258..4ee8817 100644
--- a/go/buildutil/overlay_test.go
+++ b/go/buildutil/overlay_test.go
@@ -1,3 +1,7 @@
+// Copyright 2016 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 buildutil_test
import (
diff --git a/go/buildutil/tags.go b/go/buildutil/tags.go
index 486606f..6da0ce4 100644
--- a/go/buildutil/tags.go
+++ b/go/buildutil/tags.go
@@ -1,3 +1,7 @@
+// Copyright 2015 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 buildutil
// This logic was copied from stringsFlag from $GOROOT/src/cmd/go/build.go.
diff --git a/go/buildutil/tags_test.go b/go/buildutil/tags_test.go
index 0fc2618..f823431 100644
--- a/go/buildutil/tags_test.go
+++ b/go/buildutil/tags_test.go
@@ -1,3 +1,7 @@
+// Copyright 2015 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 buildutil_test
import (
diff --git a/go/callgraph/static/static.go b/go/callgraph/static/static.go
index 709bb7b..7c41c12 100644
--- a/go/callgraph/static/static.go
+++ b/go/callgraph/static/static.go
@@ -1,3 +1,7 @@
+// Copyright 2014 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 static computes the call graph of a Go program containing
// only static call edges.
package static // import "golang.org/x/tools/go/callgraph/static"
diff --git a/go/gccgoexportdata/gccgoexportdata_test.go b/go/gccgoexportdata/gccgoexportdata_test.go
index 1aa114c..0d04102 100644
--- a/go/gccgoexportdata/gccgoexportdata_test.go
+++ b/go/gccgoexportdata/gccgoexportdata_test.go
@@ -1,3 +1,7 @@
+// Copyright 2016 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 gccgoexportdata_test
import (
diff --git a/go/gcexportdata/gcexportdata_test.go b/go/gcexportdata/gcexportdata_test.go
index 69133db..a0006c0 100644
--- a/go/gcexportdata/gcexportdata_test.go
+++ b/go/gcexportdata/gcexportdata_test.go
@@ -1,3 +1,7 @@
+// Copyright 2016 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 gcexportdata_test
import (
diff --git a/go/packages/example_test.go b/go/packages/example_test.go
index 94cf8eb..9e0e58f 100644
--- a/go/packages/example_test.go
+++ b/go/packages/example_test.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 packages_test
import (
diff --git a/go/packages/golist_overlay.go b/go/packages/golist_overlay.go
index de2c1dc..9576b47 100644
--- a/go/packages/golist_overlay.go
+++ b/go/packages/golist_overlay.go
@@ -9,7 +9,6 @@
"fmt"
"go/parser"
"go/token"
- "log"
"os"
"path/filepath"
"regexp"
@@ -35,9 +34,12 @@
// This is an approximation of import path to id. This can be
// wrong for tests, vendored packages, and a number of other cases.
havePkgs[pkg.PkgPath] = pkg.ID
- x := commonDir(pkg.GoFiles)
- if x != "" {
- pkgOfDir[x] = append(pkgOfDir[x], pkg)
+ dir, err := commonDir(pkg.GoFiles)
+ if err != nil {
+ return nil, nil, err
+ }
+ if dir != "" {
+ pkgOfDir[dir] = append(pkgOfDir[dir], pkg)
}
}
@@ -441,20 +443,21 @@
return f.Name.Name, true
}
-func commonDir(a []string) string {
+// commonDir returns the directory that all files are in, "" if files is empty,
+// or an error if they aren't in the same directory.
+func commonDir(files []string) (string, error) {
seen := make(map[string]bool)
- x := append([]string{}, a...)
- for _, f := range x {
+ for _, f := range files {
seen[filepath.Dir(f)] = true
}
if len(seen) > 1 {
- log.Fatalf("commonDir saw %v for %v", seen, x)
+ return "", fmt.Errorf("files (%v) are in more than one directory: %v", files, seen)
}
for k := range seen {
- // len(seen) == 1
- return k
+ // seen has only one element; return it.
+ return k, nil
}
- return "" // no files
+ return "", nil // no files
}
// It is possible that the files in the disk directory dir have a different package
diff --git a/go/packages/overlay_test.go b/go/packages/overlay_test.go
index 8ce5a7c..97193cf 100644
--- a/go/packages/overlay_test.go
+++ b/go/packages/overlay_test.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 packages_test
import (
diff --git a/go/packages/packagestest/modules_111.go b/go/packages/packagestest/modules_111.go
index a116ae2..61fa969 100644
--- a/go/packages/packagestest/modules_111.go
+++ b/go/packages/packagestest/modules_111.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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.
+
// +build go1.11
package packagestest
diff --git a/go/packages/visit.go b/go/packages/visit.go
index b13cb08..a1dcc40 100644
--- a/go/packages/visit.go
+++ b/go/packages/visit.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 packages
import (
diff --git a/go/pointer/query.go b/go/pointer/query.go
index b52cc9f..58aa868 100644
--- a/go/pointer/query.go
+++ b/go/pointer/query.go
@@ -1,3 +1,7 @@
+// Copyright 2017 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 pointer
import (
diff --git a/go/pointer/query_test.go b/go/pointer/query_test.go
index 2756fc0..4a3112a1 100644
--- a/go/pointer/query_test.go
+++ b/go/pointer/query_test.go
@@ -1,3 +1,7 @@
+// Copyright 2017 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 pointer
import (
diff --git a/go/ssa/identical.go b/go/ssa/identical.go
index 53cbee1..f3cc8ac 100644
--- a/go/ssa/identical.go
+++ b/go/ssa/identical.go
@@ -1,3 +1,7 @@
+// Copyright 2017 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.
+
// +build go1.8
package ssa
diff --git a/go/ssa/identical_17.go b/go/ssa/identical_17.go
index da89d33..faa124f 100644
--- a/go/ssa/identical_17.go
+++ b/go/ssa/identical_17.go
@@ -1,3 +1,7 @@
+// Copyright 2017 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.
+
// +build !go1.8
package ssa
diff --git a/go/ssa/identical_test.go b/go/ssa/identical_test.go
index d194b70..2fd4ae9 100644
--- a/go/ssa/identical_test.go
+++ b/go/ssa/identical_test.go
@@ -1,3 +1,7 @@
+// Copyright 2017 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.
+
// +build go1.8
package ssa_test
diff --git a/go/ssa/interp/external.go b/go/ssa/interp/external.go
index 735a14d..68ddee3 100644
--- a/go/ssa/interp/external.go
+++ b/go/ssa/interp/external.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
diff --git a/go/types/typeutil/ui_test.go b/go/types/typeutil/ui_test.go
index b5064ac..5986b04 100644
--- a/go/types/typeutil/ui_test.go
+++ b/go/types/typeutil/ui_test.go
@@ -1,3 +1,7 @@
+// Copyright 2016 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 typeutil_test
import (
diff --git a/go/vcs/discovery.go b/go/vcs/discovery.go
index 2428d88..7d179bc 100644
--- a/go/vcs/discovery.go
+++ b/go/vcs/discovery.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 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.
diff --git a/go/vcs/env.go b/go/vcs/env.go
index e846f5b..189210c 100644
--- a/go/vcs/env.go
+++ b/go/vcs/env.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
diff --git a/go/vcs/http.go b/go/vcs/http.go
index 9618818..5836511 100644
--- a/go/vcs/http.go
+++ b/go/vcs/http.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 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.
diff --git a/go/vcs/vcs.go b/go/vcs/vcs.go
index 6e58ac7..1deb813 100644
--- a/go/vcs/vcs.go
+++ b/go/vcs/vcs.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 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.
diff --git a/go/vcs/vcs_test.go b/go/vcs/vcs_test.go
index b725f01..a17b50d 100644
--- a/go/vcs/vcs_test.go
+++ b/go/vcs/vcs_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
diff --git a/gopls/doc/contributing.md b/gopls/doc/contributing.md
index 89b4225..091e298 100644
--- a/gopls/doc/contributing.md
+++ b/gopls/doc/contributing.md
@@ -1,6 +1,11 @@
# Documentation for contributors
-Contributions are welcome, but since development is so active, we request that you file an issue and claim it before starting to work on something. Otherwise, it is likely that we might already be working on a fix for your issue.
+This documentation augments the general documentation for contributing to the
+x/tools repository, described at the [repository root](../CONTRIBUTING.md).
+
+Contributions are welcome, but since development is so active, we request that
+you file an issue and claim it before starting to work on something. Otherwise,
+it is likely that we might already be working on a fix for your issue.
## Finding issues
@@ -14,6 +19,13 @@
Provide information to get contributors up and running here
--->
+## Getting help
+
+The best way to contact the gopls team directly is via the
+[#gopls-dev](https://app.slack.com/client/T029RQSE6/CRWSN9NCD) channel on the
+gophers slack. Please feel free to ask any questions about your contribution or
+about contributing in general.
+
## Testing
To run tests for just `gopls/`, run,
@@ -33,6 +45,37 @@
go test ./internal/lsp/...
```
+### Regtests
+
+gopls has a suite of regression tests defined in the `./gopls/internal/regtest`
+directory. Each of these tests writes files to a temporary directory, starts a
+separate gopls session, and scripts interactions using an editor-like API. As a
+result of this overhead they can be quite slow, particularly on systems where
+file operations are costly.
+
+Due to the asynchronous nature of the LSP, regtests assertions are written
+as 'expectations' that the editor state must achieve _eventually_. This can
+make debugging the regtests difficult. To aid with debugging, the regtests
+output their LSP logs on any failure. If your CL gets a test failure while
+running the regtests, please do take a look at the description of the error and
+the LSP logs, but don't hesitate to [reach out](#getting-help) to the gopls
+team if you need help.
+
+### CI
+
+When you mail your CL and you or a fellow contributor assigns the
+`Run-TryBot=1` label in Gerrit, the
+[TryBots](https://golang.org/doc/contribute.html#trybots) will run tests in
+both the `golang.org/x/tools` and `golang.org/x/tools/gopls` modules, as
+described above.
+
+Furthermore, an additional "gopls-CI" pass will be run by _Kokoro_, which is a
+Jenkins-like Google infrastructure for running Dockerized tests. This allows us
+to run gopls tests in various environments that would be difficult to add to
+the TryBots. Notably, Kokoro runs tests on
+[older Go versions](user.md#supported-go-versions) that are no longer supported
+by the TryBots.
+
## Debugging
<!--- TODO: debugging
@@ -41,4 +84,4 @@
--->
[issue-gopls]: https://github.com/golang/go/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Agopls "gopls issues"
-[issue-wanted]: https://github.com/golang/go/issues?utf8=✓&q=is%3Aissue+is%3Aopen+label%3Agopls+label%3A"help+wanted" "help wanted"
\ No newline at end of file
+[issue-wanted]: https://github.com/golang/go/issues?utf8=✓&q=is%3Aissue+is%3Aopen+label%3Agopls+label%3A"help+wanted" "help wanted"
diff --git a/gopls/doc/emacs.md b/gopls/doc/emacs.md
index e618bd6..f8d75cc 100644
--- a/gopls/doc/emacs.md
+++ b/gopls/doc/emacs.md
@@ -1,12 +1,53 @@
# Emacs
-Use [lsp-mode]. gopls is built in as a client. You first must install `gopls` and put it somewhere in your `PATH`. Here is a basic config to get you started (assuming you are using [use-package]):
+## Installing `gopls`
-```lisp
-(use-package lsp-mode
- :ensure t
- :commands (lsp lsp-deferred)
- :hook (go-mode . lsp-deferred))
+To use `gopls` with Emacs, you must first
+[install the `gopls` binary](user.md#installation) and ensure that the directory
+containing the resulting binary (either `$(go env GOBIN)` or `$(go env
+GOPATH)/bin`) is in your `PATH`.
+
+## Choosing an Emacs LSP client
+
+To use `gopls` with Emacs, you will need to choose and install an Emacs LSP
+client package. Two popular client packages are [LSP Mode] and [Eglot].
+
+LSP Mode takes a batteries-included approach, with many integrations enabled
+“out of the box” and several additional behaviors provided by `lsp-mode` itself.
+
+Eglot takes a minimally-intrusive approach, focusing on smooth integration with
+other established packages. It provides a few of its own `eglot-` commands but
+no additional keybindings by default.
+
+Once you have selected which client you want to use, install it per the packages
+instructions: see [Eglot 1-2-3](https://github.com/joaotavora/eglot#1-2-3) or
+[LSP Mode Installation](https://emacs-lsp.github.io/lsp-mode/page/installation/).
+
+## Common configuration
+
+Both Eglot and LSP Mode can integrate with popular packages in the Emacs
+ecosystem:
+
+* The built-in [`xref`] package provides cross-references.
+
+* The built-in [Flymake] package provides an on-the-fly diagnostic overlay.
+
+* [Company] mode displays code completion candidates (with a richer UI than
+ the built-in [`completion-at-point`]).
+
+Eglot provides documentation using the built-in [ElDoc] minor mode, while LSP
+Mode by default provides documentation using its own [`lsp-ui`] mode.
+
+Eglot by default locates the project root using the [`project`] package. In LSP
+Mode, this behavior can be configured using the `lsp-auto-guess-root` setting.
+
+## Configuring LSP Mode
+
+### Loading LSP Mode in `.emacs`
+
+```elisp
+(require 'lsp-mode)
+(add-hook 'go-mode-hook #'lsp-deferred)
;; Set up before-save hooks to format buffer and add/delete imports.
;; Make sure you don't have other gofmt/goimports hooks enabled.
@@ -14,32 +55,15 @@
(add-hook 'before-save-hook #'lsp-format-buffer t t)
(add-hook 'before-save-hook #'lsp-organize-imports t t))
(add-hook 'go-mode-hook #'lsp-go-install-save-hooks)
-
-;; Optional - provides fancier overlays.
-(use-package lsp-ui
- :ensure t
- :commands lsp-ui-mode)
-
-;; Company mode is a standard completion package that works well with lsp-mode.
-(use-package company
- :ensure t
- :config
- ;; Optionally enable completion-as-you-type behavior.
- (setq company-idle-delay 0)
- (setq company-minimum-prefix-length 1))
-
-;; Optional - provides snippet support.
-(use-package yasnippet
- :ensure t
- :commands yas-minor-mode
- :hook (go-mode . yas-minor-mode))
```
-lsp-mode integrates with xref. By default `lsp-find-definition` is bound to `M-.`. To go back, use `M-,`. Explore other `lsp-*` commands (not everything is supported by gopls).
+### Configuring `gopls` via LSP Mode
-## Gopls Configuration
+See [settings] for information about available gopls settings.
-Stable gopls settings have first-class support in [lsp-mode]. For example, `(setq lsp-gopls-use-placeholders nil)` will disable placeholders in completion snippets. See [lsp-go] for a list of available variables.
+Stable gopls settings have corresponding configuration variables in `lsp-mode`.
+For example, `(setq lsp-gopls-use-placeholders nil)` will disable placeholders
+in completion snippets. See [`lsp-go`] for a list of available variables.
Experimental settings can be configured via `lsp-register-custom-settings`:
@@ -49,22 +73,107 @@
("gopls.staticcheck" t t)))
```
-See [settings] for information about gopls settings.
+Note that after changing settings you must restart gopls using e.g. `M-x
+lsp-restart-workspace`.
-Note that after changing settings you must restart gopls using e.g. `M-x lsp-restart-workspace`.
+## Configuring Eglot
+
+### Configuring `project` for Go modules in `.emacs`
+
+Eglot uses the built-in `project` package to identify the LSP workspace for a
+newly-opened buffer. The `project` package does not natively know about `GOPATH`
+or Go modules. Fortunately, you can give it a custom hook to tell it to look for
+the nearest parent `go.mod` file (that is, the root of the Go module) as the
+project root.
+
+```elisp
+(require 'project)
+
+(defun project-find-go-module (dir)
+ (when-let ((root (locate-dominating-file dir "go.mod")))
+ (cons 'go-module root)))
+
+(cl-defmethod project-root ((project (head go-module)))
+ (cdr project))
+
+(add-hook 'project-find-functions #'project-find-go-module)
+```
+
+### Loading Eglot in `.emacs`
+
+```elisp
+;; Optional: load other packages before eglot to enable eglot integrations.
+(require 'company)
+(require 'yasnippet)
+
+(require 'go-mode)
+(require 'eglot)
+(add-hook 'go-mode-hook 'eglot-ensure)
+
+;; Optional: install eglot-format-buffer as a save hook.
+;; The depth of -10 places this before eglot's willSave notification,
+;; so that that notification reports the actual contents that will be saved.
+(defun eglot-format-buffer-on-save ()
+ (add-hook 'before-save-hook #'eglot-format-buffer -10 t))
+(add-hook 'go-mode-hook #'eglot-format-buffer-on-save)
+```
+
+### Configuring `gopls` via Eglot
+
+See [settings] for information about available gopls settings.
+
+LSP server settings are controlled by the `eglot-workspace-configuration`
+variable, which can be set either globally in `.emacs` (as below) or in a
+`.dir-locals.el` file in the project root.
+
+```elisp
+(setq-default eglot-workspace-configuration
+ '((:gopls .
+ ((staticcheck . t)
+ (matcher . "CaseSensitive")))))
+```
+
+### Organizing imports with Eglot
+
+`gopls` provides the import-organizing functionality of `goimports` as an LSP
+code action, which you can invoke as needed by running `M-x eglot-code-actions`
+(or a key of your choice bound to the `eglot-code-actions` function) and
+selecting `Organize Imports` at the prompt.
+
+Eglot does not currently support a standalone function to execute a specific
+code action (see
+[joaotavora/eglot#411](https://github.com/joaotavora/eglot/issues/411)), nor an
+option to organize imports as a `before-save-hook` (see
+[joaotavora/eglot#574](https://github.com/joaotavora/eglot/issues/574)). In the
+meantime, see those issues for discussion and possible workarounds.
## Troubleshooting
Common errors:
-- When prompted by Emacs for your project folder, if you are using modules you must select the module's root folder (i.e. the directory with the "go.mod"). If you are using GOPATH, select your $GOPATH as your folder.
-- Emacs must have your environment set properly (PATH, GOPATH, etc). You can run `M-x getenv <RET> PATH <RET>` to see if your PATH is set in Emacs. If not, you can try starting Emacs from your terminal, using [this package][exec-path-from-shell], or moving your shell config from .bashrc into .bashenv (or .zshenv).
-- Make sure `lsp-mode` and `lsp-ui` are up-to-date, also make sure `lsp-go` and `company-lsp` are _not_ installed.
-- Look for errors in the `*lsp-log*` buffer.
-- Ask for help in the #emacs channel on the [Gophers slack].
-[lsp-mode]: https://github.com/emacs-lsp/lsp-mode
-[use-package]: https://github.com/jwiegley/use-package
-[exec-path-from-shell]: https://github.com/purcell/exec-path-from-shell
+- When prompted by Emacs for your project folder, if you are using modules you
+ must select the module's root folder (i.e. the directory with the "go.mod").
+ If you are using GOPATH, select your $GOPATH as your folder.
+- Emacs must have your environment set properly (PATH, GOPATH, etc). You can
+ run `M-x getenv <RET> PATH <RET>` to see if your PATH is set in Emacs. If
+ not, you can try starting Emacs from your terminal, using [this
+ package][exec-path-from-shell], or moving your shell config from `.bashrc`
+ into `.profile` and logging out and back in.
+- Make sure only one LSP client mode is installed. (For example, if using
+ `lsp-mode`, ensure that you are not _also_ enabling `eglot`.)
+- Look for errors in the `*lsp-log*` buffer or run `M-x eglot-events-buffer`.
+- Ask for help in the `#emacs` channel on the [Gophers slack].
+
+[LSP Mode]: https://emacs-lsp.github.io/lsp-mode/
+[Eglot]: https://github.com/joaotavora/eglot/blob/master/README.md
+[`xref`]: https://www.gnu.org/software/emacs/manual/html_node/emacs/Xref.html
+[Flymake]: https://www.gnu.org/software/emacs/manual/html_node/flymake/Using-Flymake.html#Using-Flymake
+[Company]: https://company-mode.github.io/
+[`completion-at-point`]: https://www.gnu.org/software/emacs/manual/html_node/elisp/Completion-in-Buffers.html
+[ElDoc]: https://elpa.gnu.org/packages/eldoc.html
+[`lsp-ui`]: https://emacs-lsp.github.io/lsp-ui/
+[`lsp-go`]: https://github.com/emacs-lsp/lsp-mode/blob/master/clients/lsp-go.el
+[`use-package`]: https://github.com/jwiegley/use-package
+[`exec-path-from-shell`]: https://github.com/purcell/exec-path-from-shell
[settings]: settings.md
-[lsp-go]: https://github.com/emacs-lsp/lsp-mode/blob/master/clients/lsp-go.el
[Gophers slack]: https://invite.slack.golangbridge.org/
diff --git a/gopls/doc/vim.md b/gopls/doc/vim.md
index f05a4e3..63c1d58 100644
--- a/gopls/doc/vim.md
+++ b/gopls/doc/vim.md
@@ -215,5 +215,5 @@
[govim-install]: https://github.com/myitcv/govim/blob/master/README.md#govim---go-development-plugin-for-vim8
[nvim-docs]: https://neovim.io/doc/user/lsp.html
[nvim-install]: https://github.com/neovim/neovim/wiki/Installing-Neovim
-[nvim-lspconfig]: https://github.com/neovim/nvim-lspconfig#gopls
+[nvim-lspconfig]: https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#gopls
[nvim-lspconfig-imports]: https://github.com/neovim/nvim-lspconfig/issues/115
diff --git a/gopls/go.mod b/gopls/go.mod
index 323690f..139a166 100644
--- a/gopls/go.mod
+++ b/gopls/go.mod
@@ -6,10 +6,12 @@
github.com/jba/templatecheck v0.5.0
github.com/sanity-io/litter v1.3.0
github.com/sergi/go-diff v1.1.0
- golang.org/x/mod v0.3.0
- golang.org/x/tools v0.0.0-20201230224654-641242d23425
+ golang.org/x/mod v0.4.0
+ golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
honnef.co/go/tools v0.0.1-2020.1.6
- mvdan.cc/gofumpt v0.0.0-20200927160801-5bfeb2e70dd6
+ mvdan.cc/gofumpt v0.1.0
mvdan.cc/xurls/v2 v2.2.0
)
+
+replace golang.org/x/tools => ../
diff --git a/gopls/go.sum b/gopls/go.sum
index f0ff97f..c3f96cb 100644
--- a/gopls/go.sum
+++ b/gopls/go.sum
@@ -4,8 +4,8 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
-github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/safehtml v0.0.2 h1:ZOt2VXg4x24bW0m2jtzAOkhoXV0iM8vNKc0paByCZqM=
github.com/google/safehtml v0.0.2/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU=
@@ -22,7 +22,7 @@
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/sanity-io/litter v1.3.0 h1:5ZO+weUsqdSWMUng5JnpkW/Oz8iTXiIdeumhQr1sSjs=
github.com/sanity-io/litter v1.3.0/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
@@ -31,39 +31,24 @@
github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
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/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
+golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20201230224654-641242d23425 h1:CknW2gSa6nckpH6mEnvpj26GNhhqKvoru1gHJ2CgPWU=
-golang.org/x/tools v0.0.0-20201230224654-641242d23425/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
@@ -78,7 +63,7 @@
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.1-2020.1.6 h1:W18jzjh8mfPez+AwGLxmOImucz/IFjpNlrKVnaj2YVc=
honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY=
-mvdan.cc/gofumpt v0.0.0-20200927160801-5bfeb2e70dd6 h1:z+/YqapuV7VZPvBb3GYmuEJbA88M3PFUxaHilHYVCpQ=
-mvdan.cc/gofumpt v0.0.0-20200927160801-5bfeb2e70dd6/go.mod h1:bzrjFmaD6+xqohD3KYP0H2FEuxknnBmyyOxdhLdaIws=
+mvdan.cc/gofumpt v0.1.0 h1:hsVv+Y9UsZ/mFZTxJZuHVI6shSQCtzZ11h1JEFPAZLw=
+mvdan.cc/gofumpt v0.1.0/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48=
mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A=
mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8=
diff --git a/gopls/internal/hooks/gen-licenses.sh b/gopls/internal/hooks/gen-licenses.sh
new file mode 100755
index 0000000..f0756ff
--- /dev/null
+++ b/gopls/internal/hooks/gen-licenses.sh
@@ -0,0 +1,45 @@
+#!/bin/bash -eu
+
+# Copyright 2020 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.
+
+set -o pipefail
+
+tempfile=$(mktemp)
+cd $(dirname $0)
+
+modhash=$(sha256sum ../../go.sum | awk '{print $1}')
+# Make sure we have the code for all the modules we depend on.
+go mod download
+
+cat > $tempfile <<END
+// Copyright 2020 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.
+
+//go:generate ./gen-licenses.sh licenses.go
+package hooks
+
+const licensesText = \`
+END
+
+# List all the modules gopls depends on, except other golang.org modules, which
+# are known to have the same license.
+mods=$(go list -deps -f '{{with .Module}}{{.Path}}{{end}}' golang.org/x/tools/gopls | sort -u | grep -v golang.org)
+for mod in $mods; do
+ # Find the license file, either LICENSE or COPYING, and add it to the result.
+ dir=$(go list -m -f {{.Dir}} $mod)
+ license=$(ls -1 $dir | egrep -i '^(LICENSE|COPYING)$')
+ echo "-- $mod $license --" >> $tempfile
+ echo >> $tempfile
+ sed 's/^-- / &/' $dir/$license >> $tempfile
+ echo >> $tempfile
+done
+
+cat >> $tempfile << END
+\`
+
+const licensesGeneratedFrom = "$modhash"
+END
+mv $tempfile licenses.go
\ No newline at end of file
diff --git a/gopls/internal/hooks/hooks.go b/gopls/internal/hooks/hooks.go
index c864aa3..50e8f71 100644
--- a/gopls/internal/hooks/hooks.go
+++ b/gopls/internal/hooks/hooks.go
@@ -17,6 +17,7 @@
)
func Options(options *source.Options) {
+ options.LicensesText = licensesText
if options.GoDiff {
options.ComputeEdits = ComputeEdits
}
diff --git a/gopls/internal/hooks/licenses.go b/gopls/internal/hooks/licenses.go
new file mode 100644
index 0000000..58dea04
--- /dev/null
+++ b/gopls/internal/hooks/licenses.go
@@ -0,0 +1,171 @@
+// Copyright 2020 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.
+
+//go:generate ./gen-licenses.sh licenses.go
+package hooks
+
+const licensesText = `
+-- github.com/BurntSushi/toml COPYING --
+
+The MIT License (MIT)
+
+Copyright (c) 2013 TOML authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+-- github.com/google/go-cmp LICENSE --
+
+Copyright (c) 2017 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-- github.com/sergi/go-diff LICENSE --
+
+Copyright (c) 2012-2016 The go-diff Authors. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+
+-- honnef.co/go/tools LICENSE --
+
+Copyright (c) 2016 Dominik Honnef
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-- mvdan.cc/gofumpt LICENSE --
+
+Copyright (c) 2019, Daniel Martí. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of the copyright holder nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-- mvdan.cc/xurls/v2 LICENSE --
+
+Copyright (c) 2015, Daniel Martí. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of the copyright holder nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+`
+
+const licensesGeneratedFrom = "3fbcbd4a23419568c3f6609cc89f2918537c4ea023dc11a5bb55e3d3e5a67368"
diff --git a/gopls/internal/hooks/licenses_test.go b/gopls/internal/hooks/licenses_test.go
new file mode 100644
index 0000000..28b1149
--- /dev/null
+++ b/gopls/internal/hooks/licenses_test.go
@@ -0,0 +1,23 @@
+// Copyright 2020 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 hooks
+
+import (
+ "crypto/sha256"
+ "encoding/hex"
+ "io/ioutil"
+ "testing"
+)
+
+func TestLicenses(t *testing.T) {
+ sumBytes, err := ioutil.ReadFile("../../go.sum")
+ if err != nil {
+ t.Fatal(err)
+ }
+ sumSum := sha256.Sum256(sumBytes)
+ if licensesGeneratedFrom != hex.EncodeToString(sumSum[:]) {
+ t.Error("combined license text needs updating. Run: `go generate ./internal/hooks` from the gopls module.")
+ }
+}
diff --git a/gopls/internal/regtest/completion_test.go b/gopls/internal/regtest/completion_test.go
index 3d33799..412fdab 100644
--- a/gopls/internal/regtest/completion_test.go
+++ b/gopls/internal/regtest/completion_test.go
@@ -221,30 +221,46 @@
-- go.mod --
module mod.com
-go 1.12
+go 1.14
+
+require example.com v1.2.3
+-- go.sum --
+example.com v1.2.3 h1:ihBTGWGjTU3V4ZJ9OmHITkU9WQ4lGdQkMjgyLFk0FaY=
+example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo=
-- main.go --
package main
func main() {
_ = blah
}
+-- main2.go --
+package main
+
+import "example.com/blah"
+
+func _() {
+ _ = blah.Hello
+}
`
withOptions(
ProxyFiles(proxy),
).run(t, mod, func(t *testing.T, env *Env) {
- // Explicitly download example.com so it's added to the module cache
- // and offered as an unimported completion.
- env.RunGoCommand("get", "example.com@v1.2.3")
+ // Make sure the dependency is in the module cache and accessible for
+ // unimported completions, and then remove it before proceeding.
+ env.RemoveWorkspaceFile("main2.go")
env.RunGoCommand("mod", "tidy")
+ env.Await(CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), 2))
// Trigger unimported completions for the example.com/blah package.
env.OpenFile("main.go")
+ env.Await(CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1))
pos := env.RegexpSearch("main.go", "ah")
completions := env.Completion("main.go", pos)
if len(completions.Items) == 0 {
t.Fatalf("no completion items")
}
env.AcceptCompletion("main.go", pos, completions.Items[0])
+ env.Await(CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 1))
// Trigger completions once again for the blah.<> selector.
env.RegexpReplace("main.go", "_ = blah", "_ = blah.")
@@ -270,3 +286,40 @@
)
})
}
+
+// Test that completions still work with an undownloaded module, golang/go#43333.
+func TestUndownloadedModule(t *testing.T) {
+ // mod.com depends on example.com, but only in a file that's hidden by a
+ // build tag, so the IWL won't download example.com. That will cause errors
+ // in the go list -m call performed by the imports package.
+ const files = `
+-- go.mod --
+module mod.com
+
+go 1.14
+
+require example.com v1.2.3
+-- go.sum --
+example.com v1.2.3 h1:ihBTGWGjTU3V4ZJ9OmHITkU9WQ4lGdQkMjgyLFk0FaY=
+example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo=
+-- useblah.go --
+// +build hidden
+
+package pkg
+import "example.com/blah"
+var _ = blah.Name
+-- mainmod/mainmod.go --
+package mainmod
+
+const Name = "mainmod"
+`
+ withOptions(ProxyFiles(proxy)).run(t, files, func(t *testing.T, env *Env) {
+ env.CreateBuffer("import.go", "package pkg\nvar _ = mainmod.Name\n")
+ env.SaveBuffer("import.go")
+ content := env.ReadWorkspaceFile("import.go")
+ if !strings.Contains(content, `import "mod.com/mainmod`) {
+ t.Errorf("expected import of mod.com/mainmod in %q", content)
+ }
+ })
+
+}
diff --git a/gopls/internal/regtest/diagnostics_test.go b/gopls/internal/regtest/diagnostics_test.go
index 50bb593..8aa45ca 100644
--- a/gopls/internal/regtest/diagnostics_test.go
+++ b/gopls/internal/regtest/diagnostics_test.go
@@ -1091,12 +1091,15 @@
var x int
}
`
- runner.Run(t, mod, func(t *testing.T, env *Env) {
+ withOptions(
+ // Empty workspace folders.
+ WorkspaceFolders(),
+ ).run(t, mod, func(t *testing.T, env *Env) {
env.OpenFile("a/a.go")
env.Await(
env.DiagnosticAtRegexp("a/a.go", "x"),
)
- }, WithoutWorkspaceFolders())
+ })
}
// Reproduces the case described in
@@ -1249,13 +1252,18 @@
var x int
}
`
- withOptions(RootPath("a")).run(t, mod, func(t *testing.T, env *Env) {
+ withOptions(
+ WorkspaceFolders("a"),
+ ).run(t, mod, func(t *testing.T, env *Env) {
env.OpenFile("a/main.go")
env.Await(
env.DiagnosticAtRegexp("main.go", "x"),
)
})
- withOptions(RootPath("a"), LimitWorkspaceScope()).run(t, mod, func(t *testing.T, env *Env) {
+ withOptions(
+ WorkspaceFolders("a"),
+ LimitWorkspaceScope(),
+ ).run(t, mod, func(t *testing.T, env *Env) {
env.OpenFile("a/main.go")
env.Await(
NoDiagnostics("main.go"),
diff --git a/gopls/internal/regtest/formatting_test.go b/gopls/internal/regtest/formatting_test.go
index c9c00da..63fa0ce1 100644
--- a/gopls/internal/regtest/formatting_test.go
+++ b/gopls/internal/regtest/formatting_test.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 regtest
import (
diff --git a/gopls/internal/regtest/imports_test.go b/gopls/internal/regtest/imports_test.go
index 68e06b3..1c52d59 100644
--- a/gopls/internal/regtest/imports_test.go
+++ b/gopls/internal/regtest/imports_test.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 regtest
import (
diff --git a/gopls/internal/regtest/modfile_test.go b/gopls/internal/regtest/modfile_test.go
index 0f79646..faef053 100644
--- a/gopls/internal/regtest/modfile_test.go
+++ b/gopls/internal/regtest/modfile_test.go
@@ -34,23 +34,14 @@
const Name = "Hello"
`
-func runModfileTest(t *testing.T, files, proxy string, f TestFunc) {
- t.Run("normal", func(t *testing.T) {
- withOptions(ProxyFiles(proxy)).run(t, files, f)
- })
- t.Run("nested", func(t *testing.T) {
- withOptions(ProxyFiles(proxy), NestWorkdir(), Modes(Singleton|Experimental)).run(t, files, f)
- })
-}
-
func TestModFileModification(t *testing.T) {
testenv.NeedsGo1Point(t, 14)
const untidyModule = `
--- go.mod --
+-- a/go.mod --
module mod.com
--- main.go --
+-- a/main.go --
package main
import "example.com/blah"
@@ -59,25 +50,31 @@
println(blah.Name)
}
`
+
+ runner := runMultiple{
+ {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))},
+ {"nested", withOptions(ProxyFiles(proxy))},
+ }
+
t.Run("basic", func(t *testing.T) {
- runModfileTest(t, untidyModule, proxy, func(t *testing.T, env *Env) {
+ runner.run(t, untidyModule, func(t *testing.T, env *Env) {
// Open the file and make sure that the initial workspace load does not
// modify the go.mod file.
- goModContent := env.ReadWorkspaceFile("go.mod")
- env.OpenFile("main.go")
+ goModContent := env.ReadWorkspaceFile("a/go.mod")
+ env.OpenFile("a/main.go")
env.Await(
- env.DiagnosticAtRegexp("main.go", "\"example.com/blah\""),
+ env.DiagnosticAtRegexp("a/main.go", "\"example.com/blah\""),
)
- if got := env.ReadWorkspaceFile("go.mod"); got != goModContent {
+ if got := env.ReadWorkspaceFile("a/go.mod"); got != goModContent {
t.Fatalf("go.mod changed on disk:\n%s", tests.Diff(t, goModContent, got))
}
// Save the buffer, which will format and organize imports.
// Confirm that the go.mod file still does not change.
- env.SaveBuffer("main.go")
+ env.SaveBuffer("a/main.go")
env.Await(
- env.DiagnosticAtRegexp("main.go", "\"example.com/blah\""),
+ env.DiagnosticAtRegexp("a/main.go", "\"example.com/blah\""),
)
- if got := env.ReadWorkspaceFile("go.mod"); got != goModContent {
+ if got := env.ReadWorkspaceFile("a/go.mod"); got != goModContent {
t.Fatalf("go.mod changed on disk:\n%s", tests.Diff(t, goModContent, got))
}
})
@@ -87,13 +84,13 @@
t.Run("delete main.go", func(t *testing.T) {
t.Skip("This test will be flaky until golang/go#40269 is resolved.")
- runModfileTest(t, untidyModule, proxy, func(t *testing.T, env *Env) {
- goModContent := env.ReadWorkspaceFile("go.mod")
- mainContent := env.ReadWorkspaceFile("main.go")
- env.OpenFile("main.go")
- env.SaveBuffer("main.go")
+ runner.run(t, untidyModule, func(t *testing.T, env *Env) {
+ goModContent := env.ReadWorkspaceFile("a/go.mod")
+ mainContent := env.ReadWorkspaceFile("a/main.go")
+ env.OpenFile("a/main.go")
+ env.SaveBuffer("a/main.go")
- env.RemoveWorkspaceFile("main.go")
+ env.RemoveWorkspaceFile("a/main.go")
env.Await(
CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1),
CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidSave), 1),
@@ -114,12 +111,12 @@
func TestGoGetFix(t *testing.T) {
testenv.NeedsGo1Point(t, 14)
const mod = `
--- go.mod --
+-- a/go.mod --
module mod.com
go 1.12
--- main.go --
+-- a/main.go --
package main
import "example.com/blah"
@@ -134,16 +131,19 @@
require example.com v1.2.3
`
- runModfileTest(t, mod, proxy, func(t *testing.T, env *Env) {
+ runMultiple{
+ {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))},
+ {"nested", withOptions(ProxyFiles(proxy))},
+ }.run(t, mod, func(t *testing.T, env *Env) {
if strings.Contains(t.Name(), "workspace_module") {
t.Skip("workspace module mode doesn't set -mod=readonly")
}
- env.OpenFile("main.go")
+ env.OpenFile("a/main.go")
var d protocol.PublishDiagnosticsParams
env.Await(
OnceMet(
- env.DiagnosticAtRegexp("main.go", `"example.com/blah"`),
- ReadDiagnostics("main.go", &d),
+ env.DiagnosticAtRegexp("a/main.go", `"example.com/blah"`),
+ ReadDiagnostics("a/main.go", &d),
),
)
var goGetDiag protocol.Diagnostic
@@ -152,8 +152,8 @@
goGetDiag = diag
}
}
- env.ApplyQuickFixes("main.go", []protocol.Diagnostic{goGetDiag})
- if got := env.ReadWorkspaceFile("go.mod"); got != want {
+ env.ApplyQuickFixes("a/main.go", []protocol.Diagnostic{goGetDiag})
+ if got := env.ReadWorkspaceFile("a/go.mod"); got != want {
t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(t, want, got))
}
})
@@ -163,12 +163,12 @@
func TestMissingDependencyFixes(t *testing.T) {
testenv.NeedsGo1Point(t, 14)
const mod = `
--- go.mod --
+-- a/go.mod --
module mod.com
go 1.12
--- main.go --
+-- a/main.go --
package main
import "example.com/blah"
@@ -184,13 +184,16 @@
require random.org v1.2.3
`
- runModfileTest(t, mod, proxy, func(t *testing.T, env *Env) {
- env.OpenFile("main.go")
+ runMultiple{
+ {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))},
+ {"nested", withOptions(ProxyFiles(proxy))},
+ }.run(t, mod, func(t *testing.T, env *Env) {
+ env.OpenFile("a/main.go")
var d protocol.PublishDiagnosticsParams
env.Await(
OnceMet(
- env.DiagnosticAtRegexp("main.go", `"random.org/blah"`),
- ReadDiagnostics("main.go", &d),
+ env.DiagnosticAtRegexp("a/main.go", `"random.org/blah"`),
+ ReadDiagnostics("a/main.go", &d),
),
)
var randomDiag protocol.Diagnostic
@@ -199,8 +202,8 @@
randomDiag = diag
}
}
- env.ApplyQuickFixes("main.go", []protocol.Diagnostic{randomDiag})
- if got := env.ReadWorkspaceFile("go.mod"); got != want {
+ env.ApplyQuickFixes("a/main.go", []protocol.Diagnostic{randomDiag})
+ if got := env.ReadWorkspaceFile("a/go.mod"); got != want {
t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(t, want, got))
}
})
@@ -210,16 +213,16 @@
testenv.NeedsGo1Point(t, 14)
const mod = `
--- go.mod --
+-- a/go.mod --
module mod.com
go 1.12
require example.com v1.2.3 // indirect
--- go.sum --
+-- a/go.sum --
example.com v1.2.3 h1:ihBTGWGjTU3V4ZJ9OmHITkU9WQ4lGdQkMjgyLFk0FaY=
example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo=
--- main.go --
+-- a/main.go --
package main
import "example.com/blah"
@@ -233,17 +236,21 @@
require example.com v1.2.3
`
- runModfileTest(t, mod, proxy, func(t *testing.T, env *Env) {
- env.OpenFile("go.mod")
+
+ runMultiple{
+ {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))},
+ {"nested", withOptions(ProxyFiles(proxy))},
+ }.run(t, mod, func(t *testing.T, env *Env) {
+ env.OpenFile("a/go.mod")
var d protocol.PublishDiagnosticsParams
env.Await(
OnceMet(
- env.DiagnosticAtRegexp("go.mod", "// indirect"),
- ReadDiagnostics("go.mod", &d),
+ env.DiagnosticAtRegexp("a/go.mod", "// indirect"),
+ ReadDiagnostics("a/go.mod", &d),
),
)
- env.ApplyQuickFixes("go.mod", d.Diagnostics)
- if got := env.Editor.BufferText("go.mod"); got != want {
+ env.ApplyQuickFixes("a/go.mod", d.Diagnostics)
+ if got := env.Editor.BufferText("a/go.mod"); got != want {
t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(t, want, got))
}
})
@@ -258,14 +265,14 @@
const X = 1
`
const files = `
--- go.mod --
+-- a/go.mod --
module mod.com
go 1.14
require example.com v1.0.0
--- go.sum --
+-- a/go.sum --
example.com v1.0.0 h1:38O7j5rEBajXk+Q5wzLbRN7KqMkSgEiN9NqcM1O2bBM=
example.com v1.0.0/go.mod h1:vUsPMGpx9ZXXzECCOsOmYCW7npJTwuA16yl89n3Mgls=
--- main.go --
+-- a/main.go --
package main
func main() {}
`
@@ -275,17 +282,20 @@
go 1.14
`
- runModfileTest(t, files, proxy, func(t *testing.T, env *Env) {
- env.OpenFile("go.mod")
+ runMultiple{
+ {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))},
+ {"nested", withOptions(ProxyFiles(proxy))},
+ }.run(t, files, func(t *testing.T, env *Env) {
+ env.OpenFile("a/go.mod")
var d protocol.PublishDiagnosticsParams
env.Await(
OnceMet(
- env.DiagnosticAtRegexp("go.mod", `require example.com`),
- ReadDiagnostics("go.mod", &d),
+ env.DiagnosticAtRegexp("a/go.mod", `require example.com`),
+ ReadDiagnostics("a/go.mod", &d),
),
)
- env.ApplyQuickFixes("go.mod", d.Diagnostics)
- if got := env.ReadWorkspaceFile("go.mod"); got != want {
+ env.ApplyQuickFixes("a/go.mod", d.Diagnostics)
+ if got := env.ReadWorkspaceFile("a/go.mod"); got != want {
t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(t, want, got))
}
})
@@ -313,18 +323,18 @@
package hello
`
const repro = `
--- go.mod --
+-- a/go.mod --
module mod.com
go 1.14
require google.golang.org/protobuf v1.20.0
--- go.sum --
+-- a/go.sum --
github.com/esimov/caire v1.2.5 h1:OcqDII/BYxcBYj3DuwDKjd+ANhRxRqLa2n69EGje7qw=
github.com/esimov/caire v1.2.5/go.mod h1:mXnjRjg3+WUtuhfSC1rKRmdZU9vJZyS1ZWU0qSvJhK8=
google.golang.org/protobuf v1.20.0 h1:y9T1vAtFKQg0faFNMOxJU7WuEqPWolVkjIkU6aI8qCY=
google.golang.org/protobuf v1.20.0/go.mod h1:FcqsytGClbtLv1ot8NvsJHjBi0h22StKVP+K/j2liKA=
--- main.go --
+-- a/main.go --
package main
import (
@@ -334,16 +344,20 @@
func _() {
caire.RemoveTempImage()
}`
- runModfileTest(t, repro, proxy, func(t *testing.T, env *Env) {
- env.OpenFile("main.go")
+
+ runMultiple{
+ {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))},
+ {"nested", withOptions(ProxyFiles(proxy))},
+ }.run(t, repro, func(t *testing.T, env *Env) {
+ env.OpenFile("a/main.go")
var d protocol.PublishDiagnosticsParams
env.Await(
OnceMet(
- env.DiagnosticAtRegexp("main.go", `"github.com/esimov/caire"`),
- ReadDiagnostics("main.go", &d),
+ env.DiagnosticAtRegexp("a/main.go", `"github.com/esimov/caire"`),
+ ReadDiagnostics("a/main.go", &d),
),
)
- env.ApplyQuickFixes("main.go", d.Diagnostics)
+ env.ApplyQuickFixes("a/main.go", d.Diagnostics)
want := `module mod.com
go 1.14
@@ -353,7 +367,7 @@
google.golang.org/protobuf v1.20.0
)
`
- if got := env.ReadWorkspaceFile("go.mod"); got != want {
+ if got := env.ReadWorkspaceFile("a/go.mod"); got != want {
t.Fatalf("TestNewDepWithUnusedDep failed:\n%s", tests.Diff(t, want, got))
}
})
@@ -366,26 +380,29 @@
testenv.NeedsGo1Point(t, 14)
const mod = `
--- go.mod --
+-- a/go.mod --
module mod.com
go 1.12
require example.com v1.2.3
--- go.sum --
+-- a/go.sum --
example.com v1.2.3 h1:ihBTGWGjTU3V4ZJ9OmHITkU9WQ4lGdQkMjgyLFk0FaY=
example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo=
--- main.go --
+-- a/main.go --
package main
func main() {
fmt.Println(blah.Name)
`
- runModfileTest(t, mod, proxy, func(t *testing.T, env *Env) {
- env.Await(env.DiagnosticAtRegexp("go.mod", "require"))
- env.RunGoCommand("mod", "tidy")
+ runMultiple{
+ {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))},
+ {"nested", withOptions(ProxyFiles(proxy))},
+ }.run(t, mod, func(t *testing.T, env *Env) {
+ env.Await(env.DiagnosticAtRegexp("a/go.mod", "require"))
+ env.RunGoCommandInDir("a", "mod", "tidy")
env.Await(
- EmptyDiagnostics("go.mod"),
+ EmptyDiagnostics("a/go.mod"),
)
})
}
@@ -417,35 +434,38 @@
const Name = "Blah"
`
const files = `
--- go.mod --
+-- a/go.mod --
module mod.com
go 1.12
require example.com/blah/v2 v2.0.0
--- go.sum --
+-- a/go.sum --
example.com/blah v1.0.0 h1:kGPlWJbMsn1P31H9xp/q2mYI32cxLnCvauHN0AVaHnc=
example.com/blah v1.0.0/go.mod h1:PZUQaGFeVjyDmAE8ywmLbmDn3fj4Ws8epg4oLuDzW3M=
example.com/blah/v2 v2.0.0 h1:w5baE9JuuU11s3de3yWx2sU05AhNkgLYdZ4qukv+V0k=
example.com/blah/v2 v2.0.0/go.mod h1:UZiKbTwobERo/hrqFLvIQlJwQZQGxWMVY4xere8mj7w=
--- main.go --
+-- a/main.go --
package main
import "example.com/blah/v2"
var _ = blah.Name
`
- withOptions(ProxyFiles(proxy)).run(t, files, func(t *testing.T, env *Env) {
- env.OpenFile("main.go")
- env.OpenFile("go.mod")
+ runMultiple{
+ {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))},
+ {"nested", withOptions(ProxyFiles(proxy))},
+ }.run(t, files, func(t *testing.T, env *Env) {
+ env.OpenFile("a/main.go")
+ env.OpenFile("a/go.mod")
var d protocol.PublishDiagnosticsParams
env.Await(
OnceMet(
- DiagnosticAt("go.mod", 0, 0),
- ReadDiagnostics("go.mod", &d),
+ DiagnosticAt("a/go.mod", 0, 0),
+ ReadDiagnostics("a/go.mod", &d),
),
)
- env.ApplyQuickFixes("main.go", d.Diagnostics)
+ env.ApplyQuickFixes("a/main.go", d.Diagnostics)
const want = `module mod.com
go 1.12
@@ -455,8 +475,8 @@
example.com/blah/v2 v2.0.0
)
`
- env.Await(EmptyDiagnostics("go.mod"))
- if got := env.Editor.BufferText("go.mod"); got != want {
+ env.Await(EmptyDiagnostics("a/go.mod"))
+ if got := env.Editor.BufferText("a/go.mod"); got != want {
t.Fatalf("suggested fixes failed:\n%s", tests.Diff(t, want, got))
}
})
@@ -467,13 +487,13 @@
testenv.NeedsGo1Point(t, 14)
const unknown = `
--- go.mod --
+-- a/go.mod --
module mod.com
require (
example.com v1.2.2
)
--- main.go --
+-- a/main.go --
package main
import "example.com/blah"
@@ -483,43 +503,47 @@
}
`
+ runner := runMultiple{
+ {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))},
+ {"nested", withOptions(ProxyFiles(proxy))},
+ }
// Start from a bad state/bad IWL, and confirm that we recover.
t.Run("bad", func(t *testing.T) {
- runModfileTest(t, unknown, proxy, func(t *testing.T, env *Env) {
- env.OpenFile("go.mod")
+ runner.run(t, unknown, func(t *testing.T, env *Env) {
+ env.OpenFile("a/go.mod")
env.Await(
- env.DiagnosticAtRegexp("go.mod", "example.com v1.2.2"),
+ env.DiagnosticAtRegexp("a/go.mod", "example.com v1.2.2"),
)
- env.RegexpReplace("go.mod", "v1.2.2", "v1.2.3")
- env.Editor.SaveBuffer(env.Ctx, "go.mod") // go.mod changes must be on disk
+ env.RegexpReplace("a/go.mod", "v1.2.2", "v1.2.3")
+ env.Editor.SaveBuffer(env.Ctx, "a/go.mod") // go.mod changes must be on disk
d := protocol.PublishDiagnosticsParams{}
env.Await(
OnceMet(
- env.DiagnosticAtRegexpWithMessage("go.mod", "example.com v1.2.3", "example.com@v1.2.3"),
- ReadDiagnostics("go.mod", &d),
+ env.DiagnosticAtRegexpWithMessage("a/go.mod", "example.com v1.2.3", "example.com@v1.2.3"),
+ ReadDiagnostics("a/go.mod", &d),
),
)
- env.ApplyQuickFixes("go.mod", d.Diagnostics)
+ env.ApplyQuickFixes("a/go.mod", d.Diagnostics)
env.Await(
- EmptyDiagnostics("go.mod"),
- env.DiagnosticAtRegexp("main.go", "x = "),
+ EmptyDiagnostics("a/go.mod"),
+ env.DiagnosticAtRegexp("a/main.go", "x = "),
)
})
})
const known = `
--- go.mod --
+-- a/go.mod --
module mod.com
require (
example.com v1.2.3
)
--- go.sum --
+-- a/go.sum --
example.com v1.2.3 h1:ihBTGWGjTU3V4ZJ9OmHITkU9WQ4lGdQkMjgyLFk0FaY=
example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo=
--- main.go --
+-- a/main.go --
package main
import "example.com/blah"
@@ -531,20 +555,20 @@
// Start from a good state, transform to a bad state, and confirm that we
// still recover.
t.Run("good", func(t *testing.T) {
- runModfileTest(t, known, proxy, func(t *testing.T, env *Env) {
- env.OpenFile("go.mod")
+ runner.run(t, known, func(t *testing.T, env *Env) {
+ env.OpenFile("a/go.mod")
env.Await(
- env.DiagnosticAtRegexp("main.go", "x = "),
+ env.DiagnosticAtRegexp("a/main.go", "x = "),
)
- env.RegexpReplace("go.mod", "v1.2.3", "v1.2.2")
- env.Editor.SaveBuffer(env.Ctx, "go.mod") // go.mod changes must be on disk
+ env.RegexpReplace("a/go.mod", "v1.2.3", "v1.2.2")
+ env.Editor.SaveBuffer(env.Ctx, "a/go.mod") // go.mod changes must be on disk
env.Await(
- env.DiagnosticAtRegexp("go.mod", "example.com v1.2.2"),
+ env.DiagnosticAtRegexp("a/go.mod", "example.com v1.2.2"),
)
- env.RegexpReplace("go.mod", "v1.2.2", "v1.2.3")
- env.Editor.SaveBuffer(env.Ctx, "go.mod") // go.mod changes must be on disk
+ env.RegexpReplace("a/go.mod", "v1.2.2", "v1.2.3")
+ env.Editor.SaveBuffer(env.Ctx, "a/go.mod") // go.mod changes must be on disk
env.Await(
- env.DiagnosticAtRegexp("main.go", "x = "),
+ env.DiagnosticAtRegexp("a/main.go", "x = "),
)
})
})
@@ -576,13 +600,13 @@
const Name = "Hello"
`
const module = `
--- go.mod --
+-- a/go.mod --
module mod.com
go 1.14
require example.com v1.2.3
--- main.go --
+-- a/main.go --
package main
import "example.com/blah"
@@ -591,10 +615,13 @@
println(blah.Name)
}
`
- runModfileTest(t, module, badProxy, func(t *testing.T, env *Env) {
- env.OpenFile("go.mod")
+ runMultiple{
+ {"default", withOptions(ProxyFiles(badProxy), WorkspaceFolders("a"))},
+ {"nested", withOptions(ProxyFiles(badProxy))},
+ }.run(t, module, func(t *testing.T, env *Env) {
+ env.OpenFile("a/go.mod")
env.Await(
- env.DiagnosticAtRegexp("go.mod", "require example.com v1.2.3"),
+ env.DiagnosticAtRegexp("a/go.mod", "require example.com v1.2.3"),
)
})
}
@@ -801,6 +828,7 @@
Modes(Singleton),
).run(t, mod, func(t *testing.T, env *Env) {
env.OpenFile("go.mod")
+ env.Await(CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1))
env.RegexpReplace("go.mod", "module", "modul")
// Confirm that we still have metadata with only on-disk edits.
env.OpenFile("main.go")
diff --git a/gopls/internal/regtest/reg_test.go b/gopls/internal/regtest/reg_test.go
index dfcddbb..f8aae7f 100644
--- a/gopls/internal/regtest/reg_test.go
+++ b/gopls/internal/regtest/reg_test.go
@@ -29,6 +29,10 @@
var runner *Runner
+type regtestRunner interface {
+ run(t *testing.T, files string, f TestFunc)
+}
+
func run(t *testing.T, files string, f TestFunc) {
runner.Run(t, files, f)
}
@@ -45,6 +49,18 @@
runner.Run(t, files, f, r.opts...)
}
+type runMultiple []struct {
+ name string
+ runner regtestRunner
+}
+
+func (r runMultiple) run(t *testing.T, files string, f TestFunc) {
+ for _, runner := range r {
+ t.Run(runner.name, func(t *testing.T) {
+ runner.runner.run(t, files, f)
+ })
+ }
+}
func TestMain(m *testing.M) {
flag.Parse()
if os.Getenv("_GOPLS_TEST_BINARY_RUN_AS_GOPLS") == "true" {
diff --git a/gopls/internal/regtest/runner.go b/gopls/internal/regtest/runner.go
index 627a6fc..d168d18 100644
--- a/gopls/internal/regtest/runner.go
+++ b/gopls/internal/regtest/runner.go
@@ -72,14 +72,13 @@
}
type runConfig struct {
- editor fake.EditorConfig
- sandbox fake.SandboxConfig
- modes Mode
- timeout time.Duration
- debugAddr string
- skipLogs bool
- skipHooks bool
- nestWorkdir bool
+ editor fake.EditorConfig
+ sandbox fake.SandboxConfig
+ modes Mode
+ timeout time.Duration
+ debugAddr string
+ skipLogs bool
+ skipHooks bool
}
func (r *Runner) defaultConfig() *runConfig {
@@ -134,22 +133,17 @@
opts.editor = fake.EditorConfig(c)
}
-// WithoutWorkspaceFolders prevents workspace folders from being sent as part
-// of the sandbox's initialization. It is used to simulate opening a single
-// file in the editor, without a workspace root. In that case, the client sends
-// neither workspace folders nor a root URI.
-func WithoutWorkspaceFolders() RunOption {
+// WorkspaceFolders configures the workdir-relative workspace folders to send
+// to the LSP server. By default the editor sends a single workspace folder
+// corresponding to the workdir root. To explicitly configure no workspace
+// folders, use WorkspaceFolders with no arguments.
+func WorkspaceFolders(relFolders ...string) RunOption {
+ if len(relFolders) == 0 {
+ // Use an empty non-nil slice to signal explicitly no folders.
+ relFolders = []string{}
+ }
return optionSetter(func(opts *runConfig) {
- opts.editor.WithoutWorkspaceFolders = true
- })
-}
-
-// RootPath specifies the rootURI of the workspace folder opened in the
-// editor. By default, the sandbox opens the top-level directory, but some
-// tests need to check other cases.
-func RootPath(path string) RunOption {
- return optionSetter(func(opts *runConfig) {
- opts.editor.WorkspaceRoot = path
+ opts.editor.WorkspaceFolders = relFolders
})
}
@@ -212,14 +206,6 @@
})
}
-// NestWorkdir inserts the sandbox working directory in a subdirectory of the
-// editor workspace.
-func NestWorkdir() RunOption {
- return optionSetter(func(opts *runConfig) {
- opts.nestWorkdir = true
- })
-}
-
type TestFunc func(t *testing.T, env *Env)
// Run executes the test function in the default configured gopls execution
@@ -271,21 +257,12 @@
if err := os.MkdirAll(rootDir, 0755); err != nil {
t.Fatal(err)
}
- if config.nestWorkdir {
- config.sandbox.Workdir = "work/nested"
- }
config.sandbox.Files = files
config.sandbox.RootDir = rootDir
sandbox, err := fake.NewSandbox(&config.sandbox)
if err != nil {
t.Fatal(err)
}
- workdir := sandbox.Workdir.RootURI().SpanURI().Filename()
- if config.nestWorkdir {
- // Now that we know the actual workdir, set our workspace to be the
- // parent directory.
- config.editor.WorkspaceRoot = filepath.Clean(filepath.Join(workdir, ".."))
- }
// Deferring the closure of ws until the end of the entire test suite
// has, in testing, given the LSP server time to properly shutdown and
// release any file locks held in workspace, which is a problem on
@@ -331,6 +308,7 @@
"netbsd-arm-bsiegert": "",
"solaris-amd64-oraclerel": "",
"windows-arm-zx2c4": "",
+ "android-amd64-emu": "golang.org/issue/43554",
}
func checkBuilder(t *testing.T) {
diff --git a/gopls/internal/regtest/vendor_test.go b/gopls/internal/regtest/vendor_test.go
index ec79e25..f9d43ee 100644
--- a/gopls/internal/regtest/vendor_test.go
+++ b/gopls/internal/regtest/vendor_test.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 regtest
import (
diff --git a/gopls/internal/regtest/watch_test.go b/gopls/internal/regtest/watch_test.go
index 3bd5694..3802765 100644
--- a/gopls/internal/regtest/watch_test.go
+++ b/gopls/internal/regtest/watch_test.go
@@ -414,9 +414,9 @@
})
t.Run("delete then close", func(t *testing.T) {
- withOptions(EditorConfig{
- VerboseOutput: true,
- }).run(t, pkg, func(t *testing.T, env *Env) {
+ withOptions(
+ EditorConfig{VerboseOutput: true},
+ ).run(t, pkg, func(t *testing.T, env *Env) {
env.OpenFile("a/a.go")
env.OpenFile("a/a_unneeded.go")
env.Await(
diff --git a/gopls/internal/regtest/workspace_test.go b/gopls/internal/regtest/workspace_test.go
index 5472176..7e74b53 100644
--- a/gopls/internal/regtest/workspace_test.go
+++ b/gopls/internal/regtest/workspace_test.go
@@ -115,7 +115,7 @@
t.Run(tt.name, func(t *testing.T) {
opts := []RunOption{ProxyFiles(workspaceProxy)}
if tt.rootPath != "" {
- opts = append(opts, RootPath(tt.rootPath))
+ opts = append(opts, WorkspaceFolders(tt.rootPath))
}
withOptions(opts...).run(t, workspaceModule, func(t *testing.T, env *Env) {
f := "pkg/inner/inner.go"
@@ -135,7 +135,10 @@
// VS Code, where clicking on a reference result triggers a
// textDocument/didOpen without a corresponding textDocument/didClose.
func TestClearAnalysisDiagnostics(t *testing.T) {
- withOptions(ProxyFiles(workspaceProxy), RootPath("pkg/inner")).run(t, workspaceModule, func(t *testing.T, env *Env) {
+ withOptions(
+ ProxyFiles(workspaceProxy),
+ WorkspaceFolders("pkg/inner"),
+ ).run(t, workspaceModule, func(t *testing.T, env *Env) {
env.OpenFile("pkg/main.go")
env.Await(
env.DiagnosticAtRegexp("pkg/main2.go", "fmt.Print"),
@@ -150,7 +153,10 @@
// This test checks that gopls updates the set of files it watches when a
// replace target is added to the go.mod.
func TestWatchReplaceTargets(t *testing.T) {
- withOptions(ProxyFiles(workspaceProxy), RootPath("pkg")).run(t, workspaceModule, func(t *testing.T, env *Env) {
+ withOptions(
+ ProxyFiles(workspaceProxy),
+ WorkspaceFolders("pkg"),
+ ).run(t, workspaceModule, func(t *testing.T, env *Env) {
// Add a replace directive and expect the files that gopls is watching
// to change.
dir := env.Sandbox.Workdir.URI("goodbye").SpanURI().Filename()
diff --git a/gopls/internal/regtest/wrappers.go b/gopls/internal/regtest/wrappers.go
index 849a1a6..cdc3090 100644
--- a/gopls/internal/regtest/wrappers.go
+++ b/gopls/internal/regtest/wrappers.go
@@ -250,11 +250,21 @@
// RunGoCommand runs the given command in the sandbox's default working
// directory.
func (e *Env) RunGoCommand(verb string, args ...string) {
+ e.T.Helper()
if err := e.Sandbox.RunGoCommand(e.Ctx, "", verb, args); err != nil {
e.T.Fatal(err)
}
}
+// RunGoCommandInDir is like RunGoCommand, but executes in the given
+// relative directory of the sandbox.
+func (e *Env) RunGoCommandInDir(dir, verb string, args ...string) {
+ e.T.Helper()
+ if err := e.Sandbox.RunGoCommand(e.Ctx, dir, verb, args); err != nil {
+ e.T.Fatal(err)
+ }
+}
+
func (e *Env) DumpGoSum(dir string) {
e.T.Helper()
diff --git a/gopls/main.go b/gopls/main.go
index 0de6531..2e099e7 100644
--- a/gopls/main.go
+++ b/gopls/main.go
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The gopls command is an LSP server for Go.
+// Gopls (pronounced “go please”) is an LSP server for Go.
// The Language Server Protocol allows any text editor
// to be extended with IDE-like features;
// see https://langserver.org/ for details.
//
-// See https://github.com/golang/tools/tree/master/gopls
-// for the most up-to-date information on the gopls status.
+// See https://github.com/golang/tools/blob/master/gopls/README.md
+// for the most up-to-date documentation.
package main // import "golang.org/x/tools/gopls"
import (
diff --git a/gopls/test/debug/debug_test.go b/gopls/test/debug/debug_test.go
index 72aaff4..1b51073 100644
--- a/gopls/test/debug/debug_test.go
+++ b/gopls/test/debug/debug_test.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 debug_test
// Provide 'static type checking' of the templates. This guards against changes is various
diff --git a/imports/forward.go b/imports/forward.go
index a4e40ad..8be18a6 100644
--- a/imports/forward.go
+++ b/imports/forward.go
@@ -1,3 +1,7 @@
+// 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 imports implements a Go pretty-printer (like package "go/format")
// that also adds or removes import statements as necessary.
package imports // import "golang.org/x/tools/imports"
diff --git a/internal/apidiff/apidiff.go b/internal/apidiff/apidiff.go
index 76669d8..873ee85 100644
--- a/internal/apidiff/apidiff.go
+++ b/internal/apidiff/apidiff.go
@@ -1,3 +1,7 @@
+// 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.
+
// TODO: test swap corresponding types (e.g. u1 <-> u2 and u2 <-> u1)
// TODO: test exported alias refers to something in another package -- does correspondence work then?
// TODO: CODE COVERAGE
diff --git a/internal/apidiff/apidiff_test.go b/internal/apidiff/apidiff_test.go
index 7910096..b385b7c 100644
--- a/internal/apidiff/apidiff_test.go
+++ b/internal/apidiff/apidiff_test.go
@@ -1,3 +1,7 @@
+// 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 apidiff
import (
diff --git a/internal/apidiff/compatibility.go b/internal/apidiff/compatibility.go
index f78da8f..6b5ba75 100644
--- a/internal/apidiff/compatibility.go
+++ b/internal/apidiff/compatibility.go
@@ -1,3 +1,7 @@
+// 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 apidiff
import (
diff --git a/internal/apidiff/correspondence.go b/internal/apidiff/correspondence.go
index bd14c09..0d7b4c5 100644
--- a/internal/apidiff/correspondence.go
+++ b/internal/apidiff/correspondence.go
@@ -1,3 +1,7 @@
+// 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 apidiff
import (
diff --git a/internal/apidiff/messageset.go b/internal/apidiff/messageset.go
index 1354790..895e5f8 100644
--- a/internal/apidiff/messageset.go
+++ b/internal/apidiff/messageset.go
@@ -1,3 +1,7 @@
+// 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.
+
// TODO: show that two-non-empty dotjoin can happen, by using an anon struct as a field type
// TODO: don't report removed/changed methods for both value and pointer method sets?
diff --git a/internal/apidiff/report.go b/internal/apidiff/report.go
index ce79e27..c3f08a9 100644
--- a/internal/apidiff/report.go
+++ b/internal/apidiff/report.go
@@ -1,3 +1,7 @@
+// 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 apidiff
import (
diff --git a/internal/event/bench_test.go b/internal/event/bench_test.go
index 138b236..9ec7519 100644
--- a/internal/event/bench_test.go
+++ b/internal/event/bench_test.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 event_test
import (
diff --git a/internal/event/export/ocagent/metrics_test.go b/internal/event/export/ocagent/metrics_test.go
index 2ffdf74..001e7f0 100644
--- a/internal/event/export/ocagent/metrics_test.go
+++ b/internal/event/export/ocagent/metrics_test.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 ocagent_test
import (
diff --git a/internal/event/export/ocagent/wire/metrics_test.go b/internal/event/export/ocagent/wire/metrics_test.go
index fe2497d..34247ad 100644
--- a/internal/event/export/ocagent/wire/metrics_test.go
+++ b/internal/event/export/ocagent/wire/metrics_test.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 wire
import (
diff --git a/internal/gocommand/version.go b/internal/gocommand/version.go
index 60d45ac..0cebac6 100644
--- a/internal/gocommand/version.go
+++ b/internal/gocommand/version.go
@@ -16,9 +16,20 @@
inv.Verb = "list"
inv.Args = []string{"-e", "-f", `{{context.ReleaseTags}}`}
inv.Env = append(append([]string{}, inv.Env...), "GO111MODULE=off")
- // Unset any unneeded flags.
+ // Unset any unneeded flags, and remove them from BuildFlags, if they're
+ // present.
inv.ModFile = ""
inv.ModFlag = ""
+ var buildFlags []string
+ for _, flag := range inv.BuildFlags {
+ // Flags can be prefixed by one or two dashes.
+ f := strings.TrimPrefix(strings.TrimPrefix(flag, "-"), "-")
+ if strings.HasPrefix(f, "mod=") || strings.HasPrefix(f, "modfile=") {
+ continue
+ }
+ buildFlags = append(buildFlags, flag)
+ }
+ inv.BuildFlags = buildFlags
stdoutBytes, err := r.Run(ctx, inv)
if err != nil {
return 0, err
diff --git a/internal/imports/imports_test.go b/internal/imports/imports_test.go
index 6405ab5..198b940 100644
--- a/internal/imports/imports_test.go
+++ b/internal/imports/imports_test.go
@@ -1,3 +1,7 @@
+// 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 imports
import (
diff --git a/internal/imports/mkstdlib.go b/internal/imports/mkstdlib.go
index 85fbc28..82d8f51 100644
--- a/internal/imports/mkstdlib.go
+++ b/internal/imports/mkstdlib.go
@@ -1,3 +1,7 @@
+// 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.
+
// +build ignore
// mkstdlib generates the zstdlib.go file, containing the Go standard
diff --git a/internal/imports/mod.go b/internal/imports/mod.go
index ce3269a..65e0b94 100644
--- a/internal/imports/mod.go
+++ b/internal/imports/mod.go
@@ -1,3 +1,7 @@
+// 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 imports
import (
@@ -82,7 +86,12 @@
r.modsByDir = []*gocommand.ModuleJSON{mainMod, r.dummyVendorMod}
} else {
// Vendor mode is off, so run go list -m ... to find everything.
- r.initAllMods()
+ err := r.initAllMods()
+ // We expect an error when running outside of a module with
+ // GO111MODULE=on. Other errors are fatal.
+ if err != nil && !strings.Contains(err.Error(), "working directory is not part of a module") {
+ return err
+ }
}
if gmc := r.env.Env["GOMODCACHE"]; gmc != "" {
@@ -157,7 +166,7 @@
}
func (r *ModuleResolver) initAllMods() error {
- stdout, err := r.env.invokeGo(context.TODO(), "list", "-m", "-json", "...")
+ stdout, err := r.env.invokeGo(context.TODO(), "list", "-m", "-e", "-json", "...")
if err != nil {
return err
}
diff --git a/internal/imports/mod_cache.go b/internal/imports/mod_cache.go
index 5b4f03a..18dada4 100644
--- a/internal/imports/mod_cache.go
+++ b/internal/imports/mod_cache.go
@@ -1,3 +1,7 @@
+// 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 imports
import (
diff --git a/internal/imports/mod_cache_test.go b/internal/imports/mod_cache_test.go
index e7d3c73..39c691e 100644
--- a/internal/imports/mod_cache_test.go
+++ b/internal/imports/mod_cache_test.go
@@ -1,3 +1,7 @@
+// 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 imports
import (
diff --git a/internal/imports/mod_test.go b/internal/imports/mod_test.go
index c6bbe56..91863ef 100644
--- a/internal/imports/mod_test.go
+++ b/internal/imports/mod_test.go
@@ -1,3 +1,7 @@
+// 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 imports
import (
diff --git a/internal/lsp/cache/cache.go b/internal/lsp/cache/cache.go
index 6d40ecb..fa1b530 100644
--- a/internal/lsp/cache/cache.go
+++ b/internal/lsp/cache/cache.go
@@ -57,6 +57,12 @@
bytes []byte
hash string
err error
+
+ // size is the file length as reported by Stat, for the purpose of
+ // invalidation. Probably we could just use len(bytes), but this is done
+ // defensively in case the definition of file size in the file system
+ // differs.
+ size int64
}
func (h *fileHandle) Saved() bool {
@@ -79,11 +85,23 @@
c.fileMu.Lock()
fh, ok := c.fileContent[uri]
c.fileMu.Unlock()
- if ok && fh.modTime.Equal(fi.ModTime()) {
+
+ // Check mtime and file size to infer whether the file has changed. This is
+ // an imperfect heuristic. Notably on some real systems (such as WSL) the
+ // filesystem clock resolution can be large -- 1/64s was observed. Therefore
+ // it's quite possible for multiple file modifications to occur within a
+ // single logical 'tick'. This can leave the cache in an incorrect state, but
+ // unfortunately we can't afford to pay the price of reading the actual file
+ // content here. Or to be more precise, reading would be a risky change and
+ // we don't know if we can afford it.
+ //
+ // We check file size in an attempt to reduce the probability of false cache
+ // hits.
+ if ok && fh.modTime.Equal(fi.ModTime()) && fh.size == fi.Size() {
return fh, nil
}
- fh, err := readFile(ctx, uri, fi.ModTime())
+ fh, err := readFile(ctx, uri, fi)
if err != nil {
return nil, err
}
@@ -96,7 +114,7 @@
// ioLimit limits the number of parallel file reads per process.
var ioLimit = make(chan struct{}, 128)
-func readFile(ctx context.Context, uri span.URI, modTime time.Time) (*fileHandle, error) {
+func readFile(ctx context.Context, uri span.URI, fi os.FileInfo) (*fileHandle, error) {
select {
case ioLimit <- struct{}{}:
case <-ctx.Done():
@@ -111,12 +129,14 @@
data, err := ioutil.ReadFile(uri.Filename())
if err != nil {
return &fileHandle{
- modTime: modTime,
+ modTime: fi.ModTime(),
+ size: fi.Size(),
err: err,
}, nil
}
return &fileHandle{
- modTime: modTime,
+ modTime: fi.ModTime(),
+ size: fi.Size(),
uri: uri,
bytes: data,
hash: hashContents(data),
diff --git a/internal/lsp/cache/imports.go b/internal/lsp/cache/imports.go
index cbad73e..ed9919f 100644
--- a/internal/lsp/cache/imports.go
+++ b/internal/lsp/cache/imports.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 (
@@ -74,7 +78,9 @@
// unnecessary work and potentially mess up the go.mod file.
if s.cleanupProcessEnv != nil {
if resolver, err := s.processEnv.GetResolver(); err == nil {
- resolver.(*imports.ModuleResolver).ClearForNewMod()
+ if modResolver, ok := resolver.(*imports.ModuleResolver); ok {
+ modResolver.ClearForNewMod()
+ }
}
s.cleanupProcessEnv()
}
diff --git a/internal/lsp/cache/load.go b/internal/lsp/cache/load.go
index d73a0d5..fb328b8 100644
--- a/internal/lsp/cache/load.go
+++ b/internal/lsp/cache/load.go
@@ -220,23 +220,24 @@
for uri := range s.workspace.getActiveModFiles() {
rootModURI = uri
}
- nestedModules := map[span.URI][]source.VersionedFileHandle{}
+ nestedModules := map[string][]source.VersionedFileHandle{}
for _, fh := range openFiles {
modURI := moduleForURI(s.workspace.knownModFiles, fh.URI())
if modURI != rootModURI {
- nestedModules[modURI] = append(nestedModules[modURI], fh)
+ modDir := filepath.Dir(modURI.Filename())
+ nestedModules[modDir] = append(nestedModules[modDir], fh)
}
}
// Add a diagnostic to each file in a nested module to mark it as
// "orphaned". Don't show a general diagnostic in the progress bar,
// because the user may still want to edit a file in a nested module.
var srcErrs []*source.Error
- for modURI, uris := range nestedModules {
+ for modDir, uris := range nestedModules {
msg := fmt.Sprintf(`This file is in %s, which is a nested module in the %s module.
gopls currently requires one module per workspace folder.
Please open %s as a separate workspace folder.
You can learn more here: https://github.com/golang/go/issues/36899.
-`, modURI.Filename(), rootModURI.Filename(), modURI.Filename())
+`, modDir, filepath.Dir(rootModURI.Filename()), modDir)
srcErrs = append(srcErrs, s.applyCriticalErrorToFiles(ctx, msg, uris)...)
}
if len(srcErrs) != 0 {
diff --git a/internal/lsp/cache/workspace_test.go b/internal/lsp/cache/workspace_test.go
index 910e705..fd9cb8d 100644
--- a/internal/lsp/cache/workspace_test.go
+++ b/internal/lsp/cache/workspace_test.go
@@ -81,7 +81,7 @@
uri: uri,
}, nil
}
- fh, err := readFile(ctx, uri, fi.ModTime())
+ fh, err := readFile(ctx, uri, fi)
if err != nil {
return nil, err
}
diff --git a/internal/lsp/cmd/capabilities_test.go b/internal/lsp/cmd/capabilities_test.go
index 66c7eb3..ea0bfed 100644
--- a/internal/lsp/cmd/capabilities_test.go
+++ b/internal/lsp/cmd/capabilities_test.go
@@ -1,3 +1,7 @@
+// 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 cmd
import (
diff --git a/internal/lsp/cmd/cmd.go b/internal/lsp/cmd/cmd.go
index 5f669f3..fd9d6f9 100644
--- a/internal/lsp/cmd/cmd.go
+++ b/internal/lsp/cmd/cmd.go
@@ -171,6 +171,7 @@
&version{app: app},
&bug{},
&apiJSON{},
+ &licenses{app: app},
}
}
diff --git a/internal/lsp/cmd/info.go b/internal/lsp/cmd/info.go
index f71f5db..fd53d8a 100644
--- a/internal/lsp/cmd/info.go
+++ b/internal/lsp/cmd/info.go
@@ -86,15 +86,15 @@
type apiJSON struct{}
-func (sj *apiJSON) Name() string { return "api-json" }
-func (sj *apiJSON) Usage() string { return "" }
-func (sj *apiJSON) ShortHelp() string { return "print json describing gopls API" }
-func (sj *apiJSON) DetailedHelp(f *flag.FlagSet) {
+func (j *apiJSON) Name() string { return "api-json" }
+func (j *apiJSON) Usage() string { return "" }
+func (j *apiJSON) ShortHelp() string { return "print json describing gopls API" }
+func (j *apiJSON) DetailedHelp(f *flag.FlagSet) {
fmt.Fprint(f.Output(), ``)
f.PrintDefaults()
}
-func (sj *apiJSON) Run(ctx context.Context, args ...string) error {
+func (j *apiJSON) Run(ctx context.Context, args ...string) error {
js, err := json.MarshalIndent(source.GeneratedAPIJSON, "", "\t")
if err != nil {
return err
@@ -102,3 +102,82 @@
fmt.Fprint(os.Stdout, string(js))
return nil
}
+
+type licenses struct {
+ app *Application
+}
+
+func (l *licenses) Name() string { return "licenses" }
+func (l *licenses) Usage() string { return "" }
+func (l *licenses) ShortHelp() string { return "print licenses of included software" }
+func (l *licenses) DetailedHelp(f *flag.FlagSet) {
+ fmt.Fprint(f.Output(), ``)
+ f.PrintDefaults()
+}
+
+const licensePreamble = `
+gopls is made available under the following BSD-style license:
+
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+gopls implements the LSP specification, which is made available under the following license:
+
+Copyright (c) Microsoft Corporation
+
+All rights reserved.
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
+OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+gopls also includes software made available under these licenses:
+`
+
+func (l *licenses) Run(ctx context.Context, args ...string) error {
+ opts := source.DefaultOptions()
+ l.app.options(opts)
+ txt := licensePreamble
+ if opts.LicensesText == "" {
+ txt += "(development gopls, license information not available)"
+ } else {
+ txt += opts.LicensesText
+ }
+ fmt.Fprintf(os.Stdout, txt)
+ return nil
+}
diff --git a/internal/lsp/cmd/test/folding_range.go b/internal/lsp/cmd/test/folding_range.go
index 6edb58e..4478687 100644
--- a/internal/lsp/cmd/test/folding_range.go
+++ b/internal/lsp/cmd/test/folding_range.go
@@ -1,3 +1,7 @@
+// 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 cmdtest
import (
diff --git a/internal/lsp/cmd/test/highlight.go b/internal/lsp/cmd/test/highlight.go
index c4efa0f..99e8b2c 100644
--- a/internal/lsp/cmd/test/highlight.go
+++ b/internal/lsp/cmd/test/highlight.go
@@ -1,3 +1,7 @@
+// 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 cmdtest
import (
diff --git a/internal/lsp/completion_test.go b/internal/lsp/completion_test.go
index 55e4e8f..53d136f 100644
--- a/internal/lsp/completion_test.go
+++ b/internal/lsp/completion_test.go
@@ -1,3 +1,7 @@
+// 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 lsp
import (
diff --git a/internal/lsp/debug/info.go b/internal/lsp/debug/info.go
index ca85b3d..ebcb66b 100644
--- a/internal/lsp/debug/info.go
+++ b/internal/lsp/debug/info.go
@@ -26,7 +26,7 @@
)
// Version is a manually-updated mechanism for tracking versions.
-var Version = "v0.6.2"
+const Version = "v0.6.2"
// ServerVersion is the format used by gopls to report its version to the
// client. This format is structured so that the client can parse it easily.
diff --git a/internal/lsp/diff/diff_test.go b/internal/lsp/diff/diff_test.go
index 8c93c10..dd9414e 100644
--- a/internal/lsp/diff/diff_test.go
+++ b/internal/lsp/diff/diff_test.go
@@ -1,3 +1,7 @@
+// 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 diff_test
import (
diff --git a/internal/lsp/fake/editor.go b/internal/lsp/fake/editor.go
index 3ce4782..a5fbf2b 100644
--- a/internal/lsp/fake/editor.go
+++ b/internal/lsp/fake/editor.go
@@ -76,14 +76,13 @@
// workspace scope to the entire module.
LimitWorkspaceScope bool
- // WithoutWorkspaceFolders is used to simulate opening a single file in the
- // editor, without a workspace root. In that case, the client sends neither
- // workspace folders nor a root URI.
- WithoutWorkspaceFolders bool
-
- // WorkspaceRoot specifies the root path of the workspace folder used when
- // initializing gopls in the sandbox. If empty, the Workdir is used.
- WorkspaceRoot string
+ // WorkspaceFolders is the workspace folders to configure on the LSP server,
+ // relative to the sandbox workdir.
+ //
+ // As a special case, if WorkspaceFolders is nil the editor defaults to
+ // configuring a single workspace folder corresponding to the workdir root.
+ // To explicitly send no workspace folders, use an empty (non-nil) slice.
+ WorkspaceFolders []string
// EnableStaticcheck enables staticcheck analyzers.
EnableStaticcheck bool
@@ -125,7 +124,7 @@
protocol.Handlers(
protocol.ClientHandler(e.client,
jsonrpc2.MethodNotFound)))
- if err := e.initialize(ctx, e.Config.WithoutWorkspaceFolders, e.Config.WorkspaceRoot); err != nil {
+ if err := e.initialize(ctx, e.Config.WorkspaceFolders); err != nil {
return nil, err
}
e.sandbox.Workdir.AddWatcher(e.onFileChanges)
@@ -230,20 +229,21 @@
return config
}
-func (e *Editor) initialize(ctx context.Context, withoutWorkspaceFolders bool, editorRootPath string) error {
+func (e *Editor) initialize(ctx context.Context, workspaceFolders []string) error {
params := &protocol.ParamInitialize{}
params.ClientInfo.Name = "fakeclient"
params.ClientInfo.Version = "v1.0.0"
- if !withoutWorkspaceFolders {
- rootURI := e.sandbox.Workdir.RootURI()
- if editorRootPath != "" {
- rootURI = toURI(e.sandbox.Workdir.AbsPath(editorRootPath))
- }
- params.WorkspaceFolders = []protocol.WorkspaceFolder{{
- URI: string(rootURI),
- Name: filepath.Base(rootURI.SpanURI().Filename()),
- }}
+
+ if workspaceFolders == nil {
+ workspaceFolders = []string{string(e.sandbox.Workdir.RelativeTo)}
}
+ for _, folder := range workspaceFolders {
+ params.WorkspaceFolders = append(params.WorkspaceFolders, protocol.WorkspaceFolder{
+ URI: string(e.sandbox.Workdir.URI(folder)),
+ Name: filepath.Base(folder),
+ })
+ }
+
params.Capabilities.Workspace.Configuration = true
params.Capabilities.Window.WorkDoneProgress = true
// TODO: set client capabilities
diff --git a/internal/lsp/fake/sandbox.go b/internal/lsp/fake/sandbox.go
index ac15523..7d81790 100644
--- a/internal/lsp/fake/sandbox.go
+++ b/internal/lsp/fake/sandbox.go
@@ -146,8 +146,11 @@
if err != nil {
return "", err
}
- if err := writeTxtar(txt, RelativeTo(dir)); err != nil {
- return "", err
+ files := unpackTxt(txt)
+ for name, data := range files {
+ if err := WriteFileData(name, data, RelativeTo(dir)); err != nil {
+ return "", errors.Errorf("writing to tempdir: %w", err)
+ }
}
return dir, nil
}
diff --git a/internal/lsp/fake/workdir.go b/internal/lsp/fake/workdir.go
index 84fa9a5..3cc6f73 100644
--- a/internal/lsp/fake/workdir.go
+++ b/internal/lsp/fake/workdir.go
@@ -7,12 +7,13 @@
import (
"bytes"
"context"
+ "crypto/sha256"
+ "fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
- "time"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/span"
@@ -82,7 +83,7 @@
watchers []func(context.Context, []FileEvent)
fileMu sync.Mutex
- files map[string]time.Time
+ files map[string]string
}
// NewWorkdir writes the txtar-encoded file data in txt to dir, and returns a
@@ -91,11 +92,18 @@
return &Workdir{RelativeTo: RelativeTo(dir)}
}
+func hashFile(data []byte) string {
+ return fmt.Sprintf("%x", sha256.Sum256(data))
+}
+
func (w *Workdir) writeInitialFiles(txt string) error {
- writeTxtar(txt, w.RelativeTo)
- // Poll to capture the current file state.
- if _, err := w.pollFiles(); err != nil {
- return errors.Errorf("polling files: %w", err)
+ files := unpackTxt(txt)
+ w.files = map[string]string{}
+ for name, data := range files {
+ w.files[name] = hashFile(data)
+ if err := WriteFileData(name, data, w.RelativeTo); err != nil {
+ return errors.Errorf("writing to workdir: %w", err)
+ }
}
return nil
}
@@ -256,10 +264,10 @@
}, nil
}
-// ListFiles lists files in the given directory, returning a map of relative
+// listFiles lists files in the given directory, returning a map of relative
// path to modification time.
-func (w *Workdir) ListFiles(dir string) (map[string]time.Time, error) {
- files := make(map[string]time.Time)
+func (w *Workdir) listFiles(dir string) (map[string]string, error) {
+ files := make(map[string]string)
absDir := w.AbsPath(dir)
if err := filepath.Walk(absDir, func(fp string, info os.FileInfo, err error) error {
if err != nil {
@@ -269,7 +277,11 @@
return nil
}
path := w.RelPath(fp)
- files[path] = info.ModTime()
+ data, err := ioutil.ReadFile(fp)
+ if err != nil {
+ return err
+ }
+ files[path] = hashFile(data)
return nil
}); err != nil {
return nil, err
@@ -294,20 +306,20 @@
w.fileMu.Lock()
defer w.fileMu.Unlock()
- files, err := w.ListFiles(".")
+ files, err := w.listFiles(".")
if err != nil {
return nil, err
}
var evts []FileEvent
// Check which files have been added or modified.
- for path, mtime := range files {
- oldmtime, ok := w.files[path]
+ for path, hash := range files {
+ oldhash, ok := w.files[path]
delete(w.files, path)
var typ protocol.FileChangeType
switch {
case !ok:
typ = protocol.Created
- case oldmtime != mtime:
+ case oldhash != hash:
typ = protocol.Changed
default:
continue
diff --git a/internal/lsp/fake/workdir_test.go b/internal/lsp/fake/workdir_test.go
index e51f8c0..5c9a36c 100644
--- a/internal/lsp/fake/workdir_test.go
+++ b/internal/lsp/fake/workdir_test.go
@@ -104,7 +104,7 @@
defer cleanup()
checkFiles := func(dir string, want []string) {
- files, err := wd.ListFiles(dir)
+ files, err := wd.listFiles(dir)
if err != nil {
t.Fatal(err)
}
diff --git a/internal/lsp/folding_range.go b/internal/lsp/folding_range.go
index ab91536..75f48a4 100644
--- a/internal/lsp/folding_range.go
+++ b/internal/lsp/folding_range.go
@@ -1,3 +1,7 @@
+// 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 lsp
import (
diff --git a/internal/lsp/helper/helper.go b/internal/lsp/helper/helper.go
index 4d1dc41..59438f1 100644
--- a/internal/lsp/helper/helper.go
+++ b/internal/lsp/helper/helper.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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.
+
// Invoke with //go:generate helper/helper -t Server -d protocol/tsserver.go -u lsp -o server_gen.go
// invoke in internal/lsp
package main
diff --git a/internal/lsp/mod/code_lens.go b/internal/lsp/mod/code_lens.go
index ecd9c65..4465637 100644
--- a/internal/lsp/mod/code_lens.go
+++ b/internal/lsp/mod/code_lens.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 mod
import (
diff --git a/internal/lsp/mod/format.go b/internal/lsp/mod/format.go
index fe22300..c355766 100644
--- a/internal/lsp/mod/format.go
+++ b/internal/lsp/mod/format.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 mod
import (
diff --git a/internal/lsp/mod/hover.go b/internal/lsp/mod/hover.go
index a12b22c..82ba20f 100644
--- a/internal/lsp/mod/hover.go
+++ b/internal/lsp/mod/hover.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 mod
import (
diff --git a/internal/lsp/protocol/context.go b/internal/lsp/protocol/context.go
index 3a5b58c..487e4df 100644
--- a/internal/lsp/protocol/context.go
+++ b/internal/lsp/protocol/context.go
@@ -1,3 +1,7 @@
+// 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 protocol
import (
diff --git a/internal/lsp/protocol/log.go b/internal/lsp/protocol/log.go
index 2c82c64..fdcbb7a 100644
--- a/internal/lsp/protocol/log.go
+++ b/internal/lsp/protocol/log.go
@@ -1,3 +1,7 @@
+// 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 protocol
import (
diff --git a/internal/lsp/server.go b/internal/lsp/server.go
index 0f74ff3..df1da8c 100644
--- a/internal/lsp/server.go
+++ b/internal/lsp/server.go
@@ -115,8 +115,9 @@
}
func (s *Server) nonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) {
- paramMap := params.(map[string]interface{})
- if method == "gopls/diagnoseFiles" {
+ switch method {
+ case "gopls/diagnoseFiles":
+ paramMap := params.(map[string]interface{})
for _, file := range paramMap["files"].([]interface{}) {
snapshot, fh, ok, release, err := s.beginFileRequest(ctx, protocol.DocumentURI(file.(string)), source.UnknownKind)
defer release()
diff --git a/internal/lsp/server_gen.go b/internal/lsp/server_gen.go
index 258e922..275c7c8 100644
--- a/internal/lsp/server_gen.go
+++ b/internal/lsp/server_gen.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 lsp
// code generated by helper. DO NOT EDIT.
diff --git a/internal/lsp/source/call_hierarchy.go b/internal/lsp/source/call_hierarchy.go
index c7dfea5..bebdd4e 100644
--- a/internal/lsp/source/call_hierarchy.go
+++ b/internal/lsp/source/call_hierarchy.go
@@ -247,8 +247,14 @@
// toProtocolOutgoingCalls returns an array of protocol.CallHierarchyOutgoingCall for ast call expressions.
// Calls to the same function are assigned to the same declaration.
func toProtocolOutgoingCalls(ctx context.Context, snapshot Snapshot, fh FileHandle, callRanges []protocol.Range) ([]protocol.CallHierarchyOutgoingCall, error) {
- // multiple calls could be made to the same function
- var outgoingCalls = map[ast.Node]*protocol.CallHierarchyOutgoingCall{}
+ // Multiple calls could be made to the same function, defined by "same declaration
+ // AST node & same idenfitier name" to provide a unique identifier key even when
+ // the func is declared in a struct or interface.
+ type key struct {
+ decl ast.Node
+ name string
+ }
+ outgoingCalls := map[key]*protocol.CallHierarchyOutgoingCall{}
for _, callRange := range callRanges {
identifier, err := Identifier(ctx, snapshot, fh, callRange.Start)
if err != nil {
@@ -263,7 +269,7 @@
continue
}
- if outgoingCall, ok := outgoingCalls[identifier.Declaration.node]; ok {
+ if outgoingCall, ok := outgoingCalls[key{identifier.Declaration.node, identifier.Name}]; ok {
outgoingCall.FromRanges = append(outgoingCall.FromRanges, callRange)
continue
}
@@ -277,7 +283,7 @@
return nil, err
}
- outgoingCalls[identifier.Declaration.node] = &protocol.CallHierarchyOutgoingCall{
+ outgoingCalls[key{identifier.Declaration.node, identifier.Name}] = &protocol.CallHierarchyOutgoingCall{
To: protocol.CallHierarchyItem{
Name: identifier.Name,
Kind: protocol.Function,
diff --git a/internal/lsp/source/comment.go b/internal/lsp/source/comment.go
index 4b86245..1ad3aa5 100644
--- a/internal/lsp/source/comment.go
+++ b/internal/lsp/source/comment.go
@@ -1,3 +1,7 @@
+// 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 source
import (
diff --git a/internal/lsp/source/comment_test.go b/internal/lsp/source/comment_test.go
index cc37464..f183422 100644
--- a/internal/lsp/source/comment_test.go
+++ b/internal/lsp/source/comment_test.go
@@ -1,3 +1,7 @@
+// 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 source
import (
diff --git a/internal/lsp/source/folding_range.go b/internal/lsp/source/folding_range.go
index 7061017..05b1d60 100644
--- a/internal/lsp/source/folding_range.go
+++ b/internal/lsp/source/folding_range.go
@@ -1,3 +1,7 @@
+// 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 source
import (
diff --git a/internal/lsp/source/format_test.go b/internal/lsp/source/format_test.go
index 52f8aae..5d93a4e 100644
--- a/internal/lsp/source/format_test.go
+++ b/internal/lsp/source/format_test.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 source
import (
diff --git a/internal/lsp/source/options.go b/internal/lsp/source/options.go
index 4e20893..bb42868 100644
--- a/internal/lsp/source/options.go
+++ b/internal/lsp/source/options.go
@@ -410,6 +410,7 @@
// Hooks contains configuration that is provided to the Gopls command by the
// main package.
type Hooks struct {
+ LicensesText string
GoDiff bool
ComputeEdits diff.ComputeEdits
URLRegexp *regexp.Regexp
diff --git a/internal/lsp/source/references.go b/internal/lsp/source/references.go
index 4cbb845..08ce807 100644
--- a/internal/lsp/source/references.go
+++ b/internal/lsp/source/references.go
@@ -42,7 +42,7 @@
return nil, err
}
- refs, err := references(ctx, s, qualifiedObjs, includeDeclaration, true)
+ refs, err := references(ctx, s, qualifiedObjs, includeDeclaration, true, false)
if err != nil {
return nil, err
}
@@ -62,10 +62,10 @@
}
// references is a helper function to avoid recomputing qualifiedObjsAtProtocolPos.
-func references(ctx context.Context, snapshot Snapshot, qos []qualifiedObject, includeDeclaration, includeInterfaceRefs bool) ([]*ReferenceInfo, error) {
+func references(ctx context.Context, snapshot Snapshot, qos []qualifiedObject, includeDeclaration, includeInterfaceRefs, includeEmbeddedRefs bool) ([]*ReferenceInfo, error) {
var (
references []*ReferenceInfo
- seen = make(map[token.Position]bool)
+ seen = make(map[token.Pos]bool)
)
filename := snapshot.FileSet().Position(qos[0].obj.Pos()).Filename
@@ -105,13 +105,25 @@
for _, pkg := range searchPkgs {
for ident, obj := range pkg.GetTypesInfo().Uses {
if obj != qo.obj {
+ // If ident is not a use of qo.obj, skip it, with one exception: uses
+ // of an embedded field can be considered references of the embedded
+ // type name.
+ if !includeEmbeddedRefs {
+ continue
+ }
+ v, ok := obj.(*types.Var)
+ if !ok || !v.Embedded() {
+ continue
+ }
+ named, ok := v.Type().(*types.Named)
+ if !ok || named.Obj() != qo.obj {
+ continue
+ }
+ }
+ if seen[ident.Pos()] {
continue
}
- pos := snapshot.FileSet().Position(ident.Pos())
- if seen[pos] {
- continue
- }
- seen[pos] = true
+ seen[ident.Pos()] = true
rng, err := posToMappedRange(snapshot, pkg, ident.Pos(), ident.End())
if err != nil {
return nil, err
@@ -150,7 +162,7 @@
return references, nil
}
-// interfaceReferences returns the references to the interfaces implemeneted by
+// interfaceReferences returns the references to the interfaces implemented by
// the type or method at the given position.
func interfaceReferences(ctx context.Context, s Snapshot, f FileHandle, pp protocol.Position) ([]*ReferenceInfo, error) {
implementations, err := implementations(ctx, s, f, pp)
@@ -163,7 +175,7 @@
var refs []*ReferenceInfo
for _, impl := range implementations {
- implRefs, err := references(ctx, s, []qualifiedObject{impl}, false, false)
+ implRefs, err := references(ctx, s, []qualifiedObject{impl}, false, false, false)
if err != nil {
return nil, err
}
diff --git a/internal/lsp/source/rename.go b/internal/lsp/source/rename.go
index 26c705a..fdf3f63 100644
--- a/internal/lsp/source/rename.go
+++ b/internal/lsp/source/rename.go
@@ -91,7 +91,7 @@
if pkg == nil || pkg.IsIllTyped() {
return nil, errors.Errorf("package for %s is ill typed", f.URI())
}
- refs, err := references(ctx, s, qos, true, false)
+ refs, err := references(ctx, s, qos, true, false, true)
if err != nil {
return nil, err
}
diff --git a/internal/lsp/testdata/callhierarchy/callhierarchy.go b/internal/lsp/testdata/callhierarchy/callhierarchy.go
index 4f45a28..410e18c 100644
--- a/internal/lsp/testdata/callhierarchy/callhierarchy.go
+++ b/internal/lsp/testdata/callhierarchy/callhierarchy.go
@@ -26,7 +26,7 @@
}
// D is exported to test incoming/outgoing calls across packages
-func D() { //@mark(hierarchyD, "D"),incomingcalls(hierarchyD, hierarchyA, hierarchyB, hierarchyC, hierarchyLiteral, incomingA),outgoingcalls(hierarchyD, hierarchyE, hierarchyF, hierarchyG, hierarchyLiteralOut, outgoingB, hierarchyFoo)
+func D() { //@mark(hierarchyD, "D"),incomingcalls(hierarchyD, hierarchyA, hierarchyB, hierarchyC, hierarchyLiteral, incomingA),outgoingcalls(hierarchyD, hierarchyE, hierarchyF, hierarchyG, hierarchyLiteralOut, outgoingB, hierarchyFoo, hierarchyH, hierarchyI, hierarchyJ, hierarchyK)
e()
x()
F()
@@ -34,6 +34,14 @@
outgoing.B()
foo := func() {} //@mark(hierarchyFoo, "foo"),incomingcalls(hierarchyFoo, hierarchyD),outgoingcalls(hierarchyFoo)
foo()
+
+ var i Interface = impl{}
+ i.H()
+ i.I()
+
+ s := Struct{}
+ s.J()
+ s.K()
}
func e() {} //@mark(hierarchyE, "e")
@@ -42,3 +50,18 @@
func F() {} //@mark(hierarchyF, "F")
func g() {} //@mark(hierarchyG, "g")
+
+type Interface interface {
+ H() //@mark(hierarchyH, "H")
+ I() //@mark(hierarchyI, "I")
+}
+
+type impl struct{}
+
+func (i impl) H() {}
+func (i impl) I() {}
+
+type Struct struct {
+ J func() //@mark(hierarchyJ, "J")
+ K func() //@mark(hierarchyK, "K")
+}
diff --git a/internal/lsp/testdata/rename/issue43616/issue43616.go.golden b/internal/lsp/testdata/rename/issue43616/issue43616.go.golden
new file mode 100644
index 0000000..367d52d
--- /dev/null
+++ b/internal/lsp/testdata/rename/issue43616/issue43616.go.golden
@@ -0,0 +1,9 @@
+-- bar-rename --
+package issue43616
+
+type bar int //@rename("foo","bar")
+
+var x struct{ bar }
+
+var _ = x.bar
+
diff --git a/internal/lsp/testdata/rename/issue43616/issue43616.go.in b/internal/lsp/testdata/rename/issue43616/issue43616.go.in
new file mode 100644
index 0000000..3686914
--- /dev/null
+++ b/internal/lsp/testdata/rename/issue43616/issue43616.go.in
@@ -0,0 +1,7 @@
+package issue43616
+
+type foo int //@rename("foo","bar")
+
+var x struct{ foo }
+
+var _ = x.foo
diff --git a/internal/lsp/testdata/summary.txt.golden b/internal/lsp/testdata/summary.txt.golden
index 4c35b25..5482a03 100644
--- a/internal/lsp/testdata/summary.txt.golden
+++ b/internal/lsp/testdata/summary.txt.golden
@@ -19,7 +19,7 @@
TypeDefinitionsCount = 2
HighlightsCount = 69
ReferencesCount = 25
-RenamesCount = 30
+RenamesCount = 31
PrepareRenamesCount = 7
SymbolsCount = 5
WorkspaceSymbolsCount = 20
diff --git a/internal/packagesinternal/packages.go b/internal/packagesinternal/packages.go
index 1335a5e..d4ec6f9 100644
--- a/internal/packagesinternal/packages.go
+++ b/internal/packagesinternal/packages.go
@@ -1,3 +1,7 @@
+// Copyright 2020 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 packagesinternal exposes internal-only fields from go/packages.
package packagesinternal
diff --git a/playground/playground.go b/playground/playground.go
index 14e9841..64f1519 100644
--- a/playground/playground.go
+++ b/playground/playground.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 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.
diff --git a/playground/socket/socket.go b/playground/socket/socket.go
index 7101ce4..17b6de3 100644
--- a/playground/socket/socket.go
+++ b/playground/socket/socket.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 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.
diff --git a/playground/socket/socket_test.go b/playground/socket/socket_test.go
index 0ceb250..b866e37 100644
--- a/playground/socket/socket_test.go
+++ b/playground/socket/socket_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// Copyright 2015 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.
diff --git a/present/html.go b/present/html.go
index 0bb6438..0c1548c 100644
--- a/present/html.go
+++ b/present/html.go
@@ -1,3 +1,7 @@
+// Copyright 2013 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 present
import (
diff --git a/refactor/rename/mvpkg.go b/refactor/rename/mvpkg.go
index 91c00ff..7889711 100644
--- a/refactor/rename/mvpkg.go
+++ b/refactor/rename/mvpkg.go
@@ -1,6 +1,6 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
-// licence that can be found in the LICENSE file.
+// license that can be found in the LICENSE file.
// This file contains the implementation of the 'gomvpkg' command
// whose main function is in golang.org/x/tools/cmd/gomvpkg.
diff --git a/refactor/rename/mvpkg_test.go b/refactor/rename/mvpkg_test.go
index aca3472..b8b4d85 100644
--- a/refactor/rename/mvpkg_test.go
+++ b/refactor/rename/mvpkg_test.go
@@ -1,6 +1,6 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
-// licence that can be found in the LICENSE file.
+// license that can be found in the LICENSE file.
package rename