1
0
mirror of https://github.com/golang/go synced 2024-11-18 09:34:53 -07:00

internal/lsp: use options hooks to install diff driver

Change-Id: I2f94c2a68d0036a47ccac3fce07cf9f3b784d443
Reviewed-on: https://go-review.googlesource.com/c/tools/+/200558
Run-TryBot: Ian Cottrell <iancottrell@google.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Ian Cottrell 2019-10-10 20:48:16 -04:00
parent 17d4c77023
commit 5889748991
21 changed files with 104 additions and 115 deletions

View File

@ -19,5 +19,5 @@ import (
func main() { func main() {
debug.Version += "-cmd.gopls" debug.Version += "-cmd.gopls"
tool.Main(context.Background(), cmd.New("gopls-legacy", "", nil), os.Args[1:]) tool.Main(context.Background(), cmd.New("gopls-legacy", "", nil, nil), os.Args[1:])
} }

View File

@ -5,24 +5,22 @@
package hooks package hooks
import ( import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
"honnef.co/go/tools/simple" "honnef.co/go/tools/simple"
"honnef.co/go/tools/staticcheck" "honnef.co/go/tools/staticcheck"
"honnef.co/go/tools/stylecheck" "honnef.co/go/tools/stylecheck"
) )
func updateAnalyzers(v source.View, analyzers []*analysis.Analyzer) []*analysis.Analyzer { func updateAnalyzers(options *source.Options) {
if v.Options().StaticCheck { if options.StaticCheck {
for _, a := range simple.Analyzers { for _, a := range simple.Analyzers {
analyzers = append(analyzers, a) options.Analyzers = append(options.Analyzers, a)
} }
for _, a := range staticcheck.Analyzers { for _, a := range staticcheck.Analyzers {
analyzers = append(analyzers, a) options.Analyzers = append(options.Analyzers, a)
} }
for _, a := range stylecheck.Analyzers { for _, a := range stylecheck.Analyzers {
analyzers = append(analyzers, a) options.Analyzers = append(options.Analyzers, a)
} }
} }
return analyzers
} }

View File

@ -8,12 +8,12 @@
package hooks // import "golang.org/x/tools/gopls/internal/hooks" package hooks // import "golang.org/x/tools/gopls/internal/hooks"
import ( import (
"context" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/lsp/cache"
) )
func Install(ctx context.Context) context.Context { func Options(options *source.Options) {
cache.UpdateAnalyzers = updateAnalyzers if options.GoDiff {
return ctx options.ComputeEdits = ComputeEdits
}
updateAnalyzers(options)
} }

View File

@ -19,6 +19,5 @@ import (
func main() { func main() {
ctx := context.Background() ctx := context.Background()
ctx = hooks.Install(ctx) tool.Main(ctx, cmd.New("gopls", "", nil, hooks.Options), os.Args[1:])
tool.Main(ctx, cmd.New("gopls", "", nil), os.Args[1:])
} }

View File

@ -5,7 +5,6 @@
package gopls_test package gopls_test
import ( import (
"context"
"os" "os"
"testing" "testing"
@ -30,9 +29,7 @@ func testCommandLine(t *testing.T, exporter packagestest.Exporter) {
if stat, err := os.Stat(testdata); err != nil || !stat.IsDir() { if stat, err := os.Stat(testdata); err != nil || !stat.IsDir() {
t.Skip("testdata directory not present") t.Skip("testdata directory not present")
} }
ctx := context.Background()
hooks.Install(ctx)
data := tests.Load(t, exporter, testdata) data := tests.Load(t, exporter, testdata)
defer data.Exported.Cleanup() defer data.Exported.Cleanup()
tests.Run(t, cmdtest.NewRunner(exporter, data, tests.Context(t)), data) tests.Run(t, cmdtest.NewRunner(exporter, data, tests.Context(t), hooks.Options), data)
} }

View File

@ -1,65 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cache
import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/asmdecl"
"golang.org/x/tools/go/analysis/passes/assign"
"golang.org/x/tools/go/analysis/passes/atomic"
"golang.org/x/tools/go/analysis/passes/atomicalign"
"golang.org/x/tools/go/analysis/passes/bools"
"golang.org/x/tools/go/analysis/passes/buildtag"
"golang.org/x/tools/go/analysis/passes/cgocall"
"golang.org/x/tools/go/analysis/passes/composite"
"golang.org/x/tools/go/analysis/passes/copylock"
"golang.org/x/tools/go/analysis/passes/httpresponse"
"golang.org/x/tools/go/analysis/passes/loopclosure"
"golang.org/x/tools/go/analysis/passes/lostcancel"
"golang.org/x/tools/go/analysis/passes/nilfunc"
"golang.org/x/tools/go/analysis/passes/printf"
"golang.org/x/tools/go/analysis/passes/shift"
"golang.org/x/tools/go/analysis/passes/sortslice"
"golang.org/x/tools/go/analysis/passes/stdmethods"
"golang.org/x/tools/go/analysis/passes/structtag"
"golang.org/x/tools/go/analysis/passes/tests"
"golang.org/x/tools/go/analysis/passes/unmarshal"
"golang.org/x/tools/go/analysis/passes/unreachable"
"golang.org/x/tools/go/analysis/passes/unsafeptr"
"golang.org/x/tools/go/analysis/passes/unusedresult"
"golang.org/x/tools/internal/lsp/source"
)
var defaultAnalyzers = []*analysis.Analyzer{
// The traditional vet suite:
asmdecl.Analyzer,
assign.Analyzer,
atomic.Analyzer,
atomicalign.Analyzer,
bools.Analyzer,
buildtag.Analyzer,
cgocall.Analyzer,
composite.Analyzer,
copylock.Analyzer,
httpresponse.Analyzer,
loopclosure.Analyzer,
lostcancel.Analyzer,
nilfunc.Analyzer,
printf.Analyzer,
shift.Analyzer,
stdmethods.Analyzer,
structtag.Analyzer,
tests.Analyzer,
unmarshal.Analyzer,
unreachable.Analyzer,
unsafeptr.Analyzer,
unusedresult.Analyzer,
// Non-vet analyzers
sortslice.Analyzer,
}
var UpdateAnalyzers = func(v source.View, analyzers []*analysis.Analyzer) []*analysis.Analyzer {
return analyzers
}

View File

@ -18,21 +18,23 @@ import (
"golang.org/x/tools/internal/span" "golang.org/x/tools/internal/span"
) )
func New() source.Cache { func New(options func(*source.Options)) source.Cache {
index := atomic.AddInt64(&cacheIndex, 1) index := atomic.AddInt64(&cacheIndex, 1)
c := &cache{ c := &cache{
fs: &nativeFileSystem{}, fs: &nativeFileSystem{},
id: strconv.FormatInt(index, 10), id: strconv.FormatInt(index, 10),
fset: token.NewFileSet(), fset: token.NewFileSet(),
options: options,
} }
debug.AddCache(debugCache{c}) debug.AddCache(debugCache{c})
return c return c
} }
type cache struct { type cache struct {
fs source.FileSystem fs source.FileSystem
id string id string
fset *token.FileSet fset *token.FileSet
options func(*source.Options)
store memoize.Store store memoize.Store
} }

View File

@ -110,7 +110,10 @@ func (s *session) NewView(ctx context.Context, name string, folder span.URI, opt
} }
v.snapshot.view = v v.snapshot.view = v
v.analyzers = UpdateAnalyzers(v, defaultAnalyzers) if v.session.cache.options != nil {
v.session.cache.options(&v.options)
}
// Preemptively build the builtin package, // Preemptively build the builtin package,
// so we immediately add builtin.go to the list of ignored files. // so we immediately add builtin.go to the list of ignored files.
v.buildBuiltinPackage(ctx) v.buildBuiltinPackage(ctx)

View File

@ -15,7 +15,6 @@ import (
"strings" "strings"
"sync" "sync"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/packages" "golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/imports" "golang.org/x/tools/internal/imports"
"golang.org/x/tools/internal/lsp/debug" "golang.org/x/tools/internal/lsp/debug"
@ -80,8 +79,6 @@ type view struct {
// ignoredURIs is the set of URIs of files that we ignore. // ignoredURIs is the set of URIs of files that we ignore.
ignoredURIsMu sync.Mutex ignoredURIsMu sync.Mutex
ignoredURIs map[span.URI]struct{} ignoredURIs map[span.URI]struct{}
analyzers []*analysis.Analyzer
} }
func (v *view) Session() source.Session { func (v *view) Session() source.Session {
@ -396,10 +393,6 @@ func (v *view) findFile(uri span.URI) (viewFile, error) {
return nil, nil return nil, nil
} }
func (v *view) Analyzers() []*analysis.Analyzer {
return v.analyzers
}
func (f *fileBase) addURI(uri span.URI) int { func (f *fileBase) addURI(uri span.URI) int {
f.uris = append(f.uris, uri) f.uris = append(f.uris, uri)
return len(f.uris) return len(f.uris)

View File

@ -65,15 +65,19 @@ type Application struct {
// Control ocagent export of telemetry // Control ocagent export of telemetry
OCAgent string `flag:"ocagent" help:"The address of the ocagent, or off"` OCAgent string `flag:"ocagent" help:"The address of the ocagent, or off"`
// PrepareOptions is called to update the options when a new view is built.
// It is primarily to allow the behavior of gopls to be modified by hooks.
PrepareOptions func(*source.Options)
} }
// Returns a new Application ready to run. // Returns a new Application ready to run.
func New(name, wd string, env []string) *Application { func New(name, wd string, env []string, options func(*source.Options)) *Application {
if wd == "" { if wd == "" {
wd, _ = os.Getwd() wd, _ = os.Getwd()
} }
app := &Application{ app := &Application{
cache: cache.New(), cache: cache.New(options),
name: name, name: name,
wd: wd, wd: wd,
env: env, env: env,

View File

@ -32,7 +32,7 @@ func TestCommandLine(t *testing.T) {
func testCommandLine(t *testing.T, exporter packagestest.Exporter) { func testCommandLine(t *testing.T, exporter packagestest.Exporter) {
data := tests.Load(t, exporter, "../testdata") data := tests.Load(t, exporter, "../testdata")
defer data.Exported.Cleanup() defer data.Exported.Cleanup()
tests.Run(t, cmdtest.NewRunner(exporter, data, tests.Context(t)), data) tests.Run(t, cmdtest.NewRunner(exporter, data, tests.Context(t), nil), data)
} }
func TestDefinitionHelpExample(t *testing.T) { func TestDefinitionHelpExample(t *testing.T) {
@ -54,7 +54,7 @@ func TestDefinitionHelpExample(t *testing.T) {
fmt.Sprintf("%v:#%v", thisFile, cmd.ExampleOffset)} { fmt.Sprintf("%v:#%v", thisFile, cmd.ExampleOffset)} {
args := append(baseArgs, query) args := append(baseArgs, query)
got := cmdtest.CaptureStdOut(t, func() { got := cmdtest.CaptureStdOut(t, func() {
_ = tool.Run(tests.Context(t), cmd.New("gopls-test", "", nil), args) _ = tool.Run(tests.Context(t), cmd.New("gopls-test", "", nil, nil), args)
}) })
if !expect.MatchString(got) { if !expect.MatchString(got) {
t.Errorf("test with %v\nexpected:\n%s\ngot:\n%s", args, expect, got) t.Errorf("test with %v\nexpected:\n%s\ngot:\n%s", args, expect, got)

View File

@ -22,7 +22,7 @@ func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []source.Diagnosti
} }
fname := uri.Filename() fname := uri.Filename()
args := []string{"-remote=internal", "check", fname} args := []string{"-remote=internal", "check", fname}
app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Exported.Config.Env) app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Exported.Config.Env, r.options)
out := CaptureStdOut(t, func() { out := CaptureStdOut(t, func() {
_ = tool.Run(r.ctx, app, args) _ = tool.Run(r.ctx, app, args)
}) })

View File

@ -26,13 +26,15 @@ type runner struct {
exporter packagestest.Exporter exporter packagestest.Exporter
data *tests.Data data *tests.Data
ctx context.Context ctx context.Context
options func(*source.Options)
} }
func NewRunner(exporter packagestest.Exporter, data *tests.Data, ctx context.Context) tests.Tests { func NewRunner(exporter packagestest.Exporter, data *tests.Data, ctx context.Context, options func(*source.Options)) tests.Tests {
return &runner{ return &runner{
exporter: exporter, exporter: exporter,
data: data, data: data,
ctx: ctx, ctx: ctx,
options: options,
} }
} }

View File

@ -54,7 +54,7 @@ func (r *runner) Definition(t *testing.T, spn span.Span, d tests.Definition) {
uri := d.Src.URI() uri := d.Src.URI()
args = append(args, fmt.Sprint(d.Src)) args = append(args, fmt.Sprint(d.Src))
got := CaptureStdOut(t, func() { got := CaptureStdOut(t, func() {
app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Exported.Config.Env) app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Exported.Config.Env, r.options)
_ = tool.Run(r.ctx, app, args) _ = tool.Run(r.ctx, app, args)
}) })
got = normalizePaths(r.data, got) got = normalizePaths(r.data, got)

View File

@ -33,7 +33,7 @@ func (r *runner) Format(t *testing.T, spn span.Span) {
//TODO: our error handling differs, for now just skip unformattable files //TODO: our error handling differs, for now just skip unformattable files
t.Skip("Unformattable file") t.Skip("Unformattable file")
} }
app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Config.Env) app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Config.Env, r.options)
got := CaptureStdOut(t, func() { got := CaptureStdOut(t, func() {
_ = tool.Run(r.ctx, app, append([]string{"-remote=internal", "format"}, filename)) _ = tool.Run(r.ctx, app, append([]string{"-remote=internal", "format"}, filename))
}) })

View File

@ -16,7 +16,7 @@ import (
func (r *runner) Rename(t *testing.T, spn span.Span, newText string) { func (r *runner) Rename(t *testing.T, spn span.Span, newText string) {
filename := spn.URI().Filename() filename := spn.URI().Filename()
goldenTag := newText + "-rename" goldenTag := newText + "-rename"
app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Config.Env) app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Config.Env, r.options)
loc := fmt.Sprintf("%v", spn) loc := fmt.Sprintf("%v", spn)
var err error var err error
got := CaptureStdOut(t, func() { got := CaptureStdOut(t, func() {

View File

@ -48,7 +48,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
data := tests.Load(t, exporter, "testdata") data := tests.Load(t, exporter, "testdata")
defer data.Exported.Cleanup() defer data.Exported.Cleanup()
cache := cache.New() cache := cache.New(nil)
session := cache.NewSession(ctx) session := cache.NewSession(ctx)
options := tests.DefaultOptions() options := tests.DefaultOptions()
session.SetOptions(options) session.SetOptions(options)

View File

@ -305,7 +305,7 @@ func singleDiagnostic(uri span.URI, format string, a ...interface{}) map[span.UR
func runAnalyses(ctx context.Context, view View, cph CheckPackageHandle, disabledAnalyses map[string]struct{}, report func(a *analysis.Analyzer, diag analysis.Diagnostic) error) error { func runAnalyses(ctx context.Context, view View, cph CheckPackageHandle, disabledAnalyses map[string]struct{}, report func(a *analysis.Analyzer, diag analysis.Diagnostic) error) error {
var analyzers []*analysis.Analyzer var analyzers []*analysis.Analyzer
for _, a := range view.Analyzers() { for _, a := range view.Options().Analyzers {
if _, ok := disabledAnalyses[a.Name]; ok { if _, ok := disabledAnalyses[a.Name]; ok {
continue continue
} }

View File

@ -9,6 +9,30 @@ import (
"os" "os"
"time" "time"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/asmdecl"
"golang.org/x/tools/go/analysis/passes/assign"
"golang.org/x/tools/go/analysis/passes/atomic"
"golang.org/x/tools/go/analysis/passes/atomicalign"
"golang.org/x/tools/go/analysis/passes/bools"
"golang.org/x/tools/go/analysis/passes/buildtag"
"golang.org/x/tools/go/analysis/passes/cgocall"
"golang.org/x/tools/go/analysis/passes/composite"
"golang.org/x/tools/go/analysis/passes/copylock"
"golang.org/x/tools/go/analysis/passes/httpresponse"
"golang.org/x/tools/go/analysis/passes/loopclosure"
"golang.org/x/tools/go/analysis/passes/lostcancel"
"golang.org/x/tools/go/analysis/passes/nilfunc"
"golang.org/x/tools/go/analysis/passes/printf"
"golang.org/x/tools/go/analysis/passes/shift"
"golang.org/x/tools/go/analysis/passes/sortslice"
"golang.org/x/tools/go/analysis/passes/stdmethods"
"golang.org/x/tools/go/analysis/passes/structtag"
"golang.org/x/tools/go/analysis/passes/tests"
"golang.org/x/tools/go/analysis/passes/unmarshal"
"golang.org/x/tools/go/analysis/passes/unreachable"
"golang.org/x/tools/go/analysis/passes/unsafeptr"
"golang.org/x/tools/go/analysis/passes/unusedresult"
"golang.org/x/tools/internal/lsp/diff" "golang.org/x/tools/internal/lsp/diff"
"golang.org/x/tools/internal/lsp/diff/myers" "golang.org/x/tools/internal/lsp/diff/myers"
"golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/protocol"
@ -43,6 +67,7 @@ var (
Budget: 100 * time.Millisecond, Budget: 100 * time.Millisecond,
}, },
ComputeEdits: myers.ComputeEdits, ComputeEdits: myers.ComputeEdits,
Analyzers: defaultAnalyzers,
} }
) )
@ -57,6 +82,7 @@ type Options struct {
DisabledAnalyses map[string]struct{} DisabledAnalyses map[string]struct{}
StaticCheck bool StaticCheck bool
GoDiff bool
WatchFileChanges bool WatchFileChanges bool
InsertTextFormat protocol.InsertTextFormat InsertTextFormat protocol.InsertTextFormat
@ -76,6 +102,8 @@ type Options struct {
Completion CompletionOptions Completion CompletionOptions
ComputeEdits diff.ComputeEdits ComputeEdits diff.ComputeEdits
Analyzers []*analysis.Analyzer
} }
type CompletionOptions struct { type CompletionOptions struct {
@ -246,6 +274,9 @@ func (o *Options) set(name string, value interface{}) OptionResult {
case "staticcheck": case "staticcheck":
result.setBool(&o.StaticCheck) result.setBool(&o.StaticCheck)
case "go-diff":
result.setBool(&o.GoDiff)
// Deprecated settings. // Deprecated settings.
case "wantSuggestedFixes": case "wantSuggestedFixes":
result.State = OptionDeprecated result.State = OptionDeprecated
@ -290,3 +321,31 @@ func (r *OptionResult) setBool(b *bool) {
*b = v *b = v
} }
} }
var defaultAnalyzers = []*analysis.Analyzer{
// The traditional vet suite:
asmdecl.Analyzer,
assign.Analyzer,
atomic.Analyzer,
atomicalign.Analyzer,
bools.Analyzer,
buildtag.Analyzer,
cgocall.Analyzer,
composite.Analyzer,
copylock.Analyzer,
httpresponse.Analyzer,
loopclosure.Analyzer,
lostcancel.Analyzer,
nilfunc.Analyzer,
printf.Analyzer,
shift.Analyzer,
stdmethods.Analyzer,
structtag.Analyzer,
tests.Analyzer,
unmarshal.Analyzer,
unreachable.Analyzer,
unsafeptr.Analyzer,
unusedresult.Analyzer,
// Non-vet analyzers
sortslice.Analyzer,
}

View File

@ -48,7 +48,7 @@ func testSource(t *testing.T, exporter packagestest.Exporter) {
data := tests.Load(t, exporter, "../testdata") data := tests.Load(t, exporter, "../testdata")
defer data.Exported.Cleanup() defer data.Exported.Cleanup()
cache := cache.New() cache := cache.New(nil)
session := cache.NewSession(ctx) session := cache.NewSession(ctx)
options := tests.DefaultOptions() options := tests.DefaultOptions()
options.Env = data.Config.Env options.Env = data.Config.Env

View File

@ -240,9 +240,6 @@ type View interface {
// This function does not correctly invalidate the view when needed. // This function does not correctly invalidate the view when needed.
SetOptions(Options) SetOptions(Options)
// Analyzers returns the set of Analyzers active for this view.
Analyzers() []*analysis.Analyzer
// CheckPackageHandles returns the CheckPackageHandles for the packages // CheckPackageHandles returns the CheckPackageHandles for the packages
// that this file belongs to. // that this file belongs to.
CheckPackageHandles(ctx context.Context, f File) (Snapshot, []CheckPackageHandle, error) CheckPackageHandles(ctx context.Context, f File) (Snapshot, []CheckPackageHandle, error)