internal/lsp: treat completion documentation errors as actual errors
Also, handle *ast.StarExpr in the identifier code. This fixes a specific
case with deep completions and documentation.
Change-Id: I630ae4e8f1c123ba1fdea85e6862ae93396e2cd4
Reviewed-on: https://go-review.googlesource.com/c/tools/+/194564
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go
index 4ca0b7d..1b4b684 100644
--- a/internal/lsp/lsp_test.go
+++ b/internal/lsp/lsp_test.go
@@ -151,7 +151,6 @@
}
}
}
-
modified.InsertTextFormat = protocol.SnippetTextFormat
for _, usePlaceholders := range []bool{true, false} {
for src, want := range snippets {
diff --git a/internal/lsp/source/completion_format.go b/internal/lsp/source/completion_format.go
index b43a59a..89d4f2a 100644
--- a/internal/lsp/source/completion_format.go
+++ b/internal/lsp/source/completion_format.go
@@ -115,26 +115,26 @@
if !c.opts.Documentation {
return item, nil
}
- declRange, err := objToMappedRange(c.ctx, c.view, obj)
- if err != nil {
- return item, nil
- }
- pos := c.view.Session().Cache().FileSet().Position(declRange.spanRange.Start)
+ pos := c.view.Session().Cache().FileSet().Position(obj.Pos())
+
+ // We ignore errors here, because some types, like "unsafe" or "error",
+ // may not have valid positions that we can use to get documentation.
if !pos.IsValid() {
return item, nil
}
+
uri := span.FileURI(pos.Filename)
_, file, pkg, err := c.pkg.FindFile(c.ctx, uri, obj.Pos())
- if file == nil || pkg == nil {
- return item, nil
+ if err != nil {
+ return CompletionItem{}, err
}
ident, err := findIdentifier(c.ctx, c.view, []Package{pkg}, file, obj.Pos())
if err != nil {
- return item, nil
+ return CompletionItem{}, err
}
hover, err := ident.Hover(c.ctx)
if err != nil {
- return item, nil
+ return CompletionItem{}, err
}
item.Documentation = hover.Synopsis
if c.opts.FullDocumentation {
diff --git a/internal/lsp/source/identifier.go b/internal/lsp/source/identifier.go
index 2e286b0..993b82e 100644
--- a/internal/lsp/source/identifier.go
+++ b/internal/lsp/source/identifier.go
@@ -104,18 +104,13 @@
}
}
result := &IdentifierInfo{
- View: view,
- File: ph,
- qf: qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo()),
- pkgs: pkgs,
+ View: view,
+ File: ph,
+ qf: qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo()),
+ pkgs: pkgs,
+ ident: searchForIdent(path[0]),
}
-
- switch node := path[0].(type) {
- case *ast.Ident:
- result.ident = node
- case *ast.SelectorExpr:
- result.ident = node.Sel
- }
+ // No identifier at the given position.
if result.ident == nil {
return nil, nil
}
@@ -202,6 +197,18 @@
return result, nil
}
+func searchForIdent(n ast.Node) *ast.Ident {
+ switch node := n.(type) {
+ case *ast.Ident:
+ return node
+ case *ast.SelectorExpr:
+ return node.Sel
+ case *ast.StarExpr:
+ return searchForIdent(node.X)
+ }
+ return nil
+}
+
func typeToObject(typ types.Type) types.Object {
switch typ := typ.(type) {
case *types.Named:
diff --git a/internal/lsp/testdata/deepcomplete/deep_complete.go b/internal/lsp/testdata/deepcomplete/deep_complete.go
index 66d4859..61b8cd1 100644
--- a/internal/lsp/testdata/deepcomplete/deep_complete.go
+++ b/internal/lsp/testdata/deepcomplete/deep_complete.go
@@ -33,11 +33,12 @@
}
func _() {
+ // deepCircle is circular.
type deepCircle struct {
*deepCircle
}
var circle deepCircle //@item(deepCircle, "circle", "deepCircle", "var")
- circle.deepCircle //@item(deepCircleField, "circle.deepCircle", "*deepCircle", "field")
+ circle.deepCircle //@item(deepCircleField, "circle.deepCircle", "*deepCircle", "field", "deepCircle is circular.")
var _ deepCircle = circ //@complete(" //", deepCircle, deepCircleField)
}