Skip to content

Commit c43c25c

Browse files
committed
internal/lsp/source: run deep completions before unimported completions
Unimported completions are expensive and can use up a large portion of completion budget just to find initial deep search candidates. This change moves these expensive operations which search through the module cache to after normal deep completions so we search through more useful candidates first. Fixes golang/go#41434 Fixes golang/go#41665 Change-Id: I6f3963f8c65c1a97833a35738d2e96420de2f6ee Reviewed-on: https://go-review.googlesource.com/c/tools/+/257974 Run-TryBot: Danish Dua <danishdua@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com> Trust: Danish Dua <danishdua@google.com>
1 parent f1e51e6 commit c43c25c

File tree

2 files changed

+36
-14
lines changed

2 files changed

+36
-14
lines changed

internal/lsp/source/completion/completion.go

+25-5
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,11 @@ type completer struct {
179179
// items is the list of completion items returned.
180180
items []CompletionItem
181181

182+
// completionCallbacks is a list of callbacks to collect completions that
183+
// require expensive operations. This includes operations where we search
184+
// through the entire module cache.
185+
completionCallbacks []func(opts *imports.Options) error
186+
182187
// surrounding describes the identifier surrounding the position.
183188
surrounding *Selection
184189

@@ -516,6 +521,17 @@ func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHan
516521

517522
// Deep search collected candidates and their members for more candidates.
518523
c.deepSearch(ctx)
524+
c.deepState.searchQueue = nil
525+
526+
for _, callback := range c.completionCallbacks {
527+
if err := c.snapshot.RunProcessEnvFunc(ctx, callback); err != nil {
528+
return nil, nil, err
529+
}
530+
}
531+
532+
// Search candidates populated by expensive operations like
533+
// unimportedMembers etc. for more completion items.
534+
c.deepSearch(ctx)
519535

520536
// Statement candidates offer an entire statement in certain contexts, as
521537
// opposed to a single object. Add statement candidates last because they
@@ -799,9 +815,10 @@ func (c *completer) populateImportCompletions(ctx context.Context, searchImport
799815
}
800816
}
801817

802-
return c.snapshot.RunProcessEnvFunc(ctx, func(opts *imports.Options) error {
818+
c.completionCallbacks = append(c.completionCallbacks, func(opts *imports.Options) error {
803819
return imports.GetImportPaths(ctx, searchImports, prefix, c.filename, c.pkg.GetTypes().Name(), opts.Env)
804820
})
821+
return nil
805822
}
806823

807824
// populateCommentCompletions yields completions for comments preceding or in declarations.
@@ -1126,7 +1143,6 @@ func (c *completer) unimportedMembers(ctx context.Context, id *ast.Ident) error
11261143
}
11271144

11281145
ctx, cancel := context.WithCancel(ctx)
1129-
defer cancel()
11301146

11311147
var mu sync.Mutex
11321148
add := func(pkgExport imports.PackageExport) {
@@ -1153,9 +1169,12 @@ func (c *completer) unimportedMembers(ctx context.Context, id *ast.Ident) error
11531169
cancel()
11541170
}
11551171
}
1156-
return c.snapshot.RunProcessEnvFunc(ctx, func(opts *imports.Options) error {
1172+
1173+
c.completionCallbacks = append(c.completionCallbacks, func(opts *imports.Options) error {
1174+
defer cancel()
11571175
return imports.GetPackageExports(ctx, add, id.Name, c.filename, c.pkg.GetTypes().Name(), opts.Env)
11581176
})
1177+
return nil
11591178
}
11601179

11611180
// unimportedScore returns a score for an unimported package that is generally
@@ -1422,7 +1441,6 @@ func (c *completer) unimportedPackages(ctx context.Context, seen map[string]stru
14221441
}
14231442

14241443
ctx, cancel := context.WithCancel(ctx)
1425-
defer cancel()
14261444

14271445
var mu sync.Mutex
14281446
add := func(pkg imports.ImportFix) {
@@ -1454,9 +1472,11 @@ func (c *completer) unimportedPackages(ctx context.Context, seen map[string]stru
14541472
})
14551473
count++
14561474
}
1457-
return c.snapshot.RunProcessEnvFunc(ctx, func(opts *imports.Options) error {
1475+
c.completionCallbacks = append(c.completionCallbacks, func(opts *imports.Options) error {
1476+
defer cancel()
14581477
return imports.GetAllCandidates(ctx, add, prefix, c.filename, c.pkg.GetTypes().Name(), opts.Env)
14591478
})
1479+
return nil
14601480
}
14611481

14621482
// alreadyImports reports whether f has an import with the specified path.

internal/lsp/source/completion/deep_completion.go

+11-9
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ type deepCompletionState struct {
2222
// enabled indicates wether deep completion is permitted.
2323
enabled bool
2424

25-
// queueClosed is used to disable adding new items to search queue once
26-
// we're running out of our time budget.
25+
// queueClosed is used to disable adding new sub-fields to search queue
26+
// once we're running out of our time budget.
2727
queueClosed bool
2828

2929
// searchQueue holds the current breadth first search queue.
@@ -158,14 +158,16 @@ outer:
158158
c.deepState.candidateCount++
159159
if c.opts.budget > 0 && c.deepState.candidateCount%100 == 0 {
160160
spent := float64(time.Since(c.startTime)) / float64(c.opts.budget)
161-
if spent > 1.0 {
161+
select {
162+
case <-ctx.Done():
162163
return
163-
}
164-
// If we are almost out of budgeted time, no further elements
165-
// should be added to the queue. This ensures remaining time is
166-
// used for processing current queue.
167-
if !c.deepState.queueClosed && spent >= 0.85 {
168-
c.deepState.queueClosed = true
164+
default:
165+
// If we are almost out of budgeted time, no further elements
166+
// should be added to the queue. This ensures remaining time is
167+
// used for processing current queue.
168+
if !c.deepState.queueClosed && spent >= 0.85 {
169+
c.deepState.queueClosed = true
170+
}
169171
}
170172
}
171173

0 commit comments

Comments
 (0)