internal/lsp: stop making background contexts everywhere
For all uses inside the lsp we use the detatch logic instead For tests we build it in the test harness instead This is in preparation for things on the context becomming important Change-Id: I7e6910e0d3581b82abbeeb09f9c22a99efb73142 Reviewed-on: https://go-review.googlesource.com/c/tools/+/185677 Run-TryBot: Ian Cottrell <iancottrell@google.com> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
2868181328
commit
5f9351755f
|
@ -18,6 +18,7 @@ import (
|
||||||
"golang.org/x/tools/internal/lsp/source"
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
"golang.org/x/tools/internal/lsp/xlog"
|
"golang.org/x/tools/internal/lsp/xlog"
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
|
"golang.org/x/tools/internal/xcontext"
|
||||||
)
|
)
|
||||||
|
|
||||||
type session struct {
|
type session struct {
|
||||||
|
@ -64,11 +65,11 @@ func (s *session) Cache() source.Cache {
|
||||||
return s.cache
|
return s.cache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *session) NewView(name string, folder span.URI) source.View {
|
func (s *session) NewView(ctx context.Context, name string, folder span.URI) source.View {
|
||||||
index := atomic.AddInt64(&viewIndex, 1)
|
index := atomic.AddInt64(&viewIndex, 1)
|
||||||
s.viewMu.Lock()
|
s.viewMu.Lock()
|
||||||
defer s.viewMu.Unlock()
|
defer s.viewMu.Unlock()
|
||||||
ctx := context.Background()
|
ctx = xcontext.Detach(ctx)
|
||||||
backgroundCtx, cancel := context.WithCancel(ctx)
|
backgroundCtx, cancel := context.WithCancel(ctx)
|
||||||
v := &view{
|
v := &view{
|
||||||
session: s,
|
session: s,
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package cmd_test
|
package cmd_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -23,7 +22,7 @@ func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) {
|
||||||
fname := uri.Filename()
|
fname := uri.Filename()
|
||||||
args := []string{"-remote=internal", "check", fname}
|
args := []string{"-remote=internal", "check", fname}
|
||||||
out := captureStdOut(t, func() {
|
out := captureStdOut(t, func() {
|
||||||
tool.Main(context.Background(), r.app, args)
|
tool.Main(r.ctx, r.app, args)
|
||||||
})
|
})
|
||||||
// parse got into a collection of reports
|
// parse got into a collection of reports
|
||||||
got := map[string]struct{}{}
|
got := map[string]struct{}{}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"golang.org/x/tools/internal/lsp/source"
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
"golang.org/x/tools/internal/tool"
|
"golang.org/x/tools/internal/tool"
|
||||||
|
"golang.org/x/tools/internal/xcontext"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Application is the main application as passed to tool.Main
|
// Application is the main application as passed to tool.Main
|
||||||
|
@ -148,7 +149,7 @@ func (app *Application) connect(ctx context.Context) (*connection, error) {
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
connection := newConnection(app)
|
connection := newConnection(app)
|
||||||
ctx := context.Background() //TODO:a way of shutting down the internal server
|
ctx := xcontext.Detach(ctx) //TODO:a way of shutting down the internal server
|
||||||
cr, sw, _ := os.Pipe()
|
cr, sw, _ := os.Pipe()
|
||||||
sr, cw, _ := os.Pipe()
|
sr, cw, _ := os.Pipe()
|
||||||
var jc *jsonrpc2.Conn
|
var jc *jsonrpc2.Conn
|
||||||
|
|
|
@ -6,6 +6,7 @@ package cmd_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -24,6 +25,7 @@ type runner struct {
|
||||||
exporter packagestest.Exporter
|
exporter packagestest.Exporter
|
||||||
data *tests.Data
|
data *tests.Data
|
||||||
app *cmd.Application
|
app *cmd.Application
|
||||||
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommandLine(t *testing.T) {
|
func TestCommandLine(t *testing.T) {
|
||||||
|
@ -38,6 +40,7 @@ func testCommandLine(t *testing.T, exporter packagestest.Exporter) {
|
||||||
exporter: exporter,
|
exporter: exporter,
|
||||||
data: data,
|
data: data,
|
||||||
app: cmd.New(data.Config.Dir, data.Exported.Config.Env),
|
app: cmd.New(data.Config.Dir, data.Exported.Config.Env),
|
||||||
|
ctx: tests.Context(t),
|
||||||
}
|
}
|
||||||
tests.Run(t, r, data)
|
tests.Run(t, r, data)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package cmd_test
|
package cmd_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -56,7 +55,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 := captureStdOut(t, func() {
|
got := captureStdOut(t, func() {
|
||||||
tool.Main(context.Background(), cmd.New("", nil), args)
|
tool.Main(tests.Context(t), cmd.New("", 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)
|
||||||
|
@ -84,7 +83,7 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
|
||||||
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() {
|
||||||
tool.Main(context.Background(), r.app, args)
|
tool.Main(r.ctx, r.app, args)
|
||||||
})
|
})
|
||||||
got = normalizePaths(r.data, got)
|
got = normalizePaths(r.data, got)
|
||||||
if mode&jsonGoDef != 0 && runtime.GOOS == "windows" {
|
if mode&jsonGoDef != 0 && runtime.GOOS == "windows" {
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package cmd_test
|
package cmd_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -40,7 +39,7 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
|
||||||
}
|
}
|
||||||
app := cmd.New(r.data.Config.Dir, r.data.Config.Env)
|
app := cmd.New(r.data.Config.Dir, r.data.Config.Env)
|
||||||
got := captureStdOut(t, func() {
|
got := captureStdOut(t, func() {
|
||||||
tool.Main(context.Background(), app, append([]string{"-remote=internal", "format"}, args...))
|
tool.Main(r.ctx, app, append([]string{"-remote=internal", "format"}, args...))
|
||||||
})
|
})
|
||||||
got = normalizePaths(r.data, got)
|
got = normalizePaths(r.data, got)
|
||||||
// check the first two lines are the expected file header
|
// check the first two lines are the expected file header
|
||||||
|
|
|
@ -32,18 +32,20 @@ func TestLSP(t *testing.T) {
|
||||||
type runner struct {
|
type runner struct {
|
||||||
server *Server
|
server *Server
|
||||||
data *tests.Data
|
data *tests.Data
|
||||||
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewName = "lsp_test"
|
const viewName = "lsp_test"
|
||||||
|
|
||||||
func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
||||||
|
ctx := tests.Context(t)
|
||||||
data := tests.Load(t, exporter, "testdata")
|
data := tests.Load(t, exporter, "testdata")
|
||||||
defer data.Exported.Cleanup()
|
defer data.Exported.Cleanup()
|
||||||
|
|
||||||
log := xlog.New(xlog.StdSink{})
|
log := xlog.New(xlog.StdSink{})
|
||||||
cache := cache.New()
|
cache := cache.New()
|
||||||
session := cache.NewSession(log)
|
session := cache.NewSession(log)
|
||||||
view := session.NewView(viewName, span.FileURI(data.Config.Dir))
|
view := session.NewView(ctx, viewName, span.FileURI(data.Config.Dir))
|
||||||
view.SetEnv(data.Config.Env)
|
view.SetEnv(data.Config.Env)
|
||||||
for filename, content := range data.Config.Overlay {
|
for filename, content := range data.Config.Overlay {
|
||||||
session.SetOverlay(span.FileURI(filename), content)
|
session.SetOverlay(span.FileURI(filename), content)
|
||||||
|
@ -59,6 +61,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
||||||
hoverKind: source.SynopsisDocumentation,
|
hoverKind: source.SynopsisDocumentation,
|
||||||
},
|
},
|
||||||
data: data,
|
data: data,
|
||||||
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
tests.Run(t, r, data)
|
tests.Run(t, r, data)
|
||||||
}
|
}
|
||||||
|
@ -67,7 +70,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
||||||
func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) {
|
func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) {
|
||||||
v := r.server.session.View(viewName)
|
v := r.server.session.View(viewName)
|
||||||
for uri, want := range data {
|
for uri, want := range data {
|
||||||
f, err := v.GetFile(context.Background(), uri)
|
f, err := v.GetFile(r.ctx, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("no file for %s: %v", f, err)
|
t.Fatalf("no file for %s: %v", f, err)
|
||||||
}
|
}
|
||||||
|
@ -75,7 +78,7 @@ func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) {
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("%s is not a Go file: %v", uri, err)
|
t.Fatalf("%s is not a Go file: %v", uri, err)
|
||||||
}
|
}
|
||||||
results, err := source.Diagnostics(context.Background(), v, gof, nil)
|
results, err := source.Diagnostics(r.ctx, v, gof, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -218,7 +221,7 @@ func (r *runner) Completion(t *testing.T, data tests.Completions, snippets tests
|
||||||
|
|
||||||
func (r *runner) runCompletion(t *testing.T, src span.Span) *protocol.CompletionList {
|
func (r *runner) runCompletion(t *testing.T, src span.Span) *protocol.CompletionList {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
list, err := r.server.Completion(context.Background(), &protocol.CompletionParams{
|
list, err := r.server.Completion(r.ctx, &protocol.CompletionParams{
|
||||||
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
|
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
|
||||||
TextDocument: protocol.TextDocumentIdentifier{
|
TextDocument: protocol.TextDocumentIdentifier{
|
||||||
URI: protocol.NewURI(src.URI()),
|
URI: protocol.NewURI(src.URI()),
|
||||||
|
@ -295,7 +298,6 @@ func summarizeCompletionItems(i int, want []source.CompletionItem, got []protoco
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Format(t *testing.T, data tests.Formats) {
|
func (r *runner) Format(t *testing.T, data tests.Formats) {
|
||||||
ctx := context.Background()
|
|
||||||
for _, spn := range data {
|
for _, spn := range data {
|
||||||
uri := spn.URI()
|
uri := spn.URI()
|
||||||
filename := uri.Filename()
|
filename := uri.Filename()
|
||||||
|
@ -305,7 +307,7 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
|
||||||
return out, nil
|
return out, nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
edits, err := r.server.Formatting(context.Background(), &protocol.DocumentFormattingParams{
|
edits, err := r.server.Formatting(r.ctx, &protocol.DocumentFormattingParams{
|
||||||
TextDocument: protocol.TextDocumentIdentifier{
|
TextDocument: protocol.TextDocumentIdentifier{
|
||||||
URI: protocol.NewURI(uri),
|
URI: protocol.NewURI(uri),
|
||||||
},
|
},
|
||||||
|
@ -316,7 +318,7 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, m, err := getSourceFile(ctx, r.server.session.ViewOf(uri), uri)
|
_, m, err := getSourceFile(r.ctx, r.server.session.ViewOf(uri), uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -333,7 +335,6 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Import(t *testing.T, data tests.Imports) {
|
func (r *runner) Import(t *testing.T, data tests.Imports) {
|
||||||
ctx := context.Background()
|
|
||||||
for _, spn := range data {
|
for _, spn := range data {
|
||||||
uri := spn.URI()
|
uri := spn.URI()
|
||||||
filename := uri.Filename()
|
filename := uri.Filename()
|
||||||
|
@ -343,7 +344,7 @@ func (r *runner) Import(t *testing.T, data tests.Imports) {
|
||||||
return out, nil
|
return out, nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
actions, err := r.server.CodeAction(context.Background(), &protocol.CodeActionParams{
|
actions, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{
|
||||||
TextDocument: protocol.TextDocumentIdentifier{
|
TextDocument: protocol.TextDocumentIdentifier{
|
||||||
URI: protocol.NewURI(uri),
|
URI: protocol.NewURI(uri),
|
||||||
},
|
},
|
||||||
|
@ -354,7 +355,7 @@ func (r *runner) Import(t *testing.T, data tests.Imports) {
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, m, err := getSourceFile(ctx, r.server.session.ViewOf(uri), uri)
|
_, m, err := getSourceFile(r.ctx, r.server.session.ViewOf(uri), uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -393,13 +394,13 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
|
||||||
var locs []protocol.Location
|
var locs []protocol.Location
|
||||||
var hover *protocol.Hover
|
var hover *protocol.Hover
|
||||||
if d.IsType {
|
if d.IsType {
|
||||||
locs, err = r.server.TypeDefinition(context.Background(), params)
|
locs, err = r.server.TypeDefinition(r.ctx, params)
|
||||||
} else {
|
} else {
|
||||||
locs, err = r.server.Definition(context.Background(), params)
|
locs, err = r.server.Definition(r.ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", d.Src, err)
|
t.Fatalf("failed for %v: %v", d.Src, err)
|
||||||
}
|
}
|
||||||
hover, err = r.server.Hover(context.Background(), params)
|
hover, err = r.server.Hover(r.ctx, params)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", d.Src, err)
|
t.Fatalf("failed for %v: %v", d.Src, err)
|
||||||
|
@ -446,7 +447,7 @@ func (r *runner) Highlight(t *testing.T, data tests.Highlights) {
|
||||||
TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI},
|
TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI},
|
||||||
Position: loc.Range.Start,
|
Position: loc.Range.Start,
|
||||||
}
|
}
|
||||||
highlights, err := r.server.DocumentHighlight(context.Background(), params)
|
highlights, err := r.server.DocumentHighlight(r.ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -492,7 +493,7 @@ func (r *runner) Reference(t *testing.T, data tests.References) {
|
||||||
Position: loc.Range.Start,
|
Position: loc.Range.Start,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
got, err := r.server.References(context.Background(), params)
|
got, err := r.server.References(r.ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", src, err)
|
t.Fatalf("failed for %v: %v", src, err)
|
||||||
}
|
}
|
||||||
|
@ -509,7 +510,6 @@ func (r *runner) Reference(t *testing.T, data tests.References) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Rename(t *testing.T, data tests.Renames) {
|
func (r *runner) Rename(t *testing.T, data tests.Renames) {
|
||||||
ctx := context.Background()
|
|
||||||
for spn, newText := range data {
|
for spn, newText := range data {
|
||||||
tag := fmt.Sprintf("%s-rename", newText)
|
tag := fmt.Sprintf("%s-rename", newText)
|
||||||
|
|
||||||
|
@ -524,7 +524,7 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
|
||||||
t.Fatalf("failed for %v: %v", spn, err)
|
t.Fatalf("failed for %v: %v", spn, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
workspaceEdits, err := r.server.Rename(ctx, &protocol.RenameParams{
|
workspaceEdits, err := r.server.Rename(r.ctx, &protocol.RenameParams{
|
||||||
TextDocument: protocol.TextDocumentIdentifier{
|
TextDocument: protocol.TextDocumentIdentifier{
|
||||||
URI: protocol.NewURI(uri),
|
URI: protocol.NewURI(uri),
|
||||||
},
|
},
|
||||||
|
@ -544,7 +544,7 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
|
||||||
var res []string
|
var res []string
|
||||||
for uri, edits := range *workspaceEdits.Changes {
|
for uri, edits := range *workspaceEdits.Changes {
|
||||||
spnURI := span.URI(uri)
|
spnURI := span.URI(uri)
|
||||||
_, m, err := getSourceFile(ctx, r.server.session.ViewOf(span.URI(spnURI)), spnURI)
|
_, m, err := getSourceFile(r.ctx, r.server.session.ViewOf(span.URI(spnURI)), spnURI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -612,7 +612,7 @@ func (r *runner) Symbol(t *testing.T, data tests.Symbols) {
|
||||||
URI: string(uri),
|
URI: string(uri),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
symbols, err := r.server.DocumentSymbol(context.Background(), params)
|
symbols, err := r.server.DocumentSymbol(r.ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -688,7 +688,7 @@ func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", loc, err)
|
t.Fatalf("failed for %v: %v", loc, err)
|
||||||
}
|
}
|
||||||
gotSignatures, err := r.server.SignatureHelp(context.Background(), &protocol.TextDocumentPositionParams{
|
gotSignatures, err := r.server.SignatureHelp(r.ctx, &protocol.TextDocumentPositionParams{
|
||||||
TextDocument: protocol.TextDocumentIdentifier{
|
TextDocument: protocol.TextDocumentIdentifier{
|
||||||
URI: protocol.NewURI(spn.URI()),
|
URI: protocol.NewURI(spn.URI()),
|
||||||
},
|
},
|
||||||
|
@ -754,7 +754,7 @@ func (r *runner) Link(t *testing.T, data tests.Links) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
gotLinks, err := r.server.DocumentLink(context.Background(), &protocol.DocumentLinkParams{
|
gotLinks, err := r.server.DocumentLink(r.ctx, &protocol.DocumentLinkParams{
|
||||||
TextDocument: protocol.TextDocumentIdentifier{
|
TextDocument: protocol.TextDocumentIdentifier{
|
||||||
URI: protocol.NewURI(uri),
|
URI: protocol.NewURI(uri),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,21 +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 protocol
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// detatch returns a context that keeps all the values of its parent context
|
|
||||||
// but detatches from the cancellation and error handling.
|
|
||||||
func detatchContext(ctx context.Context) context.Context { return detatchedContext{ctx} }
|
|
||||||
|
|
||||||
type detatchedContext struct{ parent context.Context }
|
|
||||||
|
|
||||||
func (v detatchedContext) Deadline() (time.Time, bool) { return time.Time{}, false }
|
|
||||||
func (v detatchedContext) Done() <-chan struct{} { return nil }
|
|
||||||
func (v detatchedContext) Err() error { return nil }
|
|
||||||
func (v detatchedContext) Value(key interface{}) interface{} { return v.parent.Value(key) }
|
|
|
@ -10,13 +10,14 @@ import (
|
||||||
"golang.org/x/tools/internal/jsonrpc2"
|
"golang.org/x/tools/internal/jsonrpc2"
|
||||||
"golang.org/x/tools/internal/lsp/telemetry/trace"
|
"golang.org/x/tools/internal/lsp/telemetry/trace"
|
||||||
"golang.org/x/tools/internal/lsp/xlog"
|
"golang.org/x/tools/internal/lsp/xlog"
|
||||||
|
"golang.org/x/tools/internal/xcontext"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultMessageBufferSize = 20
|
const defaultMessageBufferSize = 20
|
||||||
const defaultRejectIfOverloaded = false
|
const defaultRejectIfOverloaded = false
|
||||||
|
|
||||||
func canceller(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID) {
|
func canceller(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID) {
|
||||||
ctx = detatchContext(ctx)
|
ctx = xcontext.Detach(ctx)
|
||||||
ctx, span := trace.StartSpan(ctx, "protocol.canceller")
|
ctx, span := trace.StartSpan(ctx, "protocol.canceller")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
conn.Notify(ctx, "$/cancelRequest", &CancelParams{ID: id})
|
conn.Notify(ctx, "$/cancelRequest", &CancelParams{ID: id})
|
||||||
|
|
|
@ -30,9 +30,11 @@ func TestSource(t *testing.T) {
|
||||||
type runner struct {
|
type runner struct {
|
||||||
view source.View
|
view source.View
|
||||||
data *tests.Data
|
data *tests.Data
|
||||||
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSource(t *testing.T, exporter packagestest.Exporter) {
|
func testSource(t *testing.T, exporter packagestest.Exporter) {
|
||||||
|
ctx := tests.Context(t)
|
||||||
data := tests.Load(t, exporter, "../testdata")
|
data := tests.Load(t, exporter, "../testdata")
|
||||||
defer data.Exported.Cleanup()
|
defer data.Exported.Cleanup()
|
||||||
|
|
||||||
|
@ -40,8 +42,9 @@ func testSource(t *testing.T, exporter packagestest.Exporter) {
|
||||||
cache := cache.New()
|
cache := cache.New()
|
||||||
session := cache.NewSession(log)
|
session := cache.NewSession(log)
|
||||||
r := &runner{
|
r := &runner{
|
||||||
view: session.NewView("source_test", span.FileURI(data.Config.Dir)),
|
view: session.NewView(ctx, "source_test", span.FileURI(data.Config.Dir)),
|
||||||
data: data,
|
data: data,
|
||||||
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
r.view.SetEnv(data.Config.Env)
|
r.view.SetEnv(data.Config.Env)
|
||||||
for filename, content := range data.Config.Overlay {
|
for filename, content := range data.Config.Overlay {
|
||||||
|
@ -52,11 +55,11 @@ func testSource(t *testing.T, exporter packagestest.Exporter) {
|
||||||
|
|
||||||
func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) {
|
func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) {
|
||||||
for uri, want := range data {
|
for uri, want := range data {
|
||||||
f, err := r.view.GetFile(context.Background(), uri)
|
f, err := r.view.GetFile(r.ctx, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
results, err := source.Diagnostics(context.Background(), r.view, f.(source.GoFile), nil)
|
results, err := source.Diagnostics(r.ctx, r.view, f.(source.GoFile), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -132,7 +135,7 @@ func summarizeDiagnostics(i int, want []source.Diagnostic, got []source.Diagnost
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Completion(t *testing.T, data tests.Completions, snippets tests.CompletionSnippets, items tests.CompletionItems) {
|
func (r *runner) Completion(t *testing.T, data tests.Completions, snippets tests.CompletionSnippets, items tests.CompletionItems) {
|
||||||
ctx := context.Background()
|
ctx := r.ctx
|
||||||
for src, itemList := range data {
|
for src, itemList := range data {
|
||||||
var want []source.CompletionItem
|
var want []source.CompletionItem
|
||||||
for _, pos := range itemList {
|
for _, pos := range itemList {
|
||||||
|
@ -289,7 +292,7 @@ func summarizeCompletionItems(i int, want []source.CompletionItem, got []source.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Format(t *testing.T, data tests.Formats) {
|
func (r *runner) Format(t *testing.T, data tests.Formats) {
|
||||||
ctx := context.Background()
|
ctx := r.ctx
|
||||||
for _, spn := range data {
|
for _, spn := range data {
|
||||||
uri := spn.URI()
|
uri := spn.URI()
|
||||||
filename := uri.Filename()
|
filename := uri.Filename()
|
||||||
|
@ -327,7 +330,7 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Import(t *testing.T, data tests.Imports) {
|
func (r *runner) Import(t *testing.T, data tests.Imports) {
|
||||||
ctx := context.Background()
|
ctx := r.ctx
|
||||||
for _, spn := range data {
|
for _, spn := range data {
|
||||||
uri := spn.URI()
|
uri := spn.URI()
|
||||||
filename := uri.Filename()
|
filename := uri.Filename()
|
||||||
|
@ -365,7 +368,7 @@ func (r *runner) Import(t *testing.T, data tests.Imports) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Definition(t *testing.T, data tests.Definitions) {
|
func (r *runner) Definition(t *testing.T, data tests.Definitions) {
|
||||||
ctx := context.Background()
|
ctx := r.ctx
|
||||||
for _, d := range data {
|
for _, d := range data {
|
||||||
f, err := r.view.GetFile(ctx, d.Src.URI())
|
f, err := r.view.GetFile(ctx, d.Src.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -407,7 +410,7 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Highlight(t *testing.T, data tests.Highlights) {
|
func (r *runner) Highlight(t *testing.T, data tests.Highlights) {
|
||||||
ctx := context.Background()
|
ctx := r.ctx
|
||||||
for name, locations := range data {
|
for name, locations := range data {
|
||||||
src := locations[0]
|
src := locations[0]
|
||||||
f, err := r.view.GetFile(ctx, src.URI())
|
f, err := r.view.GetFile(ctx, src.URI())
|
||||||
|
@ -432,7 +435,7 @@ func (r *runner) Highlight(t *testing.T, data tests.Highlights) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Reference(t *testing.T, data tests.References) {
|
func (r *runner) Reference(t *testing.T, data tests.References) {
|
||||||
ctx := context.Background()
|
ctx := r.ctx
|
||||||
for src, itemList := range data {
|
for src, itemList := range data {
|
||||||
f, err := r.view.GetFile(ctx, src.URI())
|
f, err := r.view.GetFile(ctx, src.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -478,7 +481,7 @@ func (r *runner) Reference(t *testing.T, data tests.References) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Rename(t *testing.T, data tests.Renames) {
|
func (r *runner) Rename(t *testing.T, data tests.Renames) {
|
||||||
ctx := context.Background()
|
ctx := r.ctx
|
||||||
for spn, newText := range data {
|
for spn, newText := range data {
|
||||||
tag := fmt.Sprintf("%s-rename", newText)
|
tag := fmt.Sprintf("%s-rename", newText)
|
||||||
|
|
||||||
|
@ -489,11 +492,11 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
|
||||||
tok := f.GetToken(ctx)
|
tok := f.GetToken(ctx)
|
||||||
pos := tok.Pos(spn.Start().Offset())
|
pos := tok.Pos(spn.Start().Offset())
|
||||||
|
|
||||||
ident, err := source.Identifier(context.Background(), r.view, f.(source.GoFile), pos)
|
ident, err := source.Identifier(r.ctx, r.view, f.(source.GoFile), pos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
changes, err := ident.Rename(context.Background(), newText)
|
changes, err := ident.Rename(r.ctx, newText)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
renamed := string(r.data.Golden(tag, spn.URI().Filename(), func() ([]byte, error) {
|
renamed := string(r.data.Golden(tag, spn.URI().Filename(), func() ([]byte, error) {
|
||||||
return []byte(err.Error()), nil
|
return []byte(err.Error()), nil
|
||||||
|
@ -568,7 +571,7 @@ func sortSourceTextEdits(d []source.TextEdit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Symbol(t *testing.T, data tests.Symbols) {
|
func (r *runner) Symbol(t *testing.T, data tests.Symbols) {
|
||||||
ctx := context.Background()
|
ctx := r.ctx
|
||||||
for uri, expectedSymbols := range data {
|
for uri, expectedSymbols := range data {
|
||||||
f, err := r.view.GetFile(ctx, uri)
|
f, err := r.view.GetFile(ctx, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -632,7 +635,7 @@ func summarizeSymbols(i int, want []source.Symbol, got []source.Symbol, reason s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
|
func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
|
||||||
ctx := context.Background()
|
ctx := r.ctx
|
||||||
for spn, expectedSignature := range data {
|
for spn, expectedSignature := range data {
|
||||||
f, err := r.view.GetFile(ctx, spn.URI())
|
f, err := r.view.GetFile(ctx, spn.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -129,7 +129,7 @@ type Cache interface {
|
||||||
// A session may have many active views at any given time.
|
// A session may have many active views at any given time.
|
||||||
type Session interface {
|
type Session interface {
|
||||||
// NewView creates a new View and returns it.
|
// NewView creates a new View and returns it.
|
||||||
NewView(name string, folder span.URI) View
|
NewView(ctx context.Context, name string, folder span.URI) View
|
||||||
|
|
||||||
// Cache returns the cache that created this session.
|
// Cache returns the cache that created this session.
|
||||||
Cache() Cache
|
Cache() Cache
|
||||||
|
|
|
@ -127,6 +127,10 @@ type Golden struct {
|
||||||
Modified bool
|
Modified bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Context(t testing.TB) context.Context {
|
||||||
|
return context.Background()
|
||||||
|
}
|
||||||
|
|
||||||
func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
|
func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
@ -193,7 +197,7 @@ func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
|
||||||
// Merge the exported.Config with the view.Config.
|
// Merge the exported.Config with the view.Config.
|
||||||
data.Config = *data.Exported.Config
|
data.Config = *data.Exported.Config
|
||||||
data.Config.Fset = token.NewFileSet()
|
data.Config.Fset = token.NewFileSet()
|
||||||
data.Config.Context = context.Background()
|
data.Config.Context = Context(nil)
|
||||||
data.Config.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
|
data.Config.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
|
||||||
panic("ParseFile should not be called")
|
panic("ParseFile should not be called")
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,6 @@ func (s *Server) changeFolders(ctx context.Context, event protocol.WorkspaceFold
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) addView(ctx context.Context, name string, uri span.URI) error {
|
func (s *Server) addView(ctx context.Context, name string, uri span.URI) error {
|
||||||
s.session.NewView(name, uri)
|
s.session.NewView(ctx, name, uri)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +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 memoize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// detatch returns a context that keeps all the values of its parent context
|
|
||||||
// but detatches from the cancellation and error handling.
|
|
||||||
func detatchContext(ctx context.Context) context.Context { return detatchedContext{ctx} }
|
|
||||||
|
|
||||||
type detatchedContext struct{ parent context.Context }
|
|
||||||
|
|
||||||
func (v detatchedContext) Deadline() (time.Time, bool) { return time.Time{}, false }
|
|
||||||
func (v detatchedContext) Done() <-chan struct{} { return nil }
|
|
||||||
func (v detatchedContext) Err() error { return nil }
|
|
||||||
func (v detatchedContext) Value(key interface{}) interface{} { return v.parent.Value(key) }
|
|
|
@ -19,6 +19,8 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/xcontext"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Store binds keys to functions, returning handles that can be used to access
|
// Store binds keys to functions, returning handles that can be used to access
|
||||||
|
@ -180,7 +182,7 @@ func (e *entry) get(ctx context.Context, f Function) (interface{}, bool) {
|
||||||
// Use the background context to avoid canceling the function.
|
// Use the background context to avoid canceling the function.
|
||||||
// The function cannot be canceled even if the context is canceled
|
// The function cannot be canceled even if the context is canceled
|
||||||
// because multiple goroutines may depend on it.
|
// because multiple goroutines may depend on it.
|
||||||
value = f(detatchContext(ctx))
|
value = f(xcontext.Detach(ctx))
|
||||||
|
|
||||||
// The function has completed. Update the value in the entry.
|
// The function has completed. Update the value in the entry.
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
// 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 xcontext is a package to offer the extra functionality we need
|
||||||
|
// from contexts that is not available from the standard context package.
|
||||||
|
package xcontext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Detach returns a context that keeps all the values of its parent context
|
||||||
|
// but detaches from the cancellation and error handling.
|
||||||
|
func Detach(ctx context.Context) context.Context { return detachedContext{ctx} }
|
||||||
|
|
||||||
|
type detachedContext struct{ parent context.Context }
|
||||||
|
|
||||||
|
func (v detachedContext) Deadline() (time.Time, bool) { return time.Time{}, false }
|
||||||
|
func (v detachedContext) Done() <-chan struct{} { return nil }
|
||||||
|
func (v detachedContext) Err() error { return nil }
|
||||||
|
func (v detachedContext) Value(key interface{}) interface{} { return v.parent.Value(key) }
|
Loading…
Reference in New Issue