gopls/internal/lsp/source: simplify extracting object hover doc
Add a new helper HoverDocForObject, which finds the relevant object
documentation without needing to type-check. This eliminates the last
use of FindPackageFromPos.
For golang/go#57987
Change-Id: Ic9deec78d68156e9ead3831a8247f8c30259a3c6
Reviewed-on: https://go-review.googlesource.com/c/tools/+/464455
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/gopls/internal/lsp/source/completion/format.go b/gopls/internal/lsp/source/completion/format.go
index dfa61a0..738879b 100644
--- a/gopls/internal/lsp/source/completion/format.go
+++ b/gopls/internal/lsp/source/completion/format.go
@@ -19,7 +19,6 @@
"golang.org/x/tools/gopls/internal/lsp/source"
"golang.org/x/tools/gopls/internal/span"
"golang.org/x/tools/internal/event"
- "golang.org/x/tools/internal/event/tag"
"golang.org/x/tools/internal/imports"
"golang.org/x/tools/internal/typeparams"
)
@@ -242,27 +241,21 @@
if !pos.IsValid() {
return item, nil
}
- uri := span.URIFromPath(pos.Filename)
- // Find the source file of the candidate.
- pkg, err := source.FindPackageFromPos(ctx, c.snapshot, c.pkg, obj.Pos())
+ comment, err := source.HoverDocForObject(ctx, c.snapshot, c.pkg, obj)
if err != nil {
- return item, nil
- }
-
- decl, _, _ := source.FindDeclInfo(pkg.GetSyntax(), obj.Pos()) // may be nil
- hover, err := source.FindHoverContext(ctx, c.snapshot, pkg, obj, decl, nil)
- if err != nil {
- event.Error(ctx, "failed to find Hover", err, tag.URI.Of(uri))
+ event.Error(ctx, fmt.Sprintf("failed to find Hover for %q", obj.Name()), err)
return item, nil
}
if c.opts.fullDocumentation {
- item.Documentation = hover.Comment.Text()
+ item.Documentation = comment.Text()
} else {
- item.Documentation = doc.Synopsis(hover.Comment.Text())
+ item.Documentation = doc.Synopsis(comment.Text())
}
// The desired pattern is `^// Deprecated`, but the prefix has been removed
- if strings.HasPrefix(hover.Comment.Text(), "Deprecated") {
+ // TODO(rfindley): It doesn't look like this does the right thing for
+ // multi-line comments.
+ if strings.HasPrefix(comment.Text(), "Deprecated") {
if c.snapshot.View().Options().CompletionTags {
item.Tags = []protocol.CompletionItemTag{protocol.ComplDeprecated}
} else if c.snapshot.View().Options().CompletionDeprecated {
diff --git a/gopls/internal/lsp/source/hover.go b/gopls/internal/lsp/source/hover.go
index 1d48152..85d66de 100644
--- a/gopls/internal/lsp/source/hover.go
+++ b/gopls/internal/lsp/source/hover.go
@@ -499,6 +499,51 @@
return str
}
+// HoverDocForObject returns the best doc comment for obj, referenced by srcpkg.
+//
+// TODO(rfindley): there appears to be zero(!) tests for this functionality.
+func HoverDocForObject(ctx context.Context, snapshot Snapshot, srcpkg Package, obj types.Object) (*ast.CommentGroup, error) {
+ if _, isTypeName := obj.(*types.TypeName); isTypeName {
+ if _, isTypeParam := obj.Type().(*typeparams.TypeParam); isTypeParam {
+ return nil, nil
+ }
+ }
+
+ pgf, pos, err := parseFull(ctx, snapshot, srcpkg, obj.Pos())
+ if err != nil {
+ return nil, fmt.Errorf("re-parsing: %v", err)
+ }
+
+ decl, spec, field := FindDeclInfo([]*ast.File{pgf.File}, pos)
+ if field != nil && field.Doc != nil {
+ return field.Doc, nil
+ }
+ switch decl := decl.(type) {
+ case *ast.FuncDecl:
+ return decl.Doc, nil
+ case *ast.GenDecl:
+ switch spec := spec.(type) {
+ case *ast.ValueSpec:
+ if spec.Doc != nil {
+ return spec.Doc, nil
+ }
+ if decl.Doc != nil {
+ return decl.Doc, nil
+ }
+ return spec.Comment, nil
+ case *ast.TypeSpec:
+ if spec.Doc != nil {
+ return spec.Doc, nil
+ }
+ if decl.Doc != nil {
+ return decl.Doc, nil
+ }
+ return spec.Comment, nil
+ }
+ }
+ return nil, nil
+}
+
// parseFull fully parses the file corresponding to position pos, referenced
// from the given srcpkg.
//
diff --git a/gopls/internal/lsp/source/signature_help.go b/gopls/internal/lsp/source/signature_help.go
index 17549b8..0f81b85 100644
--- a/gopls/internal/lsp/source/signature_help.go
+++ b/gopls/internal/lsp/source/signature_help.go
@@ -97,17 +97,12 @@
comment *ast.CommentGroup
)
if obj != nil {
- declPkg, err := FindPackageFromPos(ctx, snapshot, pkg, obj.Pos())
- if err != nil {
- return nil, 0, err
- }
- node, _, _ := FindDeclInfo(declPkg.GetSyntax(), obj.Pos()) // may be nil
- d, err := FindHoverContext(ctx, snapshot, pkg, obj, node, nil)
+ d, err := HoverDocForObject(ctx, snapshot, pkg, obj)
if err != nil {
return nil, 0, err
}
name = obj.Name()
- comment = d.Comment
+ comment = d
} else {
name = "func"
}
diff --git a/gopls/internal/lsp/source/util.go b/gopls/internal/lsp/source/util.go
index 6a8dc26..8340c5e 100644
--- a/gopls/internal/lsp/source/util.go
+++ b/gopls/internal/lsp/source/util.go
@@ -100,22 +100,6 @@
return pgf.PosMappedRange(pos, end)
}
-// FindPackageFromPos returns the Package for the given position, which must be
-// among the transitive dependencies of pkg.
-//
-// TODO(rfindley): is this the best factoring of this API? This function is
-// really a trivial wrapper around findFileInDeps, which may be a more useful
-// function to expose.
-func FindPackageFromPos(ctx context.Context, snapshot Snapshot, pkg Package, pos token.Pos) (Package, error) {
- if !pos.IsValid() {
- return nil, fmt.Errorf("invalid position")
- }
- fileName := pkg.FileSet().File(pos).Name()
- uri := span.URIFromPath(fileName)
- _, pkg, err := findFileInDeps(ctx, snapshot, pkg, uri)
- return pkg, err
-}
-
// Matches cgo generated comment as well as the proposed standard:
//
// https://golang.org/s/generatedcode