mirror of
https://github.com/golang/go
synced 2024-11-18 11:04:42 -07:00
internal/lsp: use one context throughout completion
I originally made this change to see if it would help with the timeouts. Based on the TryBot results, it doesn't -- but I still think it's more correct to have the contexts this way. It was my mistake to put the context on the completer in the first place, I think. Change-Id: Ib77c8f0ac0b0d0922b82db4120820fb96cb664f4 Reviewed-on: https://go-review.googlesource.com/c/tools/+/227303 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
parent
7db14c95bf
commit
ee2abff5cf
@ -136,9 +136,6 @@ type completer struct {
|
||||
qf types.Qualifier
|
||||
opts *completionOptions
|
||||
|
||||
// ctx is the context associated with this completion request.
|
||||
ctx context.Context
|
||||
|
||||
// filename is the name of the file associated with this completion request.
|
||||
filename string
|
||||
|
||||
@ -247,13 +244,6 @@ func (p Selection) Suffix() string {
|
||||
return p.content[p.cursor-p.spanRange.Start:]
|
||||
}
|
||||
|
||||
func (c *completer) deepCompletionContext() (context.Context, context.CancelFunc) {
|
||||
if c.opts.budget == 0 {
|
||||
return context.WithCancel(c.ctx)
|
||||
}
|
||||
return context.WithDeadline(c.ctx, c.startTime.Add(c.opts.budget))
|
||||
}
|
||||
|
||||
func (c *completer) setSurrounding(ident *ast.Ident) {
|
||||
if c.surrounding != nil {
|
||||
return
|
||||
@ -292,7 +282,7 @@ func (c *completer) getSurrounding() *Selection {
|
||||
|
||||
// found adds a candidate completion. We will also search through the object's
|
||||
// members for more candidates.
|
||||
func (c *completer) found(cand candidate) {
|
||||
func (c *completer) found(ctx context.Context, cand candidate) {
|
||||
obj := cand.obj
|
||||
|
||||
if obj.Pkg() != nil && obj.Pkg() != c.pkg.GetTypes() && !obj.Exported() {
|
||||
@ -341,7 +331,7 @@ func (c *completer) found(cand candidate) {
|
||||
|
||||
// We only care about named types (i.e. don't want builtin types).
|
||||
if _, isNamed := obj.Type().(*types.Named); isNamed {
|
||||
c.literal(obj.Type(), cand.imp)
|
||||
c.literal(ctx, obj.Type(), cand.imp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -370,13 +360,13 @@ func (c *completer) found(cand candidate) {
|
||||
// Avoid calling c.item() for deep candidates that wouldn't be in the top
|
||||
// MaxDeepCompletions anyway.
|
||||
if !c.inDeepCompletion() || c.deepState.isHighScore(cand.score) {
|
||||
if item, err := c.item(cand); err == nil {
|
||||
if item, err := c.item(ctx, cand); err == nil {
|
||||
c.items = append(c.items, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.deepSearch(cand)
|
||||
c.deepSearch(ctx, cand)
|
||||
}
|
||||
|
||||
// candidate represents a completion candidate.
|
||||
@ -482,7 +472,6 @@ func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, protoPos
|
||||
pkg: pkg,
|
||||
snapshot: snapshot,
|
||||
qf: qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo()),
|
||||
ctx: ctx,
|
||||
filename: fh.Identity().URI.Filename(),
|
||||
file: file,
|
||||
path: path,
|
||||
@ -512,32 +501,40 @@ func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, protoPos
|
||||
c.deepState.maxDepth = -1
|
||||
}
|
||||
|
||||
var cancel context.CancelFunc
|
||||
if c.opts.budget == 0 {
|
||||
ctx, cancel = context.WithCancel(ctx)
|
||||
} else {
|
||||
ctx, cancel = context.WithDeadline(ctx, c.startTime.Add(c.opts.budget))
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
if surrounding := c.containingIdent(src); surrounding != nil {
|
||||
c.setSurrounding(surrounding)
|
||||
}
|
||||
|
||||
c.inference = expectedCandidate(c)
|
||||
c.inference = expectedCandidate(ctx, c)
|
||||
|
||||
defer c.sortItems()
|
||||
|
||||
// If we're inside a comment return comment completions
|
||||
for _, comment := range file.Comments {
|
||||
if comment.Pos() < rng.Start && rng.Start <= comment.End() {
|
||||
c.populateCommentCompletions(comment)
|
||||
c.populateCommentCompletions(ctx, comment)
|
||||
return c.items, c.getSurrounding(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Struct literals are handled entirely separately.
|
||||
if c.wantStructFieldCompletions() {
|
||||
if err := c.structLiteralFieldName(); err != nil {
|
||||
if err := c.structLiteralFieldName(ctx); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return c.items, c.getSurrounding(), nil
|
||||
}
|
||||
|
||||
if lt := c.wantLabelCompletion(); lt != labelNone {
|
||||
c.labels(lt)
|
||||
c.labels(ctx, lt)
|
||||
return c.items, c.getSurrounding(), nil
|
||||
}
|
||||
|
||||
@ -555,7 +552,7 @@ func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, protoPos
|
||||
case *ast.Ident:
|
||||
// Is this the Sel part of a selector?
|
||||
if sel, ok := path[1].(*ast.SelectorExpr); ok && sel.Sel == n {
|
||||
if err := c.selector(sel); err != nil {
|
||||
if err := c.selector(ctx, sel); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return c.items, c.getSurrounding(), nil
|
||||
@ -573,19 +570,19 @@ func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, protoPos
|
||||
return nil, nil, ErrIsDefinition{objStr: objStr}
|
||||
}
|
||||
}
|
||||
if err := c.lexical(); err != nil {
|
||||
if err := c.lexical(ctx); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// The function name hasn't been typed yet, but the parens are there:
|
||||
// recv.‸(arg)
|
||||
case *ast.TypeAssertExpr:
|
||||
// Create a fake selector expression.
|
||||
if err := c.selector(&ast.SelectorExpr{X: n.X}); err != nil {
|
||||
if err := c.selector(ctx, &ast.SelectorExpr{X: n.X}); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
case *ast.SelectorExpr:
|
||||
if err := c.selector(n); err != nil {
|
||||
if err := c.selector(ctx, n); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@ -595,7 +592,7 @@ func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, protoPos
|
||||
|
||||
default:
|
||||
// fallback to lexical completions
|
||||
if err := c.lexical(); err != nil {
|
||||
if err := c.lexical(ctx); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
@ -687,7 +684,7 @@ func (c *completer) emptySwitchStmt() bool {
|
||||
|
||||
// populateCommentCompletions yields completions for an exported
|
||||
// variable immediately preceding comment.
|
||||
func (c *completer) populateCommentCompletions(comment *ast.CommentGroup) {
|
||||
func (c *completer) populateCommentCompletions(ctx context.Context, comment *ast.CommentGroup) {
|
||||
|
||||
// Using the comment position find the line after
|
||||
fset := c.snapshot.View().Session().Cache().FileSet()
|
||||
@ -720,7 +717,7 @@ func (c *completer) populateCommentCompletions(comment *ast.CommentGroup) {
|
||||
}
|
||||
|
||||
exportedVar := c.pkg.GetTypesInfo().ObjectOf(name)
|
||||
c.found(candidate{obj: exportedVar, score: stdScore})
|
||||
c.found(ctx, candidate{obj: exportedVar, score: stdScore})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -748,11 +745,11 @@ const (
|
||||
)
|
||||
|
||||
// selector finds completions for the specified selector expression.
|
||||
func (c *completer) selector(sel *ast.SelectorExpr) error {
|
||||
func (c *completer) selector(ctx context.Context, sel *ast.SelectorExpr) error {
|
||||
// Is sel a qualified identifier?
|
||||
if id, ok := sel.X.(*ast.Ident); ok {
|
||||
if pkgName, ok := c.pkg.GetTypesInfo().Uses[id].(*types.PkgName); ok {
|
||||
c.packageMembers(pkgName.Imported(), stdScore, nil)
|
||||
c.packageMembers(ctx, pkgName.Imported(), stdScore, nil)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -760,21 +757,21 @@ func (c *completer) selector(sel *ast.SelectorExpr) error {
|
||||
// Invariant: sel is a true selector.
|
||||
tv, ok := c.pkg.GetTypesInfo().Types[sel.X]
|
||||
if ok {
|
||||
return c.methodsAndFields(tv.Type, tv.Addressable(), nil)
|
||||
return c.methodsAndFields(ctx, tv.Type, tv.Addressable(), nil)
|
||||
}
|
||||
|
||||
// Try unimported packages.
|
||||
if id, ok := sel.X.(*ast.Ident); ok && c.opts.unimported {
|
||||
if err := c.unimportedMembers(id); err != nil {
|
||||
if err := c.unimportedMembers(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *completer) unimportedMembers(id *ast.Ident) error {
|
||||
func (c *completer) unimportedMembers(ctx context.Context, id *ast.Ident) error {
|
||||
// Try loaded packages first. They're relevant, fast, and fully typed.
|
||||
known, err := c.snapshot.CachedImportPaths(c.ctx)
|
||||
known, err := c.snapshot.CachedImportPaths(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -789,8 +786,8 @@ func (c *completer) unimportedMembers(id *ast.Ident) error {
|
||||
|
||||
var relevances map[string]int
|
||||
if len(paths) != 0 {
|
||||
c.snapshot.View().RunProcessEnvFunc(c.ctx, func(opts *imports.Options) error {
|
||||
relevances = imports.ScoreImportPaths(c.ctx, opts.Env, paths)
|
||||
c.snapshot.View().RunProcessEnvFunc(ctx, func(opts *imports.Options) error {
|
||||
relevances = imports.ScoreImportPaths(ctx, opts.Env, paths)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@ -807,14 +804,15 @@ func (c *completer) unimportedMembers(id *ast.Ident) error {
|
||||
if imports.ImportPathToAssumedName(path) != pkg.GetTypes().Name() {
|
||||
imp.name = pkg.GetTypes().Name()
|
||||
}
|
||||
c.packageMembers(pkg.GetTypes(), stdScore+.01*float64(relevance), imp)
|
||||
c.packageMembers(ctx, pkg.GetTypes(), stdScore+.01*float64(relevance), imp)
|
||||
if len(c.items) >= unimportedMemberTarget {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := c.deepCompletionContext()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
var mu sync.Mutex
|
||||
add := func(pkgExport imports.PackageExport) {
|
||||
mu.Lock()
|
||||
@ -827,7 +825,7 @@ func (c *completer) unimportedMembers(id *ast.Ident) error {
|
||||
pkg := types.NewPackage(pkgExport.Fix.StmtInfo.ImportPath, pkgExport.Fix.IdentName)
|
||||
for _, export := range pkgExport.Exports {
|
||||
score := stdScore + 0.01*float64(pkgExport.Fix.Relevance)
|
||||
c.found(candidate{
|
||||
c.found(ctx, candidate{
|
||||
obj: types.NewVar(0, pkg, export, nil),
|
||||
score: score,
|
||||
imp: &importInfo{
|
||||
@ -845,11 +843,11 @@ func (c *completer) unimportedMembers(id *ast.Ident) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (c *completer) packageMembers(pkg *types.Package, score float64, imp *importInfo) {
|
||||
func (c *completer) packageMembers(ctx context.Context, pkg *types.Package, score float64, imp *importInfo) {
|
||||
scope := pkg.Scope()
|
||||
for _, name := range scope.Names() {
|
||||
obj := scope.Lookup(name)
|
||||
c.found(candidate{
|
||||
c.found(ctx, candidate{
|
||||
obj: obj,
|
||||
score: score,
|
||||
imp: imp,
|
||||
@ -858,7 +856,7 @@ func (c *completer) packageMembers(pkg *types.Package, score float64, imp *impor
|
||||
}
|
||||
}
|
||||
|
||||
func (c *completer) methodsAndFields(typ types.Type, addressable bool, imp *importInfo) error {
|
||||
func (c *completer) methodsAndFields(ctx context.Context, typ types.Type, addressable bool, imp *importInfo) error {
|
||||
mset := c.methodSetCache[methodSetKey{typ, addressable}]
|
||||
if mset == nil {
|
||||
if addressable && !types.IsInterface(typ) && !isPointer(typ) {
|
||||
@ -872,7 +870,7 @@ func (c *completer) methodsAndFields(typ types.Type, addressable bool, imp *impo
|
||||
}
|
||||
|
||||
for i := 0; i < mset.Len(); i++ {
|
||||
c.found(candidate{
|
||||
c.found(ctx, candidate{
|
||||
obj: mset.At(i).Obj(),
|
||||
score: stdScore,
|
||||
imp: imp,
|
||||
@ -882,7 +880,7 @@ func (c *completer) methodsAndFields(typ types.Type, addressable bool, imp *impo
|
||||
|
||||
// Add fields of T.
|
||||
eachField(typ, func(v *types.Var) {
|
||||
c.found(candidate{
|
||||
c.found(ctx, candidate{
|
||||
obj: v,
|
||||
score: stdScore - 0.01,
|
||||
imp: imp,
|
||||
@ -894,7 +892,7 @@ func (c *completer) methodsAndFields(typ types.Type, addressable bool, imp *impo
|
||||
}
|
||||
|
||||
// lexical finds completions in the lexical environment.
|
||||
func (c *completer) lexical() error {
|
||||
func (c *completer) lexical(ctx context.Context) error {
|
||||
var scopes []*types.Scope // scopes[i], where i<len(path), is the possibly nil Scope of path[i].
|
||||
for _, n := range c.path {
|
||||
// Include *FuncType scope if pos is inside the function body.
|
||||
@ -978,7 +976,7 @@ func (c *completer) lexical() error {
|
||||
// If we haven't already added a candidate for an object with this name.
|
||||
if _, ok := seen[obj.Name()]; !ok {
|
||||
seen[obj.Name()] = struct{}{}
|
||||
c.found(candidate{
|
||||
c.found(ctx, candidate{
|
||||
obj: obj,
|
||||
score: score,
|
||||
addressable: isVar(obj),
|
||||
@ -1007,7 +1005,7 @@ func (c *completer) lexical() error {
|
||||
if imports.ImportPathToAssumedName(pkg.Path()) != pkg.Name() {
|
||||
imp.name = pkg.Name()
|
||||
}
|
||||
c.found(candidate{
|
||||
c.found(ctx, candidate{
|
||||
obj: obj,
|
||||
score: stdScore,
|
||||
imp: imp,
|
||||
@ -1018,7 +1016,7 @@ func (c *completer) lexical() error {
|
||||
}
|
||||
|
||||
if c.opts.unimported {
|
||||
if err := c.unimportedPackages(seen); err != nil {
|
||||
if err := c.unimportedPackages(ctx, seen); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -1036,7 +1034,7 @@ func (c *completer) lexical() error {
|
||||
// our expected type is "[]int", this will add a candidate of
|
||||
// "[]int{}".
|
||||
if _, named := t.(*types.Named); !named {
|
||||
c.literal(t, nil)
|
||||
c.literal(ctx, t, nil)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1046,17 +1044,14 @@ func (c *completer) lexical() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *completer) unimportedPackages(seen map[string]struct{}) error {
|
||||
ctx, cancel := c.deepCompletionContext()
|
||||
defer cancel()
|
||||
|
||||
prefix := ""
|
||||
func (c *completer) unimportedPackages(ctx context.Context, seen map[string]struct{}) error {
|
||||
var prefix string
|
||||
if c.surrounding != nil {
|
||||
prefix = c.surrounding.Prefix()
|
||||
}
|
||||
initialItemCount := len(c.items)
|
||||
|
||||
known, err := c.snapshot.CachedImportPaths(c.ctx)
|
||||
known, err := c.snapshot.CachedImportPaths(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1071,7 +1066,7 @@ func (c *completer) unimportedPackages(seen map[string]struct{}) error {
|
||||
var relevances map[string]int
|
||||
if len(paths) != 0 {
|
||||
c.snapshot.View().RunProcessEnvFunc(ctx, func(opts *imports.Options) error {
|
||||
relevances = imports.ScoreImportPaths(c.ctx, opts.Env, paths)
|
||||
relevances = imports.ScoreImportPaths(ctx, opts.Env, paths)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@ -1086,7 +1081,7 @@ func (c *completer) unimportedPackages(seen map[string]struct{}) error {
|
||||
imp.name = pkg.GetTypes().Name()
|
||||
}
|
||||
score := 0.01 * float64(relevance)
|
||||
c.found(candidate{
|
||||
c.found(ctx, candidate{
|
||||
obj: types.NewPkgName(0, nil, pkg.GetTypes().Name(), pkg.GetTypes()),
|
||||
score: score,
|
||||
imp: imp,
|
||||
@ -1096,6 +1091,9 @@ func (c *completer) unimportedPackages(seen map[string]struct{}) error {
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
var mu sync.Mutex
|
||||
add := func(pkg imports.ImportFix) {
|
||||
mu.Lock()
|
||||
@ -1115,7 +1113,7 @@ func (c *completer) unimportedPackages(seen map[string]struct{}) error {
|
||||
// multiple packages of the same name as completion suggestions, since
|
||||
// only one will be chosen.
|
||||
obj := types.NewPkgName(0, nil, pkg.IdentName, types.NewPackage(pkg.StmtInfo.ImportPath, pkg.IdentName))
|
||||
c.found(candidate{
|
||||
c.found(ctx, candidate{
|
||||
obj: obj,
|
||||
score: score,
|
||||
imp: &importInfo{
|
||||
@ -1163,7 +1161,7 @@ func (c *completer) inConstDecl() bool {
|
||||
}
|
||||
|
||||
// structLiteralFieldName finds completions for struct field names inside a struct literal.
|
||||
func (c *completer) structLiteralFieldName() error {
|
||||
func (c *completer) structLiteralFieldName(ctx context.Context) error {
|
||||
clInfo := c.enclosingCompositeLiteral
|
||||
|
||||
// Mark fields of the composite literal that have already been set,
|
||||
@ -1190,7 +1188,7 @@ func (c *completer) structLiteralFieldName() error {
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
field := t.Field(i)
|
||||
if !addedFields[field] {
|
||||
c.found(candidate{
|
||||
c.found(ctx, candidate{
|
||||
obj: field,
|
||||
score: highScore,
|
||||
})
|
||||
@ -1200,10 +1198,10 @@ func (c *completer) structLiteralFieldName() error {
|
||||
// Add lexical completions if we aren't certain we are in the key part of a
|
||||
// key-value pair.
|
||||
if clInfo.maybeInFieldName {
|
||||
return c.lexical()
|
||||
return c.lexical(ctx)
|
||||
}
|
||||
default:
|
||||
return c.lexical()
|
||||
return c.lexical(ctx)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -1468,7 +1466,7 @@ type typeNameInference struct {
|
||||
|
||||
// expectedCandidate returns information about the expected candidate
|
||||
// for an expression at the query position.
|
||||
func expectedCandidate(c *completer) (inf candidateInference) {
|
||||
func expectedCandidate(ctx context.Context, c *completer) (inf candidateInference) {
|
||||
inf.typeName = expectTypeName(c)
|
||||
|
||||
if c.enclosingCompositeLiteral != nil {
|
||||
@ -1592,7 +1590,7 @@ Nodes:
|
||||
// inferred type from its parent node.
|
||||
defer func() {
|
||||
inf = c.builtinArgType(obj, node, inf)
|
||||
inf.objKind = c.builtinArgKind(obj, node)
|
||||
inf.objKind = c.builtinArgKind(ctx, obj, node)
|
||||
}()
|
||||
|
||||
// The expected type of builtin arguments like append() is
|
||||
|
@ -5,6 +5,7 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go/ast"
|
||||
"go/types"
|
||||
)
|
||||
@ -12,8 +13,8 @@ import (
|
||||
// builtinArgKind determines the expected object kind for a builtin
|
||||
// argument. It attempts to use the AST hints from builtin.go where
|
||||
// possible.
|
||||
func (c *completer) builtinArgKind(obj types.Object, call *ast.CallExpr) objKind {
|
||||
astObj, err := c.snapshot.View().LookupBuiltin(c.ctx, obj.Name())
|
||||
func (c *completer) builtinArgKind(ctx context.Context, obj types.Object, call *ast.CallExpr) objKind {
|
||||
astObj, err := c.snapshot.View().LookupBuiltin(ctx, obj.Name())
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
@ -23,12 +23,12 @@ import (
|
||||
)
|
||||
|
||||
// formatCompletion creates a completion item for a given candidate.
|
||||
func (c *completer) item(cand candidate) (CompletionItem, error) {
|
||||
func (c *completer) item(ctx context.Context, cand candidate) (CompletionItem, error) {
|
||||
obj := cand.obj
|
||||
|
||||
// Handle builtin types separately.
|
||||
if obj.Parent() == types.Universe {
|
||||
return c.formatBuiltin(cand), nil
|
||||
return c.formatBuiltin(ctx, cand), nil
|
||||
}
|
||||
|
||||
var (
|
||||
@ -46,7 +46,7 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
|
||||
// expandFuncCall mutates the completion label, detail, and snippet
|
||||
// to that of an invocation of sig.
|
||||
expandFuncCall := func(sig *types.Signature) {
|
||||
params := formatParams(c.ctx, c.snapshot, c.pkg, sig, c.qf)
|
||||
params := formatParams(ctx, c.snapshot, c.pkg, sig, c.qf)
|
||||
snip = c.functionCallSnippet(label, params)
|
||||
results, writeParens := formatResults(sig.Results(), c.qf)
|
||||
detail = "func" + formatFunction(params, results, writeParens)
|
||||
@ -67,7 +67,7 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
|
||||
detail = "struct{...}" // for anonymous structs
|
||||
} else if obj.IsField() {
|
||||
var err error
|
||||
detail, err = formatFieldType(c.ctx, c.snapshot, c.pkg, obj)
|
||||
detail, err = formatFieldType(ctx, c.snapshot, c.pkg, obj)
|
||||
if err != nil {
|
||||
detail = types.TypeString(obj.Type(), c.qf)
|
||||
}
|
||||
@ -115,7 +115,7 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
|
||||
// If this candidate needs an additional import statement,
|
||||
// add the additional text edits needed.
|
||||
if cand.imp != nil {
|
||||
addlEdits, err := c.importEdits(cand.imp)
|
||||
addlEdits, err := c.importEdits(ctx, cand.imp)
|
||||
if err != nil {
|
||||
return CompletionItem{}, err
|
||||
}
|
||||
@ -144,10 +144,9 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
|
||||
if sel := enclosingSelector(c.path, c.pos); sel != nil {
|
||||
edits, err := prependEdit(c.snapshot.View().Session().Cache().FileSet(), c.mapper, sel, prefixOp)
|
||||
if err != nil {
|
||||
event.Error(c.ctx, "error generating prefix edit", err)
|
||||
} else {
|
||||
protocolEdits = append(protocolEdits, edits...)
|
||||
return CompletionItem{}, err
|
||||
}
|
||||
protocolEdits = append(protocolEdits, edits...)
|
||||
} else {
|
||||
// If there is no selector, just stick the prefix at the start.
|
||||
insert = prefixOp + insert
|
||||
@ -190,13 +189,13 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
|
||||
if err != nil {
|
||||
return item, nil
|
||||
}
|
||||
ident, err := findIdentifier(c.ctx, c.snapshot, pkg, file, obj.Pos())
|
||||
ident, err := findIdentifier(ctx, c.snapshot, pkg, file, obj.Pos())
|
||||
if err != nil {
|
||||
return item, nil
|
||||
}
|
||||
hover, err := ident.Hover(c.ctx)
|
||||
hover, err := ident.Hover(ctx)
|
||||
if err != nil {
|
||||
event.Error(c.ctx, "failed to find Hover", err, tag.URI.Of(uri))
|
||||
event.Error(ctx, "failed to find Hover", err, tag.URI.Of(uri))
|
||||
return item, nil
|
||||
}
|
||||
item.Documentation = hover.Synopsis
|
||||
@ -207,7 +206,7 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
|
||||
}
|
||||
|
||||
// importEdits produces the text edits necessary to add the given import to the current file.
|
||||
func (c *completer) importEdits(imp *importInfo) ([]protocol.TextEdit, error) {
|
||||
func (c *completer) importEdits(ctx context.Context, imp *importInfo) ([]protocol.TextEdit, error) {
|
||||
if imp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@ -223,7 +222,7 @@ func (c *completer) importEdits(imp *importInfo) ([]protocol.TextEdit, error) {
|
||||
return nil, errors.Errorf("building import completion for %v: no ParseGoHandle for %s", imp.importPath, c.filename)
|
||||
}
|
||||
|
||||
return computeOneImportFixEdits(c.ctx, c.snapshot.View(), ph, &imports.ImportFix{
|
||||
return computeOneImportFixEdits(ctx, c.snapshot.View(), ph, &imports.ImportFix{
|
||||
StmtInfo: imports.ImportInfo{
|
||||
ImportPath: imp.importPath,
|
||||
Name: imp.name,
|
||||
@ -233,7 +232,7 @@ func (c *completer) importEdits(imp *importInfo) ([]protocol.TextEdit, error) {
|
||||
})
|
||||
}
|
||||
|
||||
func (c *completer) formatBuiltin(cand candidate) CompletionItem {
|
||||
func (c *completer) formatBuiltin(ctx context.Context, cand candidate) CompletionItem {
|
||||
obj := cand.obj
|
||||
item := CompletionItem{
|
||||
Label: obj.Name(),
|
||||
@ -245,17 +244,17 @@ func (c *completer) formatBuiltin(cand candidate) CompletionItem {
|
||||
item.Kind = protocol.ConstantCompletion
|
||||
case *types.Builtin:
|
||||
item.Kind = protocol.FunctionCompletion
|
||||
astObj, err := c.snapshot.View().LookupBuiltin(c.ctx, obj.Name())
|
||||
astObj, err := c.snapshot.View().LookupBuiltin(ctx, obj.Name())
|
||||
if err != nil {
|
||||
event.Error(c.ctx, "no builtin package", err)
|
||||
event.Error(ctx, "no builtin package", err)
|
||||
break
|
||||
}
|
||||
decl, ok := astObj.Decl.(*ast.FuncDecl)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
params, _ := formatFieldList(c.ctx, c.snapshot.View(), decl.Type.Params)
|
||||
results, writeResultParens := formatFieldList(c.ctx, c.snapshot.View(), decl.Type.Results)
|
||||
params, _ := formatFieldList(ctx, c.snapshot.View(), decl.Type.Params)
|
||||
results, writeResultParens := formatFieldList(ctx, c.snapshot.View(), decl.Type.Results)
|
||||
item.Label = obj.Name()
|
||||
item.Detail = "func" + formatFunction(params, results, writeResultParens)
|
||||
item.snippet = c.functionCallSnippet(obj.Name(), params)
|
||||
|
@ -5,6 +5,7 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"math"
|
||||
@ -49,7 +50,7 @@ func takesLabel(n ast.Node) labelType {
|
||||
|
||||
// labels adds completion items for labels defined in the enclosing
|
||||
// function.
|
||||
func (c *completer) labels(lt labelType) {
|
||||
func (c *completer) labels(ctx context.Context, lt labelType) {
|
||||
if c.enclosingFunc == nil {
|
||||
return
|
||||
}
|
||||
@ -57,7 +58,7 @@ func (c *completer) labels(lt labelType) {
|
||||
addLabel := func(score float64, l *ast.LabeledStmt) {
|
||||
labelObj := c.pkg.GetTypesInfo().ObjectOf(l.Label)
|
||||
if labelObj != nil {
|
||||
c.found(candidate{obj: labelObj, score: score})
|
||||
c.found(ctx, candidate{obj: labelObj, score: score})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
@ -19,7 +20,7 @@ import (
|
||||
|
||||
// literal generates composite literal, function literal, and make()
|
||||
// completion items.
|
||||
func (c *completer) literal(literalType types.Type, imp *importInfo) {
|
||||
func (c *completer) literal(ctx context.Context, literalType types.Type, imp *importInfo) {
|
||||
if !c.opts.literal {
|
||||
return
|
||||
}
|
||||
@ -101,9 +102,9 @@ func (c *completer) literal(literalType types.Type, imp *importInfo) {
|
||||
matchName = types.TypeString(t.Elem(), qf)
|
||||
}
|
||||
|
||||
addlEdits, err := c.importEdits(imp)
|
||||
addlEdits, err := c.importEdits(ctx, imp)
|
||||
if err != nil {
|
||||
event.Error(c.ctx, "error adding import for literal candidate", err)
|
||||
event.Error(ctx, "error adding import for literal candidate", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -116,7 +117,7 @@ func (c *completer) literal(literalType types.Type, imp *importInfo) {
|
||||
// "foo.&Bar{}".
|
||||
edits, err := prependEdit(c.snapshot.View().Session().Cache().FileSet(), c.mapper, sel, "&")
|
||||
if err != nil {
|
||||
event.Error(c.ctx, "error making edit for literal pointer completion", err)
|
||||
event.Error(ctx, "error making edit for literal pointer completion", err)
|
||||
return
|
||||
}
|
||||
addlEdits = append(addlEdits, edits...)
|
||||
|
@ -5,6 +5,7 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go/types"
|
||||
"strings"
|
||||
"time"
|
||||
@ -162,7 +163,7 @@ func (c *completer) shouldPrune() bool {
|
||||
|
||||
// deepSearch searches through cand's subordinate objects for more
|
||||
// completion items.
|
||||
func (c *completer) deepSearch(cand candidate) {
|
||||
func (c *completer) deepSearch(ctx context.Context, cand candidate) {
|
||||
if c.deepState.maxDepth == 0 {
|
||||
return
|
||||
}
|
||||
@ -198,7 +199,7 @@ func (c *completer) deepSearch(cand candidate) {
|
||||
// the deep chain.
|
||||
c.deepState.push(obj, true)
|
||||
// The result of a function call is not addressable.
|
||||
c.methodsAndFields(sig.Results().At(0).Type(), false, cand.imp)
|
||||
c.methodsAndFields(ctx, sig.Results().At(0).Type(), false, cand.imp)
|
||||
c.deepState.pop()
|
||||
}
|
||||
}
|
||||
@ -208,9 +209,9 @@ func (c *completer) deepSearch(cand candidate) {
|
||||
|
||||
switch obj := obj.(type) {
|
||||
case *types.PkgName:
|
||||
c.packageMembers(obj.Imported(), stdScore, cand.imp)
|
||||
c.packageMembers(ctx, obj.Imported(), stdScore, cand.imp)
|
||||
default:
|
||||
c.methodsAndFields(obj.Type(), cand.addressable, cand.imp)
|
||||
c.methodsAndFields(ctx, obj.Type(), cand.addressable, cand.imp)
|
||||
}
|
||||
|
||||
// Pop the object off our search stack.
|
||||
|
Loading…
Reference in New Issue
Block a user