internal/lsp/source: don't build low scoring workspace symbols
By refactoring the symbol resolution to defer symbol construction until
after scoring, we can avoid some unnecessary string allocation.
Benchmark (fastfuzzy "test" in x/tools): 21ms->17ms
Benchmark (fuzzy "test" in x/tools): 46ms->42ms
Benchmark (fastfuzzy "test" in kubernetes): 199ms->183ms
Change-Id: I9de72eb203c9971acc1afe89657976ce193b5a5d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/338696
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/source/workspace_symbol.go b/internal/lsp/source/workspace_symbol.go
index b717ed5..6dd8de9 100644
--- a/internal/lsp/source/workspace_symbol.go
+++ b/internal/lsp/source/workspace_symbol.go
@@ -69,17 +69,17 @@
// []string{"myType.field"} or []string{"myType.", "field"}.
//
// See the comment for symbolCollector for more information.
-type symbolizer func(name string, pkg Metadata, m matcherFunc) (string, float64)
+type symbolizer func(name string, pkg Metadata, m matcherFunc) ([]string, float64)
-func fullyQualifiedSymbolMatch(name string, pkg Metadata, matcher matcherFunc) (string, float64) {
+func fullyQualifiedSymbolMatch(name string, pkg Metadata, matcher matcherFunc) ([]string, float64) {
_, score := dynamicSymbolMatch(name, pkg, matcher)
if score > 0 {
- return pkg.PkgPath() + "." + name, score
+ return []string{pkg.PkgPath(), ".", name}, score
}
- return "", 0
+ return nil, 0
}
-func dynamicSymbolMatch(name string, pkg Metadata, matcher matcherFunc) (string, float64) {
+func dynamicSymbolMatch(name string, pkg Metadata, matcher matcherFunc) ([]string, float64) {
var score float64
endsInPkgName := strings.HasSuffix(pkg.PkgPath(), pkg.Name())
@@ -94,10 +94,10 @@
// If our match is contained entirely within the unqualified portion,
// just return that.
if idx >= nameStart {
- return name, score
+ return []string{name}, score
}
// Lower the score for matches that include the package name.
- return strings.Join(pkgQualified, ""), score * 0.8
+ return pkgQualified, score * 0.8
}
}
@@ -108,7 +108,7 @@
// As above, check if we matched just the unqualified symbol name.
nameStart := len(pkg.PkgPath()) + 1
if idx >= nameStart {
- return name, score
+ return []string{name}, score
}
// If our package path ends in the package name, we'll have skipped the
@@ -117,21 +117,21 @@
if endsInPkgName && idx >= 0 {
pkgStart := len(pkg.PkgPath()) - len(pkg.Name())
if idx >= pkgStart {
- return pkg.Name() + "." + name, score
+ return []string{pkg.Name(), ".", name}, score
}
}
// Our match was not contained within the unqualified or package qualified
// symbol. Return the fully qualified symbol but discount the score.
- return strings.Join(fullyQualified, ""), score * 0.6
+ return fullyQualified, score * 0.6
}
-func packageSymbolMatch(name string, pkg Metadata, matcher matcherFunc) (string, float64) {
+func packageSymbolMatch(name string, pkg Metadata, matcher matcherFunc) ([]string, float64) {
qualified := []string{pkg.Name(), ".", name}
if _, s := matcher(qualified); s > 0 {
- return strings.Join(qualified, ""), s
+ return qualified, s
}
- return "", 0
+ return nil, 0
}
// symbolCollector holds context as we walk Packages, gathering symbols that
@@ -319,7 +319,7 @@
}
md := mds[0]
for _, sym := range syms {
- symbol, score := sc.symbolizer(sym.Name, md, sc.matcher)
+ symbolParts, score := sc.symbolizer(sym.Name, md, sc.matcher)
// Check if the score is too low before applying any downranking.
if sc.tooLow(score) {
@@ -392,7 +392,7 @@
si := symbolInformation{
score: score,
- symbol: symbol,
+ symbol: strings.Join(symbolParts, ""),
kind: sym.Kind,
uri: uri,
rng: sym.Range,