mirror of
https://github.com/golang/go
synced 2024-11-18 16:14:46 -07:00
internal/lsp: implement signature help
Add SignatureHelp functionality to source package. Tests will be added in a subsequent change. Change-Id: Ia43280946d96a984c5741273a00c12255d637b2a Reviewed-on: https://go-review.googlesource.com/c/149177 Reviewed-by: Ian Cottrell <iancottrell@google.com> Run-TryBot: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
0a8e63141f
commit
7e59e591a2
@ -43,14 +43,15 @@ func (s *server) Initialize(ctx context.Context, params *protocol.InitializePara
|
|||||||
s.initialized = true
|
s.initialized = true
|
||||||
return &protocol.InitializeResult{
|
return &protocol.InitializeResult{
|
||||||
Capabilities: protocol.ServerCapabilities{
|
Capabilities: protocol.ServerCapabilities{
|
||||||
|
CompletionProvider: protocol.CompletionOptions{},
|
||||||
|
DefinitionProvider: true,
|
||||||
|
DocumentFormattingProvider: true,
|
||||||
|
DocumentRangeFormattingProvider: true,
|
||||||
|
SignatureHelpProvider: protocol.SignatureHelpOptions{},
|
||||||
TextDocumentSync: protocol.TextDocumentSyncOptions{
|
TextDocumentSync: protocol.TextDocumentSyncOptions{
|
||||||
Change: float64(protocol.Full), // full contents of file sent on each update
|
Change: float64(protocol.Full), // full contents of file sent on each update
|
||||||
OpenClose: true,
|
OpenClose: true,
|
||||||
},
|
},
|
||||||
DocumentFormattingProvider: true,
|
|
||||||
DocumentRangeFormattingProvider: true,
|
|
||||||
CompletionProvider: protocol.CompletionOptions{},
|
|
||||||
DefinitionProvider: true,
|
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -174,8 +175,18 @@ func (s *server) Hover(context.Context, *protocol.TextDocumentPositionParams) (*
|
|||||||
return nil, notImplemented("Hover")
|
return nil, notImplemented("Hover")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) SignatureHelp(context.Context, *protocol.TextDocumentPositionParams) (*protocol.SignatureHelp, error) {
|
func (s *server) SignatureHelp(ctx context.Context, params *protocol.TextDocumentPositionParams) (*protocol.SignatureHelp, error) {
|
||||||
return nil, notImplemented("SignatureHelp")
|
f := s.view.GetFile(source.URI(params.TextDocument.URI))
|
||||||
|
tok, err := f.GetToken()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pos := fromProtocolPosition(tok, params.Position)
|
||||||
|
info, err := source.SignatureHelp(ctx, f, pos)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return toProtocolSignatureHelp(info), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) Definition(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
func (s *server) Definition(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
||||||
|
33
internal/lsp/signature_help.go
Normal file
33
internal/lsp/signature_help.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package lsp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
func toProtocolSignatureHelp(info *source.SignatureInformation) *protocol.SignatureHelp {
|
||||||
|
return &protocol.SignatureHelp{
|
||||||
|
ActiveParameter: float64(info.ActiveParameter),
|
||||||
|
ActiveSignature: 0, // there is only ever one possible signature
|
||||||
|
Signatures: []protocol.SignatureInformation{
|
||||||
|
{
|
||||||
|
Label: info.Label,
|
||||||
|
Parameters: toProtocolParameterInformation(info.Parameters),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toProtocolParameterInformation(info []source.ParameterInformation) []protocol.ParameterInformation {
|
||||||
|
var result []protocol.ParameterInformation
|
||||||
|
for _, p := range info {
|
||||||
|
result = append(result, protocol.ParameterInformation{
|
||||||
|
Label: p.Label,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
118
internal/lsp/source/signature_help.go
Normal file
118
internal/lsp/source/signature_help.go
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package source
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/ast/astutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SignatureInformation struct {
|
||||||
|
Label string
|
||||||
|
Parameters []ParameterInformation
|
||||||
|
ActiveParameter int
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParameterInformation struct {
|
||||||
|
Label string
|
||||||
|
}
|
||||||
|
|
||||||
|
func SignatureHelp(ctx context.Context, f *File, pos token.Pos) (*SignatureInformation, error) {
|
||||||
|
fAST, err := f.GetAST()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pkg, err := f.GetPackage()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a call expression surrounding the query position.
|
||||||
|
var callExpr *ast.CallExpr
|
||||||
|
path, _ := astutil.PathEnclosingInterval(fAST, pos, pos)
|
||||||
|
if path == nil {
|
||||||
|
return nil, fmt.Errorf("cannot find node enclosing position")
|
||||||
|
}
|
||||||
|
for _, node := range path {
|
||||||
|
if c, ok := node.(*ast.CallExpr); ok {
|
||||||
|
callExpr = c
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if callExpr == nil || callExpr.Fun == nil {
|
||||||
|
return nil, fmt.Errorf("cannot find an enclosing function")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the type information for the function corresponding to the call expression.
|
||||||
|
var obj types.Object
|
||||||
|
switch t := callExpr.Fun.(type) {
|
||||||
|
case *ast.Ident:
|
||||||
|
obj = pkg.TypesInfo.ObjectOf(t)
|
||||||
|
case *ast.SelectorExpr:
|
||||||
|
obj = pkg.TypesInfo.ObjectOf(t.Sel)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("the enclosing function is malformed")
|
||||||
|
}
|
||||||
|
if obj == nil {
|
||||||
|
return nil, fmt.Errorf("cannot resolve %s", callExpr.Fun)
|
||||||
|
}
|
||||||
|
// Find the signature corresponding to the object.
|
||||||
|
var sig *types.Signature
|
||||||
|
switch obj.(type) {
|
||||||
|
case *types.Var:
|
||||||
|
if underlying, ok := obj.Type().Underlying().(*types.Signature); ok {
|
||||||
|
sig = underlying
|
||||||
|
}
|
||||||
|
case *types.Func:
|
||||||
|
sig = obj.Type().(*types.Signature)
|
||||||
|
}
|
||||||
|
if sig == nil {
|
||||||
|
return nil, fmt.Errorf("no function signatures found for %s", obj.Name())
|
||||||
|
}
|
||||||
|
pkgStringer := qualifier(fAST, pkg.Types, pkg.TypesInfo)
|
||||||
|
var paramInfo []ParameterInformation
|
||||||
|
for i := 0; i < sig.Params().Len(); i++ {
|
||||||
|
param := sig.Params().At(i)
|
||||||
|
label := types.TypeString(param.Type(), pkgStringer)
|
||||||
|
if param.Name() != "" {
|
||||||
|
label = fmt.Sprintf("%s %s", param.Name(), label)
|
||||||
|
}
|
||||||
|
paramInfo = append(paramInfo, ParameterInformation{
|
||||||
|
Label: label,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Determine the query position relative to the number of parameters in the function.
|
||||||
|
var activeParam int
|
||||||
|
var start, end token.Pos
|
||||||
|
for i, expr := range callExpr.Args {
|
||||||
|
if start == token.NoPos {
|
||||||
|
start = expr.Pos()
|
||||||
|
}
|
||||||
|
end = expr.End()
|
||||||
|
if i < len(callExpr.Args)-1 {
|
||||||
|
end = callExpr.Args[i+1].Pos() - 1 // comma
|
||||||
|
}
|
||||||
|
if start <= pos && pos <= end {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
activeParam++
|
||||||
|
start = expr.Pos() + 1 // to account for commas
|
||||||
|
}
|
||||||
|
// Label for function, qualified by package name.
|
||||||
|
label := obj.Name()
|
||||||
|
if pkg := pkgStringer(obj.Pkg()); pkg != "" {
|
||||||
|
label = pkg + "." + label
|
||||||
|
}
|
||||||
|
return &SignatureInformation{
|
||||||
|
Label: label + formatParams(sig.Params(), sig.Variadic(), pkgStringer),
|
||||||
|
Parameters: paramInfo,
|
||||||
|
ActiveParameter: activeParam,
|
||||||
|
}, nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user