internal/lsp: don't deep complete struct field names
When it is certain we are completing a struct field name, we don't
want deep completions. The only possible completions are the remaining
field names.
I also silenced the log spam in tests by disabling the go/packages
logger and the lsp logger.
Fixes golang/go#33614
Change-Id: Icec8d92112b1674fa7a6a21145ab710d054919b4
Reviewed-on: https://go-review.googlesource.com/c/tools/+/190097
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go
index 800c5e9..386e5e8 100644
--- a/internal/lsp/lsp_test.go
+++ b/internal/lsp/lsp_test.go
@@ -20,6 +20,7 @@
"golang.org/x/tools/internal/lsp/diff"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source"
+ "golang.org/x/tools/internal/lsp/telemetry/log"
"golang.org/x/tools/internal/lsp/tests"
"golang.org/x/tools/internal/span"
)
@@ -41,6 +42,8 @@
data := tests.Load(t, exporter, "testdata")
defer data.Exported.Cleanup()
+ log.AddLogger(log.NullLogger)
+
cache := cache.New()
session := cache.NewSession(ctx)
view := session.NewView(ctx, viewName, span.FileURI(data.Config.Dir))
diff --git a/internal/lsp/source/deep_completion.go b/internal/lsp/source/deep_completion.go
index bb1fbbf..7d2f6ad 100644
--- a/internal/lsp/source/deep_completion.go
+++ b/internal/lsp/source/deep_completion.go
@@ -56,6 +56,12 @@
return
}
+ // If we are definitely completing a struct field name, deep completions
+ // don't make sense.
+ if c.wantStructFieldCompletions() && c.enclosingCompositeLiteral.inKey {
+ return
+ }
+
// Don't search into type names.
if isTypeName(obj) {
return
diff --git a/internal/lsp/source/source_test.go b/internal/lsp/source/source_test.go
index b54684d..1de9474 100644
--- a/internal/lsp/source/source_test.go
+++ b/internal/lsp/source/source_test.go
@@ -18,6 +18,7 @@
"golang.org/x/tools/internal/lsp/cache"
"golang.org/x/tools/internal/lsp/diff"
"golang.org/x/tools/internal/lsp/source"
+ "golang.org/x/tools/internal/lsp/telemetry/log"
"golang.org/x/tools/internal/lsp/tests"
"golang.org/x/tools/internal/span"
)
@@ -37,6 +38,8 @@
data := tests.Load(t, exporter, "../testdata")
defer data.Exported.Cleanup()
+ log.AddLogger(log.NullLogger)
+
cache := cache.New()
session := cache.NewSession(ctx)
r := &runner{
diff --git a/internal/lsp/telemetry/log/log.go b/internal/lsp/telemetry/log/log.go
index 8391ad7..2d957f6 100644
--- a/internal/lsp/telemetry/log/log.go
+++ b/internal/lsp/telemetry/log/log.go
@@ -90,3 +90,9 @@
fmt.Fprintf(os.Stderr, "%v\n", ToEntry(ctx, at, tags))
return true
}
+
+// NullLogger is a logger that throws away log messages and reports
+// success so that the fallback stderr logging does not happen.
+var NullLogger = func(context.Context, time.Time, tag.List) bool {
+ return true
+}
diff --git a/internal/lsp/testdata/deepcomplete/deep_complete.go b/internal/lsp/testdata/deepcomplete/deep_complete.go
index bfde660..2f31b1f 100644
--- a/internal/lsp/testdata/deepcomplete/deep_complete.go
+++ b/internal/lsp/testdata/deepcomplete/deep_complete.go
@@ -59,3 +59,14 @@
a.deepEmbedC //@item(deepEmbedC, "a.deepEmbedC", "deepEmbedC", "field")
wantsC(a) //@complete(")", deepEmbedC, deepEmbedA, deepEmbedB)
}
+
+func _() {
+ type nested struct {
+ a int
+ n *nested //@item(deepNestedField, "n", "*nested", "field")
+ }
+
+ nested{
+ a: 123, //@complete(" //", deepNestedField)
+ }
+}
diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go
index 88fb2c3..608cd3f 100644
--- a/internal/lsp/tests/tests.go
+++ b/internal/lsp/tests/tests.go
@@ -26,7 +26,7 @@
// We hardcode the expected number of test cases to ensure that all tests
// are being executed. If a test is added, this number must be changed.
const (
- ExpectedCompletionsCount = 144
+ ExpectedCompletionsCount = 145
ExpectedCompletionSnippetCount = 15
ExpectedDiagnosticsCount = 21
ExpectedFormatCount = 6
@@ -195,12 +195,12 @@
filename := data.Exported.File(testModule, fragment)
data.fragments[filename] = fragment
}
- data.Exported.Config.Logf = t.Logf
+ data.Exported.Config.Logf = nil
// Merge the exported.Config with the view.Config.
data.Config = *data.Exported.Config
data.Config.Fset = token.NewFileSet()
- data.Config.Logf = t.Logf
+ data.Config.Logf = nil
data.Config.Context = Context(nil)
data.Config.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
panic("ParseFile should not be called")